Docker 学习文档(Mac + Docker Desktop 版)

Docker 学习文档(Mac + Docker Desktop 版)

适用人群:刚在 Mac 上装好 Docker Desktop、想系统学 Docker 的同学 工具环境:macOS + Docker Desktop(可视化桌面版) 作者视角:以「生产级」标准要求自己------镜像不是能跑就行,体积、安全、构建速度、可维护性一个都不能少。


0. 学习地图(先看这张图,心里有数)

scss 复制代码
Docker 知识树
├── 理念层:容器 vs 虚拟机、为什么需要 Docker
├── Mac 专属:Docker Desktop 本质 = Mac 上跑了一台 Linux 虚拟机
├── 概念层:镜像(Image) / 容器(Container) / 仓库(Registry) / 卷(Volume) / 网络(Network)
├── 操作层:docker 命令 + Docker Desktop 图形界面
├── 构建层:Dockerfile / 多阶段构建 / .dockerignore
├── 编排层:docker-compose(一次管多个容器)
└── 实战层:从「跑起来」到「安全上线」

学习顺序建议:先理解概念 → 用 Desktop 点一点 → 用命令行敲一遍 → 自己写一个 Dockerfile → 用 compose 组一套服务


1. Docker 是什么?为什么要用它?

1.1 一句话理解

Docker 把你的「应用 + 它运行所需的一切依赖(系统库、环境变量、配置文件)」打包成一个标准化、可移植的盒子(镜像) 。这个盒子在任何装了 Docker 的机器上都能以完全一致的方式跑起来。

1.2 经典痛点(你一定遇过)

场景 没有 Docker 有 Docker
「在我机器上能跑」 同事环境一跑就崩 镜像一样,跑出来就一样
环境搭建 装 MySQL/Redis/Python 半小时起 docker run 一条命令秒起
版本冲突 项目 A 要 Python 3.8,项目 B 要 3.12,互相打架 每个项目各自隔离
上线交付 运维按文档手动配环境,容易漏 直接交付镜像,开箱即用

1.3 容器 ≠ 虚拟机(重要区别)

虚拟机(VM) 容器(Container)
隔离级别 虚拟整台机器(含 Guest OS 内核) 共享宿主机内核,隔离进程/文件系统
体积 几百 MB ~ GB 通常几 MB ~ 几百 MB
启动速度 秒级~分钟级 毫秒级~秒级
资源占用

记忆口诀:VM 是「租整栋楼」,容器是「租一个带独立水电的房间」,楼(内核)大家共用。


2. Mac 上 Docker 的特殊性(新手最容易踩的坑)

2.1 核心事实:Mac 不能直接跑 Linux 容器

macOS 的内核是 Darwin(XNU),而 Docker 容器本质上是 Linux 进程。所以:

Docker Desktop 在你的 Mac 上悄悄启动了一台轻量 Linux 虚拟机(基于 HyperKit / Apple 虚拟机框架),所有容器其实都跑在这台 VM 里。

带来的直接影响:

  • docker run 的容器,逻辑上在「那台 Linux VM」里,不是直接在你的 macOS 上。
  • 容器访问宿主机(Mac)的服务时,不能直接用 localhost,要用特殊地址(见第 9 章)。

2.2 芯片架构:Intel(x86_64) vs Apple Silicon(arm64)

Mac 分两种芯片:

  • Intel Mac:x86_64 架构
  • Apple Silicon(M1/M2/M3...):arm64 架构

坑点 :很多老镜像只有 x86_64 版本。在 M 系列 Mac 上直接跑可能报错(如 exec format error)或靠 QEMU 模拟变慢。

解决:

  • 优先拉取带 arm64 标签或 multi-arch(多架构)的官方镜像(官方镜像一般已支持)。
  • docker run --platform linux/amd64 镜像名 强制用 x86 模拟跑(慢,仅应急)。

查看自己架构:

bash 复制代码
uname -m
# arm64 = Apple Silicon;x86_64 = Intel

2.3 Docker Desktop 的资源设置

打开 Docker Desktop → 右上角齿轮 ⚙️ → Settings → Resources

  • CPUs / Memory / Disk:分配多少资源给那台 Linux VM。默认一般够用,跑重服务(如 Elasticsearch)可加内存。
  • Disk image location:VM 磁盘文件位置,别手贱删。
  • General 里可勾选「Start Docker Desktop when you log in」(开机自启)。

3. Docker Desktop 界面导览(点点看,建立直觉)

启动 Docker Desktop 后,左侧是一排导航,常用这几个:

模块 干什么 对应命令行
Containers 看正在跑/已停止的容器,点进去能看日志、终端、启停 docker ps / docker logs
Images 看本地已有的镜像,可删除、运行、查看层级 docker images
Volumes 看数据卷(容器里持久化数据的地盘) docker volume ls
Builds(新版) 看构建记录、BuildKit 缓存 docker build
Docker Hub 浏览/拉取官方镜像 docker pull
Settings ⚙️ 资源、镜像源、Kubernetes 开关等 ---

新手建议:先用命令行把概念敲熟,再用 Desktop 的图形界面「回看」------图形界面是命令的可视化,理解了命令,界面一看就懂。


4. 核心概念(必须刻进脑子里)

4.1 镜像(Image)------「模板 / 类」

只读的模板,定义了容器里有什么。比如 node:20-alpine 就是一个预装了 Node 20 的镜像。

4.2 容器(Container)------「运行中的实例 / 对象」

镜像跑起来后变成容器,是可读可写的运行实例。一个镜像可以同时跑出 N 个容器。

4.3 仓库 / 镜像源(Registry)------「应用商店」

  • Docker Hub :默认公共仓库(docker pull nginx 就是从这拉)。
  • 国内加速:在 Settings → Docker Engine 里配置镜像加速器(如中科大、阿里云镜像),拉取更快。

4.4 卷(Volume)------「容器的硬盘」

容器删了,里面数据默认全没了。想持久化(数据库文件、上传资料),必须用 Volume 或挂载宿主机目录。

bash 复制代码
docker run -v 卷名:/容器里的路径 镜像

4.5 网络(Network)------「容器间的局域网」

默认容器间可通过自定义网络互访(用服务名当域名)。compose 会自动建网络。

4.6 Dockerfile------「镜像的配方」

一个文本文件,写清楚「基于什么基础镜像、装什么、拷什么、怎么启动」。这是你亲手造镜像的方式(第 7 章细讲)。


5. 必会命令(建议全部亲手敲一遍)

提示:Docker Desktop 装好后,命令行里 docker 命令就可用了(它会连上那台 VM)。

5.1 镜像相关

bash 复制代码
docker pull nginx:alpine        # 拉取镜像(指定 tag,别用 latest!)
docker images                   # 看本地镜像列表
docker rmi 镜像ID               # 删除镜像
docker image prune              # 删掉所有没被用的悬空镜像

5.2 容器相关(最常用)

bash 复制代码
docker run -d -p 8080:80 --name mynginx nginx:alpine
#   -d        后台运行
#   -p 8080:80  把宿主机 8080 映射到容器 80 端口
#   --name    给容器起个名字(不然是一串随机串)

docker ps                        # 看正在跑的容器
docker ps -a                     # 看所有容器(含已退出的)
docker logs mynginx              # 看日志
docker exec -it mynginx sh       # 进入容器里的 shell(-it 交互)
docker stop mynginx              # 停
docker start mynginx             # 起
docker rm mynginx                # 删(先 stop)
docker rm -f mynginx            # 强制删(没 stop 也行)

5.3 清理(Mac 磁盘容易被 Docker 吃满)

bash 复制代码
docker system prune             # 删停止的容器 + 悬空镜像 + 网络(安全)
docker system prune -a          # 更狠:连没被用的镜像也删(谨慎)

在 Mac 上,Docker Desktop 的 VM 磁盘只增不减prune 删文件后还要去 Settings → Resources → 「Clean / Reset」 才能真正回收磁盘空间。

5.4 一键跑个 Nginx 验证环境

bash 复制代码
docker run -d -p 8080:80 --name demo nginx:alpine

浏览器打开 http://localhost:8080,看到 Nginx 欢迎页 = 环境 OK ✅


6. 第一个实战:从零做一个自己的镜像

目标:做一个打印「Hello Docker」的 Python 小服务,并容器化。

6.1 项目结构

复制代码
demo/
├── app.py
└── requirements.txt

app.py

python 复制代码
from http.server import BaseHTTPRequestHandler, HTTPServer

class H(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Hello Docker from Mac!")

if __name__ == "__main__":
    HTTPServer(("0.0.0.0", 8000)).serve_forever()

requirements.txt:(本例其实没第三方依赖,留空也行,演示用)

6.2 写 Dockerfile(基础版,先跑通)

dockerfile 复制代码
FROM python:3.12-alpine
WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]

6.3 构建并运行

bash 复制代码
cd demo
docker build -t hello-docker .
docker run -d -p 8000:8000 --name hello hello-docker
# 打开 http://localhost:8000

跑通后你会发现镜像有几百 MB(因为带了整个 Python)。第 7 章教你压缩到几十 MB。


7. Dockerfile 写法与最佳实践(重点章节)

这是「生产级」和「玩具级」的分水岭。下面每条都是实战踩出来的。

7.1 基础镜像选型(体积/安全的第一步)

基础镜像 特点 适用
python:3.12 完整 Debian,体积大 调试、需要系统库
python:3.12-slim 精简 Debian,中等 通用生产
python:3.12-alpine 最小(musl libc) 追求极小,但部分 C 库编译要装 build 依赖
gcr.io/distroless/... 几乎只有运行时,最安全 对安全要求极高

原则 :版本别写 latest,要 pin 具体版本(如 python:3.12-alpine),否则今天构建和明天构建可能不一样,出事都查不到原因。

7.2 多阶段构建(把构建环境和运行环境分开)

以 Go 为例(Go 编译出静态二进制,最能体现多阶段价值):

dockerfile 复制代码
# 阶段1:构建
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o app .

# 阶段2:运行(极小的纯净镜像)
FROM alpine:3.20
WORKDIR /app
COPY --from=builder /src/app .
USER 1000          # 不用 root 跑
CMD ["./app"]

好处:构建工具(编译器、源码)全部留在第一阶段,最终镜像只有二进制 + 极简系统,体积能小一个数量级,攻击面也大幅减少。

7.3 非 root 用户运行(安全底线)

dockerfile 复制代码
RUN addgroup -S app && adduser -S app -G app
USER app

容器里默认是 root,一旦被攻破,攻击者就在容器里拥有最高权限。切到普通用户是基本素养。

7.4 合理利用层缓存(让构建飞快)

Docker 按行构建,改得越少、越靠后的指令,越要放后面

dockerfile 复制代码
# ✅ 好:先拷依赖清单装依赖(这层很少变),再拷代码(常变)
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

# ❌ 差:COPY . . 在最前,每次改一行代码都要重装所有依赖

原理:依赖不变 → 这一层命中缓存 → 跳过 npm install,几秒过;只重跑代码拷贝和启动。

7.5 .dockerignore(别把垃圾塞进镜像)

项目根目录建 .dockerignore,作用类似 .gitignore

bash 复制代码
node_modules
.git
.env
Dockerfile
*.log
dist(如果构建在宿主机做)

不忽略的话,COPY . . 会把 node_modules.git 全打进镜像,体积爆炸、还有泄密风险。

7.6 HEALTHCHECK(让编排系统知道你「真活着」)

dockerfile 复制代码
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:8000/ || exit 1

加了之后,docker ps 里状态会从 starting 变成 healthy,K8s/compose 也靠它判断要不要重启。

7.7 不把密钥写进镜像

dockerfile 复制代码
# ❌ 绝对不要
ENV DB_PASSWORD=supersecret

# ✅ 运行时通过 -e 或 secrets 注入
docker run -e DB_PASSWORD=$DB_PASSWORD ...

镜像会被推到仓库、被别人 docker history 看到,硬编码密钥等于公开。

7.8 把第 6 章的镜像压到极小(Alpine 版)

dockerfile 复制代码
FROM python:3.12-alpine
WORKDIR /app
COPY app.py .
# 用 python:3.12-alpine 已够小;若用多阶段可进一步压
USER 1000
EXPOSE 8000
CMD ["python", "app.py"]

相比完整 python:3.12(~1GB),alpine 版约 ~50MB,差距 20 倍。


8. docker-compose 入门(一次管多个容器)

单条 docker run 管一两个容器还行,服务一多就乱了。compose 用一个 docker-compose.yml 描述整套服务。

8.1 例子:Web + Redis

yaml 复制代码
version: "3.9"
services:
  web:
    build: .                  # 用当前目录 Dockerfile 构建
    ports:
      - "8000:8000"
    depends_on:
      - redis
  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data      # 数据持久化

volumes:
  redis-data:

8.2 常用命令

bash 复制代码
docker compose up -d          # 后台启动整套
docker compose ps            # 看状态
docker compose logs web      # 看某个服务日志
docker compose down          # 停并删容器(数据卷保留)
docker compose down -v       # 连数据卷一起删(慎用)

Docker Desktop 里也能直接看到 compose 项目,点点就能启停,和命令行一一对应。


9. Mac 常见坑 & 排查清单

现象 原因 解决
exec format error 镜像架构不匹配(M 芯片跑 x86 镜像) 换 multi-arch 镜像,或 --platform linux/amd64
容器里访问宿主机服务连不上 容器在 Linux VM 里,localhost 是 VM 自己 host.docker.internal 代替 localhost
文件改了容器内没变 没挂载卷 -v $(pwd):/app 挂载
Mac 磁盘被吃满 VM 磁盘不自动收缩 prune 后到 Settings → Resources 清理
端口被占用 宿主机端口已被占 -p 8081:80 映射端口
拉镜像慢 默认连 Docker Hub 跨国 配国内镜像加速器

访问宿主机(Mac)的经典写法

bash 复制代码
# 容器里的应用要连 Mac 上跑的 MySQL(端口 3306)
docker run myapp  # 代码里填 host.docker.internal:3306

10. 学习路径 & 进阶建议

10.1 30 天上手路线

  • 第 1 周 :概念 + Desktop 界面 + 必会命令(第 1~5 章),把 nginx/redis/mysql 跑熟。
  • 第 2 周:自己写 Dockerfile,练多阶段、.dockerignore、非 root(第 6~7 章)。
  • 第 3 周:docker-compose 组一套「Web + DB + 缓存」(第 8 章)。
  • 第 4 周 :镜像优化(体积/安全扫描)、.dockerignore/secret 管理进阶。

10.2 推荐进阶主题

  • 镜像安全扫描docker scout cves 镜像名(Desktop 内置),或 Trivy。
  • BuildKit 新特性--mount=type=cache 缓存依赖、--mount=type=secret 安全传密钥。
  • Kubernetes:Docker Desktop 里 Settings 勾选 Kubernetes 即可本地单节点练手。
  • CI 集成 :把 docker build 放进 GitHub Actions / GitLab CI,做到提交即构建。

10.3 给自己的三条铁律(记住就超过大多数人)

  1. 基础镜像版本要 pin 死,绝不写 latest
  2. 最终运行镜像能小则小、能非 root 则非 root。
  3. 密钥永远不进镜像,运行时注入。

附:速查卡片(贴墙上)

bash 复制代码
# 拉起一个服务
docker run -d -p 宿主机端口:容器端口 --name 名字 镜像:tag

# 进容器
docker exec -it 名字 sh

# 构建
docker build -t 名字:版本 .

# 清理
docker system prune

# 编排
docker compose up -d
docker compose down

文档完。建议边看边敲,遇到报错先对照第 9 章排查清单。Docker 是「手感型」技能,敲得越多越熟。

相关推荐
AlienZHOU3 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
狗头大军之江苏分军6 小时前
《潮水漫过十七岁》开学了
后端
苏三说技术6 小时前
如何看待GPT-6在UP主众测中碾压夺冠?它是现在最强大模型吗?
后端
mldong7 小时前
一份 JSON,一条能跑的审批流:把报销流程送上工作流引擎
后端·架构
wno7047 小时前
Spring Boot WebFlux增删改查
java·spring boot·后端
Captaincc7 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
aramae8 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端
计算机魔术师8 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen8 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒9 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端