乐于分享
好东西不私藏

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

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

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

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


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

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 模拟跑(慢,仅应急)。

查看自己架构:

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 或挂载宿主机目录。

docker run -v 卷名:/容器里的路径 镜像

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

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

4.6 Dockerfile——「镜像的配方」

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


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

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

5.1 镜像相关

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

5.2 容器相关(最常用)

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 吃满)

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

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

5.4 一键跑个 Nginx 验证环境

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

from http.server import BaseHTTPRequestHandler, HTTPServerclass 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(基础版,先跑通)

FROM python:3.12-alpineWORKDIR /appCOPY app.py .CMD ["python", "app.py"]

6.3 构建并运行

cd demodocker 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 编译出静态二进制,最能体现多阶段价值):

# 阶段1:构建FROM golang:1.22-alpine AS builderWORKDIR /srcCOPY . .RUN go build -o app .# 阶段2:运行(极小的纯净镜像)FROM alpine:3.20WORKDIR /appCOPY --from=builder /src/app .USER 1000          # 不用 root 跑CMD ["./app"]

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

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

RUN addgroup -S app && adduser -S app -G appUSER app

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

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

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

# ✅ 好:先拷依赖清单装依赖(这层很少变),再拷代码(常变)COPY package.json package-lock.json ./RUN npm ciCOPY . .# ❌ 差:COPY . . 在最前,每次改一行代码都要重装所有依赖

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

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

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

node_modules.git.envDockerfile*.logdist(如果构建在宿主机做)

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

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

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

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

7.7 不把密钥写进镜像

# ❌ 绝对不要ENV DB_PASSWORD=supersecret# ✅ 运行时通过 -e 或 secrets 注入docker run -e DB_PASSWORD=(pwd):/app 挂载Mac 磁盘被吃满VM 磁盘不自动收缩prune 后到 Settings → Resources 清理端口被占用宿主机端口已被占换 -p 8081:80 映射端口拉镜像慢默认连 Docker Hub 跨国配国内镜像加速器访问宿主机(Mac)的经典写法:# 容器里的应用要连 Mac 上跑的 MySQL(端口 3306)docker run myapp  # 代码里填 host.docker.internal:330610. 学习路径 & 进阶建议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 给自己的三条铁律(记住就超过大多数人)基础镜像版本要 pin 死,绝不写 latest。最终运行镜像能小则小、能非 root 则非 root。密钥永远不进镜像,运行时注入。附:速查卡片(贴墙上)# 拉起一个服务docker run -d -p 宿主机端口:容器端口 --name 名字 镜像:tag# 进容器docker exec -it 名字 sh# 构建docker build -t 名字:版本 .# 清理docker system prune# 编排docker compose up -ddocker compose down