路线图

容器基础Docker

星辉 2026-07-02 阅读 4 min 735 字 路线图
容器基础Docker 封面

本章帮助你理解容器是什么、为什么需要它,以及掌握 Docker 的核心用法。学完本章后,你将能够编写实用的 Dockerfile、使用常用 Docker 命令管理容器和镜像,并为后续学习 Kubernetes 打下基础。


容器 vs 虚拟机#

容器和虚拟机都做"隔离",但思路和开销完全不同。

虚拟机(VM) 是在物理机上跑一个完整的操作系统,每个 VM 有自己的内核、完整的 OS 文件系统、虚拟硬件。隔离性强,但重。

容器 共享宿主机的操作系统内核,通过 Linux namespace 和 cgroup 实现进程级隔离。不需要跑多个操作系统,所以轻。

对比维度虚拟机容器
隔离机制Hypervisor 虚拟化硬件,每个 VM 有独立 OS 内核Linux namespace(隔离视图)+ cgroup(限制资源),共享宿主机内核
启动速度分钟级(要启动整个 OS)秒级(只需启动进程)
资源开销高:每个 VM 占用数百MB内存跑OS本身低:容器进程本身只占几MB,几乎没有额外开销
镜像大小GB 级(包含完整 OS)MB 级(只含应用和依赖)
适用场景需要强隔离、运行不同 OS(如 Windows on Linux)、传统单体应用微服务、CI/CD、大规模集群部署、Kubernetes 调度单元

一句话总结:虚拟机是"装修好的整套房子",容器是"合租房里的一间卧室"——共享水电网(内核),但各自有独立空间(namespace)和用电上限(cgroup)。

注意事项:容器不是虚拟机,容器里的"root"和宿主机的 root 在某种程度上是同一个——这也是为什么生产环境容器不能以 root 运行。


镜像、容器与 Layer#

核心概念#

镜像(Image) 是一个只读的文件包,包含运行应用所需的一切:代码、运行时、系统工具、系统库、配置文件。

容器(Container) 是镜像的运行实例。镜像好比是"程序",容器是"进程"——镜像是静态的,容器是动态的。

Layer(层) 是镜像的构成单元。Docker 镜像不是一个大文件,而是由多层叠加而成的。每一层是一个只读的文件系统快照,上一层可以覆盖下一层的文件(写时复制,Copy-on-Write)。

Layer 类比:乐高积木#

把镜像构建过程想象成搭乐高:

  • 第一层(基础层):放一块 8x8 的底板 → 对应 FROM ubuntu:22.04
  • 第二层:在底板上放几个块 → 对应 RUN apt-get install -y curl
  • 第三层:再放几个块 → 对应 RUN pip install -r requirements.txt
  • 第四层:放一个小人 → 对应 COPY . /app
  • 最顶层(容器层):可以在底板上放临时块,拿走也不影响下面的结构 → 对应容器运行时可写层

每一层都是只读的,多个镜像可以共享相同的层(比如 10 个基于 ubuntu:22.04 的镜像,底层的 Ubuntu 只需在磁盘上存一份)。

text
镜像层(只读,叠加组成完整镜像):
┌─────────────────────────┐  Layer 5: CMD ["python", "app.py"]  (仅 1KB 元数据)
├─────────────────────────┤  Layer 4: COPY . /app               (你的代码,几 MB)
├─────────────────────────┤  Layer 3: RUN pip install -r requirements.txt
├─────────────────────────┤  Layer 2: RUN apt-get install -y python3
├─────────────────────────┤  Layer 1: FROM ubuntu:22.04        (几十 MB)
└─────────────────────────┘

容器运行时(可写层,容器删除后可写层消失):
┌─────────────────────────┐  writable layer: 容器运行时产生的临时文件
├═════════════════════════┤  (镜像层只读,通过 CoW 机制"看起来"可修改)
│      镜像层(只读)       │
└─────────────────────────┘

注意事项:Layer 越多,镜像越大,拉取越慢。合并多个 RUN 指令到一行(用 && 连接)可以减少层数。


Dockerfile 写法与构建#

基本结构#

dockerfile
# 指定基础镜像(必须有)
FROM python:3.11-slim

# 设置工作目录(后续指令的当前目录)
WORKDIR /app

# 先复制依赖声明文件(利用缓存,这步很关键)
COPY requirements.txt .
RUN pip install -r requirements.txt

# 再复制应用代码(代码变动不会导致上面依赖层缓存失效)
COPY . .

# 暴露端口(文档性质,实际映射靠 docker run -p)
EXPOSE 8000

# 容器启动命令
CMD ["python", "app.py"]

多阶段构建#

多阶段构建是生产 Dockerfile 的核心技巧:构建阶段需要编译工具和完整依赖,运行时只需要最终产物

dockerfile
# ========== 阶段1:构建 ==========
FROM golang:1.22-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# CGO_ENABLED=0 生成纯静态二进制,不依赖系统库
RUN CGO_ENABLED=0 GOOS=linux go build -o app .

# ========== 阶段2:运行 ==========
FROM alpine:3.19
# 从构建阶段复制产物(只复制需要的文件)
COPY --from=builder /build/app /app
EXPOSE 8080
CMD ["/app"]

最终镜像只有阶段2的内容,构建阶段的编译器、源码、中间产物都不会进入最终镜像。上面的例子最终镜像只有不到 20MB(alpine + 静态二进制),而如果直接用 golang 镜像运行,镜像会超过 300MB。

缓存策略要点#

Docker 构建缓存的核心规则:指令不变,缓存就命中;前面任何一层失效,后面所有层都失效

所以这行指令的顺序非常关键:

dockerfile
# ❌ 错误:每次改一行代码,整个镜像重新构建
COPY . .              # 代码变动 → 此层及后面所有层缓存失效
RUN pip install -r requirements.txt

# ✅ 正确:依赖文件不变就复用缓存
COPY requirements.txt .
RUN pip install -r requirements.txt   # 这层缓存命中,省去几十秒安装时间
COPY . .                              # 只有代码层会重建

经验法则:把变更频率低的指令放前面,变更频率高的放后面。

指令顺序变更频率说明
FROM极低基础镜像,很少变动
RUN apt-get install系统依赖,变动不多
COPY requirements.txt / go.mod依赖声明,变动较少
RUN pip install / go mod download依赖安装,依赖声明不变就命中缓存
COPY . .业务代码,每次变动
RUN build构建步骤,代码变动后执行

注意事项--no-cache 参数会禁用缓存,调试 Dockerfile 时有用,但日常构建不要加。


常用命令速查#

docker run —— 创建并启动容器#

bash
# 基本启动(前台运行,Ctrl+C 停止)
docker run python:3.11 python app.py

# 后台运行(-d detached)
docker run -d --name my-web -p 8080:80 nginx:alpine

# 端口映射(-p 主机端口:容器端口)
docker run -d -p 3306:3306 mysql:8.0

# 挂载数据卷(-v 主机路径:容器路径)
docker run -d -v /data/mysql:/var/lib/mysql mysql:8.0

# 环境变量(-e)
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql:8.0

# 自动删除容器(退出后自动 rm,适合临时测试)
docker run --rm -it python:3.11 bash

# 交互式终端(-it)
docker run -it --name my-ubuntu ubuntu:22.04 bash

docker exec —— 在运行中的容器里执行命令#

bash
# 进入容器 shell(调试首选)
docker exec -it my-web bash

# 直接执行命令
docker exec my-web ls /app

# 没有 bash 的镜像用 sh
docker exec -it my-web sh

docker logs —— 查看容器日志#

bash
# 查看日志
docker logs my-web

# 实时跟踪(类似 tail -f)
docker logs -f my-web

# 查看最近 100 行
docker logs --tail 100 my-web

docker ps —— 查看容器列表#

bash
# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止的)
docker ps -a

# 只显示容器 ID(脚本处理时有用)
docker ps -q

docker rm / docker rmi —— 删除容器和镜像#

bash
# 删除已停止的容器
docker rm my-web

# 强制删除运行中的容器
docker rm -f my-web

# 删除镜像
docker rmi nginx:alpine

# 清理所有已停止的容器
docker container prune

# 清理所有未使用的镜像
docker image prune -a

注意事项docker rm 删容器,docker rmi 删镜像,别搞混。容器删除后数据卷默认不删除,加 -v 参数可以连同匿名卷一起删除。


数据卷(Volume)#

容器本身的生命周期是短暂的,容器删除后容器内产生的数据也会消失。数据卷解决的就是"容器死了,数据还活着"的问题。

Volume vs Bind Mount#

对比维度Volume(数据卷)Bind Mount(绑定挂载)
存储位置Docker 管理的区域(/var/lib/docker/volumes/宿主机上任意指定的路径
创建方式docker volume create mydata-v mydata:/data-v /host/path:/container/path
适合场景数据库数据、应用持久化数据配置文件挂载、开发时代码热加载
权限管理Docker 自动处理需手动确保宿主机目录权限正确
备份迁移docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/data.tar.gz /data直接操作宿主机文件

使用示例#

bash
# 创建命名数据卷
docker volume create mysql-data

# 使用数据卷(Volume)
docker run -d \
  --name mysql \
  -v mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  mysql:8.0

# 使用绑定挂载(Bind Mount)
# 适合开发场景:本地改代码,容器内实时生效
docker run -d \
  --name web \
  -v $(pwd):/app \
  -p 8000:8000 \
  python:3.11-slim \
  python /app/app.py

# 查看数据卷
docker volume ls

# 查看数据卷详情(包括实际存储路径)
docker volume inspect mysql-data

注意事项:生产环境优先用 Volume,因为 Docker 管理权限更可靠,且支持云存储驱动(如 AWS EBS)。Bind Mount 更适合开发环境。


镜像仓库#

镜像仓库(Registry)是存储和分发镜像的服务。默认是 Docker Hub(docker.io),也可以搭建私有仓库。

三步操作:tag → push → pull#

bash
# 1. tag:给镜像打上仓库地址的标签
docker tag myapp:latest registry.example.com/myapp:1.0.0

# 2. push:推送到仓库
docker push registry.example.com/myapp:1.0.0

# 3. pull:从仓库拉取镜像
docker pull registry.example.com/myapp:1.0.0

私有仓库#

生产环境通常搭建私有镜像仓库,常见方案:

  • Harbor:最受欢迎的开源私有仓库,带 UI、RBAC、漏洞扫描
  • Docker Registry:Docker 官方开源版本,功能简单
  • 云厂商托管:AWS ECR、阿里云 ACR、腾讯云 TCR

私有仓库的概念了解即可,后续 Kubernetes 章节会详细讲解如何配置 ImagePullSecret 从私有仓库拉取镜像。


小结#

本章覆盖了容器技术的核心基础:

  • 容器 vs 虚拟机:容器共享内核、秒级启动、MB 级开销,适合微服务场景;虚拟机强隔离、GB 级开销,适合异构 OS 需求
  • 镜像/容器/Layer:镜像是只读模板,容器是运行实例,Layer 像乐高积木一层层叠加,相同层在磁盘上只存一份
  • Dockerfile:多阶段构建让最终镜像只含运行时产物;指令顺序影响缓存命中率,依赖声明文件要放前面
  • 常用命令docker run(启动)、docker exec(进入)、docker logs(日志)、docker ps(查看)、docker rm/rmi(删除)
  • 数据卷:Volume 适合生产持久化数据,Bind Mount 适合开发时代码挂载
  • 镜像仓库docker tag + docker push + docker pull 三步完成镜像分发