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 是「手感型」技能,敲得越多越熟。

相关推荐
刘名喜1 小时前
第30篇-Spring-Security-7核心概念
后端·kotlin·springboot
java1234_小锋1 小时前
Vue3专题 - 条件渲染
前端·javascript·vue.js
明月_清风1 小时前
🚀 AI Agent 完全入门指南:从 LLM 到生产落地,新手必懂的 34 个核心概念
前端·后端·ai编程
鸽鸽1 小时前
Vue 3 API 完全指南:从 Options 到 Composition 的进阶之路
前端·vue.js
名字还没想好☜1 小时前
React 用 Portal + Context 实现全局 Toast:一次调用、自动消失与队列管理
前端·javascript·react.js·react·next.js
程序员阿明1 小时前
spring boot3访问resources下的文件,使得在浏览器url中可以直接访问
java·spring boot·后端
掘金者阿豪1 小时前
MongoDB迁移不想重写代码?一次国产数据库替换踩坑记录
后端