🐳 Docker 速成攻略

从零到实战 · Docker & Docker Compose 完整指南

✅ 适合新手 📦 含 Compose ⚡ 命令速查

一、Docker 是什么?

Docker 是一个开源的容器化平台,让你可以把应用及其依赖打包到一个轻量、可移植的容器中,然后发布到任何 Linux / Windows / macOS 机器上。

🐚 容器 vs 虚拟机

特性容器 (Container)虚拟机 (VM)
启动速度毫秒 ~ 秒级分钟级
资源开销低(共享宿主机内核)高(每个 VM 独占 OS)
镜像大小MB ~ GBGB ~ TB
隔离级别进程级隔离硬件级虚拟化
移植性极高(一次构建,到处运行)一般
💡 一句话总结:容器是「轻量级进程隔离」,VM 是「完整操作系统模拟」。Docker 让部署像「下载 App 并双击」一样简单。

二、安装与验证

🖥️ 各平台安装方式

平台推荐方式
WindowsDocker Desktop for Windows(需 WSL2)
macOSDocker Desktop for Mac
Linux (Ubuntu)curl -fsSL https://get.docker.com | bash
Linux (CentOS / RHEL)sudo yum install -y yum-utils && sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && sudo yum install docker-ce docker-ce-cli containerd.io

✅ 验证安装

# 查看版本docker --version
docker compose version

# 运行 Hello World
docker run hello-world
⚠️ Linux 下非 root 用户运行 Docker:
sudo usermod -aG docker $USER 然后重新登录。

三、核心概念

Docker 生态有三大核心对象,理解它们等于掌握 Docker 的 80%:

概念类比说明
镜像 (Image) 📀 安装光盘 / 类 只读模板,包含运行应用所需的一切(代码、运行时、库、环境变量、配置文件)。
容器 (Container) 🏃 运行的进程 / 实例 镜像的运行态实例。可以启动、停止、删除。每个容器是隔离的。
仓库 (Repository / Registry) 📦 应用商店 存放镜像的地方。公共的 Docker Hub,也可以自建私有仓库。
🔁 三者的关系:
仓库 拉取 镜像 → 用镜像创建 容器 → 容器运行应用。修改后可以 docker commit 生成新镜像,推回仓库。

四、镜像管理

📥 拉取镜像

# 从 Docker Hub 拉取
docker pull nginx:latest
#  pull            子命令,从仓库拉取镜像
#  nginx:latest    镜像名:标签(不指定标签默认 :latest)
docker pull ubuntu:22.04
docker pull python:3.12-slim

# 从私有仓库拉取
docker pull registry.example.com/myapp:v1.0
#  pull                        子命令,从仓库拉取镜像
#  registry.example.com/myapp:v1.0  完整镜像地址:仓库地址/镜像名:标签

📋 查看镜像

docker images
docker image ls

# 简洁模式(只显示镜像 ID)
docker images -q
#  -q    只显示镜像 ID(静默模式),可配合 xargs 批量操作

# 按名称过滤
docker images | grep nginx

🏷️ 打标签

docker tag nginx:latest my-nginx:v1
docker tag nginx:latest my-nginx:v1.0.0

🗑️ 删除镜像

# 按名称:标签删除
docker rmi my-nginx:v1
#  rmi          子命令,删除镜像(remove image)
#  my-nginx:v1  镜像名:标签

# 按 ID 删除
docker rmi abc123def456
#  rmi              子命令,删除镜像(remove image)
#  abc123def456     镜像 ID(docker images 可以看到短 ID 或完整 ID)

# 强制删除(即使有依赖的容器)
docker rmi -f my-nginx:v1
#  -f    强制删除

# 删除所有未使用的镜像(悬空镜像)
docker image prune
#  prune    清理无标签的悬空镜像(dangling images)

# 删除所有未被容器使用的镜像(慎用)
docker image prune -a

📸 从容器生成新镜像(docker commit)

# 将容器的当前状态保存为新镜像
docker commit my-nginx my-nginx:custom-v1
#  commit          子命令,将容器当前状态保存为新镜像
#  my-nginx        容器名称或 ID
#  my-nginx:custom-v1  新镜像名:标签

# 添加变更说明
docker commit -m "修改了 nginx.conf" my-nginx my-nginx:v2
#  -m                    -m 提交消息(message),描述做了什么修改
#  "修改了 nginx.conf"   提交消息内容
#  my-nginx              容器名称或 ID
#  my-nginx:v2           新镜像名:标签

📤 导入 / 导出镜像

# 导出镜像为 tar 文件
docker save -o nginx.tar nginx:latest
#  save            子命令,保存镜像为 tar 归档
#  -o nginx.tar    -o 指定输出文件名
#  nginx:latest    要导出的镜像名:标签

# 从 tar 文件导入镜像
docker load -i nginx.tar
#  load            子命令,加载 tar 归档为镜像
#  -i nginx.tar    -i 从文件导入(input)

🔧 附:镜像加速器配置

在国内拉取 Docker Hub 镜像通常很慢,建议配置镜像加速器(Registry Mirror)。Docker 支持通过 daemon.json 配置多个加速器地址。

📝 配置方法

编辑(或创建)Docker 配置文件 /etc/docker/daemon.json(Linux / macOS)
C:\ProgramData\docker\config\daemon.json(Windows 管理员身份):

/etc/docker/daemon.json
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerproxy.com",
    "https://docker.nju.edu.cn",
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}
📌 说明:
• 以上列表是 国内常用公共加速器,可用性随时间变化,请自行测试
阿里云加速器:需注册阿里云账号后获取 https://<你的ID>.mirror.aliyuncs.com
推荐:配置 2~3 个即可,Docker 会按优先级依次尝试
# 重启 Docker 使配置生效
# Linux (systemd)
sudo systemctl daemon-reload && sudo systemctl restart docker

# macOS (Docker Desktop → Settings → Docker Engine → 粘贴 → Apply & Restart)

# Windows
# Docker Desktop → Settings → Docker Engine → 粘贴 daemon.json → Apply & Restart

# 验证是否生效
docker info | findstr -i "Registry Mirrors"
# 输出应显示你配置的镜像地址

🔒 私有仓库(Insecure Registry)

如果自建了 HTTP 协议的私有仓库(非 HTTPS),Docker 默认拒绝连接,需要添加到不安全仓库白名单:

/etc/docker/daemon.json
{
  "insecure-registries": [
    "192.168.1.100:5000",
    "registry.internal.example.com:80"
  ]
}
# 然后
sudo systemctl restart docker

# 测试
docker pull 192.168.1.100:5000/myapp:v1

🔐 HTTPS 自签证书仓库

如果自建了 HTTPS 协议的私有仓库,但使用了自签证书(非公开 CA 签发)
Docker 默认会因证书不受信任而拒绝连接。此时不要把仓库加到 insecure-registries(那样会降级为 HTTP,不安全),
正确做法是让 Docker 信任该证书

# 将自签 CA 证书放到 Docker 的仓库证书目录
# 目录命名规则:/etc/docker/certs.d/<仓库地址>:<端口>/

sudo mkdir -p /etc/docker/certs.d/registry.example.com:5000

# 将你的 CA 证书(ca.crt)复制到该目录
sudo cp /path/to/your-ca.crt /etc/docker/certs.d/registry.example.com:5000/ca.crt

# 无需重启 Docker,立即生效

# 测试拉取
docker pull registry.example.com:5000/myapp:v1
# Windows 路径(Docker Desktop)
C:\Users\<你的用户名>\.docker\certs.d\registry.example.com:5000\ca.crt
📌 关键区别:
insecure-registries → 跳过 HTTPS,明文传输,仅用于 HTTP 仓库
certs.d/ 目录 → 保留 HTTPS 加密传输,只是额外信任你的自签证书
推荐:能用证书信任就不要用 insecure_registries

五、容器管理

🚀 创建并运行容器

📌 端口映射语法:
-p <宿主机端口>:<容器端口>

👉 冒号左边 = 宿主机(你电脑)上要使用的端口
👉 冒号右边 = 容器内部服务监听的端口

一句话记住:「左边宿主机端口,右边容器端口」

例如 -p 8080:80 表示:
  → 访问你电脑的 http://localhost:8080
  → 流量会转发到容器内部的 80 端口(Nginx 默认监听端口)

多端口映射:多个 -p 或用逗号分隔
  -p 8080:80 -p 443:443-p "8080:80,443:443"
# 基本运行
docker run nginx

# 后台运行(-d, detached)
docker run -d nginx

# 指定名称(--name)
docker run -d --name my-nginx nginx

# 端口映射 -p 宿主机端口:容器端口
docker run -d -p 8080:80 nginx
#  -d             后台运行(detached),容器在后台默默跑
#  -p 8080:80     端口映射 格式:宿主机端口:容器端口
#  nginx          使用的镜像名

# 挂载卷(-v 宿主机目录:容器目录)
docker run -d -p 8080:80 -v /my/data:/usr/share/nginx/html nginx
#  -v /my/data:/usr/share/nginx/html  -v 挂载卷 格式:宿主机目录:容器目录

# 设置环境变量(-e)
docker run -d -e MYSQL_ROOT_PASSWORD=root123 mysql:8.0
#  -e MYSQL_ROOT_PASSWORD=root123  -e 设置环境变量 格式:KEY=VALUE

# 自动删除(--rm,适合测试)
docker run --rm -it ubuntu:22.04 bash
#  --rm         退出后自动删除容器
#  -i           保持输入流开放
#  -t           分配伪终端
#  ubuntu:22.04 使用的镜像
#  bash         容器内要执行的命令

# 交互式终端(-it)
docker run -it python:3.12-slim python
#  -i             交互输入
#  -t             伪终端
#  python:3.12-slim  使用的镜像
#  python         要执行的命令

📊 查看容器

# 查看运行中的容器
docker ps

# 查看所有容器(包括已停止的)
docker ps -a
#  -a    显示所有容器(all),默认只显示运行中的

# 查看最新创建的 N 个容器
docker ps -n 5
#  -n N  显示最近 N 个创建的容器

# 仅显示容器 ID
docker ps -q
#  -q    只显示容器 ID(静默模式),可配合 $(...) 批量操作

⏯️ 启停容器

# 启动已停止的容器
docker start my-nginx
#  my-nginx  容器名称或 ID

# 停止容器
docker stop my-nginx
#  my-nginx  容器名称或 ID

# 重启容器
docker restart my-nginx
#  my-nginx  容器名称或 ID

# 强制停止(发送 SIGKILL)
docker kill my-nginx
#  my-nginx  容器名称或 ID

🔍 进入容器

# 在运行中的容器里执行命令
docker exec -it my-nginx bash
#  -i     保持输入流开放(可以交互地输入命令)
#  -t     分配伪终端(显示 shell 提示符,支持颜色)
#  my-nginx  容器名称或 ID
#  bash      容器内要执行的命令
#  组合 -it = 交互式终端,进入后可以像 SSH 一样操作容器

# 执行单条命令(不需要 -it)
docker exec my-nginx ls -la /etc/nginx

# 以 root 用户进入
docker exec -u root -it my-nginx bash
#  -u    指定用户(默认是容器 entrypoint 的用户)

📋 容器日志

# 查看日志
docker logs my-nginx

# 实时追踪(类似 tail -f)
docker logs -f my-nginx
#  -f           实时追踪输出(follow),Ctrl+C 退出
#  my-nginx     容器名称或 ID

# 显示时间戳
docker logs -t my-nginx
#  -t    为每条日志添加时间戳

# 只显示最后 N 行
docker logs --tail 50 my-nginx
#  --tail 50   只显示最近 50 行日志
#  my-nginx    容器名称或 ID

🗑️ 删除容器

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

# 强制删除运行中的容器
docker rm -f my-nginx
#  -f         强制删除(即使容器正在运行)
#  my-nginx   容器名称或 ID

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

# 删除所有容器(慎用!)
docker rm -f $(docker ps -aq)
#  $(docker ps -aq)   shell 命令替换,将子命令输出作为参数
#  docker ps -aq      列出所有容器 ID

# 清理所有停止的容器 + 未使用的网络/镜像/构建缓存
docker system prune -a
#  prune  系统级清理子命令
#  -a     清理所有未使用的资源(不只是悬空镜像)

📦 容器与宿主机文件互拷

# 从宿主机拷贝到容器
docker cp ./app.conf my-nginx:/etc/nginx/conf.d/
#  ./app.conf                    宿主机源文件路径
#  my-nginx:                     容器名称("容器名:" 代表往容器内)
#  /etc/nginx/conf.d/            容器内目标路径

# 从容器的拷贝到宿主机
docker cp my-nginx:/var/log/nginx/access.log ./
#  my-nginx:                     容器名称("容器名:" 代表从容器的)
#  /var/log/nginx/access.log     容器内文件路径
#  ./                            宿主机目标路径

📊 查看容器资源占用

# 实时资源监控
docker stats
#  [容器名]    可指定容器(不指定则显示所有运行中容器)

# 查看容器内进程
docker top my-nginx
#  my-nginx  容器名称或 ID

# 查看容器详细信息(JSON)
docker inspect my-nginx
#  my-nginx  容器名称或 ID

# 查看端口映射
docker port my-nginx
#  my-nginx  容器名称或 ID

🔗 连接到容器主进程

# 连接到容器的主进程(如 nginx、bash)
docker attach my-nginx
#  my-nginx  容器名称或 ID

# 退出时不影响容器继续运行
# Ctrl+P 然后 Ctrl+Q(detach 快捷键)

🔄 容器暂停 / 恢复

# 暂停容器内所有进程(SIGSTOP)
docker pause my-nginx
#  my-nginx  容器名称或 ID

# 恢复容器内进程
docker unpause my-nginx
#  my-nginx  容器名称或 ID

🔍 查看容器文件变更

# 对比容器文件系统与镜像的差异
docker diff my-nginx
#  my-nginx  容器名称或 ID
# 输出示例:
# C /etc/nginx/nginx.conf    (修改)
# A /usr/share/nginx/html    (新增)
# D /etc/nginx/conf.d/default.conf(删除)

📤 导出容器文件系统

# 将容器文件系统导出为 tar 包(不含元数据/层历史)
docker export my-nginx -o my-nginx.tar
#  my-nginx               容器名称或 ID
#  -o my-nginx.tar        -o 输出文件名

# 从 tar 包导入为镜像
docker import my-nginx.tar my-nginx:snapshot-v1
#  my-nginx.tar           tar 包路径
#  my-nginx:snapshot-v1   镜像名称:标签

✏️ 容器改名 / 更新资源限制

# 重命名容器
docker rename old-name new-name
#  old-name  容器原名称
#  new-name  新名称

# 更新容器资源限制(无需重启)
docker update --memory 512m --cpus 1 my-nginx
#  --memory 512m   内存限制(m=兆字节, g=吉字节)
#  --cpus 1        CPU 核心数限制
#  my-nginx        容器名称或 ID

🔄 容器暂停 / 恢复

# 暂停容器内所有进程(SIGSTOP)
docker pause my-nginx

# 恢复容器内进程
docker unpause my-nginx

🔍 查看容器文件变更

# 对比容器文件系统与镜像的差异
docker diff my-nginx
# 输出示例:
# C /etc/nginx/nginx.conf    (修改)
# A /usr/share/nginx/html    (新增)
# D /etc/nginx/conf.d/default.conf(删除)

📤 导出容器文件系统

# 将容器文件系统导出为 tar 包(不含元数据/层历史)
docker export my-nginx -o my-nginx.tar

# 从 tar 包导入为镜像
docker import my-nginx.tar my-nginx:snapshot-v1

✏️ 容器改名 / 更新资源限制

# 重命名容器
docker rename old-name new-name

# 更新容器资源限制(无需重启)
docker update --memory 512m --cpus 1 my-nginx

六、网络与存储

🌐 网络模式

网络模式说明使用场景
bridge(默认)容器通过虚拟网桥通信,与宿主机隔离单机多容器互联
host容器直接使用宿主机网络栈(无隔离)追求性能的场景
none容器无网络安全隔离或自定义网络
overlay跨宿主机容器通信(Swarm 模式)集群部署
# 创建自定义网络(推荐,可容器名互联)
docker network create my-net

# 容器加入自定义网络
docker run -d --name web --network my-net nginx

# 查看网络
docker network ls

# 查看网络详情
docker network inspect my-net

# 将已有容器连接到网络
docker network connect my-net my-nginx

# 断开网络
docker network disconnect my-net my-nginx
💡 同一个 bridge 网络下的容器,可以直接用容器名(而不是 IP)通信。
例如:web 容器可以通过 http://db:3306 访问 db 容器。

💾 数据持久化:Volumes & Bind Mounts

📌 挂载语法核心规则:
所有 -v / --volume 参数的格式统一为:
-v <宿主机路径或卷名>:<容器内路径>

👉 冒号左边 = 宿主机(你的电脑)上的目录/卷名
👉 冒号右边 = 容器内部的目录

一句话记住:「左边宿主机,右边容器内」
方式说明命令示例左边是什么右边是什么
Volume
(卷,推荐)
由 Docker 管理,存在宿主机特定目录 -v mydata:/data mydata ← 卷名(Docker 自动管理路径) /data ← 容器内的目录
Bind Mount
(绑定挂载)
挂载宿主机任意目录到容器 -v /宿主机/路径:/容器/路径 /宿主机/路径 ← 你电脑上的绝对路径 /容器/路径 ← 容器内的目录
tmpfs Mount 数据存在内存中,容器停止即消失 --tmpfs /tmp 无(仅容器内路径) /tmp ← 容器内的内存目录
⚠️ 常见误区:
-v /data:/app/data ❌ —— 左边 /data宿主机根目录下的 data,不是卷名!
-v mydata:/app/data ✅ —— 左边 mydata 没有前导斜杠,Docker 会把它当作卷名
• 区分方法:左边以 / 开头 → Bind Mount(宿主机路径);无 / 开头 → Volume(卷名)
# 卷 (Volume) —— 左边是卷名,右边是容器内路径
docker volume create mydata
docker run -d -v mydata:/var/lib/mysql mysql:8.0
#                 ↑ 卷名          ↑ 容器内目录

# 绑定挂载 (Bind Mount) —— 左边是宿主机路径,右边是容器内路径
docker run -d -p 8080:80 -v $(pwd)/html:/usr/share/nginx/html nginx
#                        ↑ 宿主机当前目录/html    ↑ 容器内 Nginx 静态文件目录

# 绑定挂载用绝对路径(Windows 需写完整路径)
docker run -d -v C:\项目\html:/usr/share/nginx/html nginx

七、Dockerfile 编写

Dockerfile 是构建镜像的「配方文件」。下面从一个 Node.js 应用示例入手:

📄 示例 Dockerfile

# 1. 基础镜像
FROM node:20-alpine

# 2. 设置工作目录
WORKDIR /app

# 3. 复制依赖描述文件(利用缓存层)
COPY package.json package-lock.json ./

# 4. 安装依赖
RUN npm ci --only=production

# 5. 复制源码
COPY . .

# 6. 暴露端口
EXPOSE 3000

# 7. 启动命令
CMD ["node", "src/index.js"]

🔑 Dockerfile 常用指令

指令说明示例
FROM指定基础镜像(必须第一行)FROM python:3.12-slim
WORKDIR设置工作目录(自动创建)WORKDIR /app
COPY复制文件到镜像COPY . .
ADD类似 COPY,支持 URL / 自动解压 tarADD app.tar.gz /app
RUN构建时执行命令(产生新层)RUN apt update && apt install -y curl
ENV设置环境变量ENV NODE_ENV=production
EXPOSE声明容器监听端口(文档性质)EXPOSE 8080
CMD容器启动默认命令(可被覆盖)CMD ["python", "app.py"]
ENTRYPOINT容器启动入口(不易覆盖)ENTRYPOINT ["docker-entrypoint.sh"]
ARG构建参数(构建时变量)ARG VERSION=1.0
USER切换到非 root 用户运行USER node
HEALTHCHECK健康检查HEALTHCHECK CMD curl -f http://localhost || exit 1

🔨 构建镜像

# 基本构建
docker build -t myapp:v1 .
#  -t myapp:v1   -t 指定镜像名称:标签
#  .             构建上下文路径(包含 Dockerfile 的目录)

# 指定 Dockerfile 文件名
docker build -f Dockerfile.prod -t myapp:prod .
#  -f Dockerfile.prod   -f 指定 Dockerfile 文件名(默认是 Dockerfile)
#  -t myapp:prod        -t 镜像名称:标签
#  .                    构建上下文

# 传递构建参数
docker build --build-arg VERSION=2.0 -t myapp:v2 .
#  --build-arg VERSION=2.0   --build-arg 传递构建时变量(ARG 指令使用)
#  -t myapp:v2               -t 镜像名称:标签
#  .                         构建上下文

# 多阶段构建(减小镜像体积)
docker build -t myapp:latest .

✨ 多阶段构建示例

# 第1阶段 —— 构建
FROM golang:1.22-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o app .

# 第2阶段 —— 运行(极小的镜像)
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /build/app .
EXPOSE 8080
CMD ["./app"]
💡 最佳实践:
• 尽量使用官方基础镜像(如 alpine 版本更小)
• 把「不常变」的层放前面(COPY package.json 在 COPY . 之前),最大化缓存利用
• 使用多阶段构建减小最终镜像体积
• 不要以 root 运行应用(用 USER 指令切换)

八、Docker Compose 详解

📖 什么是 Docker Compose?

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过一个 compose.yaml(或 docker-compose.yml)文件,你可以用一条命令启动、停止、管理整个应用栈(例如:前端 + 后端 + 数据库 + Redis + 消息队列)。

💡 Docker Compose v2 已集成到 Docker CLI 中:
现在的命令是 docker compose(中间没有横杠),不再是 docker-compose

📄 compose.yaml 基本结构

version: "3.9"     # ⚠️ 目前可省略(Docker 会自动推断)

services:          # 定义各个服务(容器)
  web:
    build: .       # 从 Dockerfile 构建
    ports:
      - "8080:80"
    depends_on:
      - db

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root123
    volumes:
      - db_data:/var/lib/mysql

volumes:           # 声明命名卷
  db_data:

networks:          # 声明网络(可选)
  mynet:

🔧 Compose 文件核心配置项

配置项说明示例
services.<name>.image使用的镜像image: nginx:alpine
services.<name>.build构建配置(Dockerfile 路径)build: ./backend
services.<name>.ports端口映射
格式:宿主机端口:容器端口
ports: - "3000:3000"
services.<name>.environment环境变量environment: NODE_ENV=production
services.<name>.env_file从文件加载环境变量env_file: .env
services.<name>.volumes挂载卷 / 绑定挂载
格式:宿主机路径或卷名:容器内路径
volumes: - ./data:/data
services.<name>.depends_on依赖服务(启动顺序)depends_on: - db - redis
services.<name>.command覆盖容器 CMDcommand: npm run start:prod
services.<name>.restart重启策略restart: unless-stopped
services.<name>.networks指定网络networks: - frontend
services.<name>.healthcheck健康检查healthcheck: test: ["CMD", "curl", "-f", "http://localhost"]
services.<name>.container_name自定义容器名(不推荐 Compose 中指定)container_name: my-app

🚢 Compose 常用命令

# 启动所有服务(-d 后台运行)
docker compose up -d

# 构建并启动(--build 强制重新构建)
docker compose up --build -d

# 查看运行中的服务
docker compose ps

# 查看日志(-f 实时追踪)
docker compose logs -f

# 查看某个服务的日志
docker compose logs web

# 停止所有服务
docker compose stop

# 停止并删除所有服务(容器、网络)
docker compose down

# 停止并删除 + 删除卷(⚠️ 数据会丢失)
docker compose down -v

# 在运行中的服务中执行命令
docker compose exec db bash

# 重启某服务
docker compose restart web

# 暂停 / 恢复服务
docker compose pause web
docker compose unpause web

# 查看服务启动顺序和各种状态
docker compose top

# 查看 Compose 项目的配置(合并后的内容)
docker compose config

# 查看容器资源使用
docker compose stats

🔁 Compose 中 .env 文件

Compose 自动读取同目录下的 .env 文件,变量可用于 Compose 文件的 ${VAR} 占位符中:

# .env 文件
DB_PASSWORD=mys3cret
APP_PORT=4000
# compose.yaml 引用 .env 变量
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
  web:
    build: .
    ports:
      - "${APP_PORT}:3000"

九、Compose 实战示例

🌐 Web 应用 + PostgreSQL

services:
  web:
    build: ./app
    ports:
      - "3000:3000"                    # ← 左边:宿主机端口  右边:容器端口
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/mydb
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pg_data:/var/lib/postgresql/data   # ← 左边:卷名  右边:容器内路径
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 5s
      retries: 5
    restart: unless-stopped

volumes:
  pg_data:

📦 全栈应用(Vite + FastAPI + Redis + MySQL)

services:
  frontend:
    build: ./frontend
    ports:
      - "5173:5173"                  # ← 左边:宿主机端口  右边:容器端口
    environment:
      VITE_API_URL: http://localhost:8000
    depends_on:
      - backend
    volumes:
      - ./frontend:/app                 # ← 左边:宿主机源码目录  右边:容器内工作目录
      - /app/node_modules               # ← 仅容器内路径(匿名卷,避免覆盖 node_modules)

  backend:
    build: ./backend
    ports:
      - "8000:8000"                  # ← 左边:宿主机端口  右边:容器端口
    environment:
      DB_URL: mysql://root:root123@mysql:3306/mydb
      REDIS_URL: redis://redis:6379
    depends_on:
      - mysql
      - redis
    volumes:
      - ./backend:/app                  # ← 左边:宿主机源码目录  右边:容器内工作目录

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: mydb
    volumes:
      - mysql_data:/var/lib/mysql       # ← 左边:卷名  右边:容器内数据目录
    ports:
      - "3306:3306"                  # ← 左边:宿主机端口  右边:容器端口

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data                # ← 左边:卷名  右边:容器内数据目录

volumes:
  mysql_data:
  redis_data:

🧰 Nginx 反向代理

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"                      # ← 左边:宿主机端口  右边:容器端口
      - "443:443"                    # ← 左边:宿主机端口  右边:容器端口
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - web1
      - web2
    restart: unless-stopped

  web1:
    build: ./app
    environment:
      - NODE_ENV=production

  web2:
    build: ./app
    environment:
      - NODE_ENV=production

十、日常运维技巧

🧹 清理系统

# 清理所有未使用的资源(容器、网络、悬空镜像、构建缓存)
docker system prune

# 更彻底(包括未使用的镜像和卷)
docker system prune -a --volumes

📦 推送镜像到仓库

# 登录到 Docker Hub
docker login

# 打标签(必须带用户名/仓库前缀)
docker tag myapp:v1 username/myapp:v1

# 推送
docker push username/myapp:v1

# 推送到私有仓库
docker tag myapp:v1 registry.example.com/myapp:v1
docker push registry.example.com/myapp:v1

🔒 以非 root 用户运行

# Dockerfile 中
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

# 也可以在 Compose 中指定
services:
  app:
    image: myapp
    user: "1000:1000"

🧪 开发时热重载

利用 Bind Mount 将源码挂载到容器,结合 nodemon / uvicorn --reload 实现修改即自动重启:

services:
  app:
    build: .
    volumes:
      - .:/app       # 源码挂载到容器
    command: npx nodemon src/index.js

📈 限制资源

# 限制内存和 CPU
docker run -d --memory="512m" --cpus="1.5" nginx

# Compose 中限制
services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.5"

🏷️ 给镜像加多标签 / 推送到多个仓库

docker tag myapp:v1 myapp:latest
docker tag myapp:v1 username/myapp:v1
docker tag myapp:v1 username/myapp:latest
docker push --all-tags username/myapp
⚠️ 生产环境注意事项:
• 不要用 latest 标签部署生产 — 用明确版本号
• 始终配置 restart: unless-stopped
• 设置健康检查 healthcheck
• 敏感信息用 Docker Secrets.env + .gitignore,不要硬编码

🔧 附:Docker 代理配置

在公司网络、学校环境或需要科学上网的场景下,Docker 需要配置代理才能正常拉取镜像、构建和运行容器。代理配置分为三个层面:

层面作用范围配置位置
Docker Daemon 代理docker pull / push / build(守护进程发起的请求)/etc/systemd/system/docker.service.d/
容器运行时代理容器内部应用访问外网环境变量 HTTP_PROXY
构建时代理Dockerfile 中 RUN 命令下载依赖--build-argARG

1️⃣ Docker Daemon 代理(拉取镜像时)

适用于 docker pulldocker pushdocker build 中容器引擎下载依赖包等场景:

# Linux (systemd) —— 创建配置目录和文件
sudo mkdir -p /etc/systemd/system/docker.service.d

# 创建代理配置文件
sudo tee /etc/systemd/system/docker.service.d/proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,.local,.example.com,10.0.0.0/8"
EOF

# 重新加载并重启
sudo systemctl daemon-reload
sudo systemctl restart docker

# 验证代理是否生效
sudo systemctl show docker --property Environment
📌 说明:
HTTP_PROXYHTTPS_PROXY 值请替换成你自己的代理地址(http:// 协议,不是 socks5)
NO_PROXY 配置不走代理的地址段,避免本地局域网和内部服务走代理导致连接失败
• Docker Desktop(macOS / Windows)用户:Settings → Resources → Proxies 中直接填写

2️⃣ 容器运行时代理

容器内的应用程序需要通过代理访问外网时设置:

# docker run 方式
docker run -e HTTP_PROXY=http://host.docker.internal:7890 \
           -e HTTPS_PROXY=http://host.docker.internal:7890 \
           -e NO_PROXY=localhost,127.0.0.1 \
           alpine:latest curl -s https://www.google.com

# Compose 方式
services:
  app:
    image: alpine
    environment:
      HTTP_PROXY: http://host.docker.internal:7890
      HTTPS_PROXY: http://host.docker.internal:7890
      NO_PROXY: localhost,127.0.0.1
⚠️ host.docker.internal 说明:
macOS / Windows(Docker Desktop):host.docker.internal 自动解析为宿主机地址,可直接用
Linux:默认没有 host.docker.internal,需要用 --add-host host.docker.internal:host-gateway 或在 Compose 中添加 extra_hosts
• 或者 Linux 下直接填宿主机内网 IP(如 http://192.168.1.100:7890
# Linux 下 Compose 添加 host.docker.internal
services:
  app:
    image: alpine
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      HTTP_PROXY: http://host.docker.internal:7890

3️⃣ 构建时代理(Dockerfile build)

当 Dockerfile 中 RUN 命令需要下载依赖包时,通过构建参数传入代理,不影响最终镜像(构建参数不持久化):

# 命令行构建时传入
docker build \
  --build-arg HTTP_PROXY=http://host.docker.internal:7890 \
  --build-arg HTTPS_PROXY=http://host.docker.internal:7890 \
  -t myapp .

# Dockerfile 中声明 ARG(推荐放在基础镜像之后)
FROM node:20-alpine
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

# RUN 命令会自动读取这些环境变量
RUN npm install

# 如果用国内 npm 源,也可以配置镜像源
RUN npm config set registry https://registry.npmmirror.com
💡 小技巧:
• 不想每次手动输入 --build-arg,可以在 Shell 中提前 export BUILDKIT_PROGRESS=plain
• 或者用 Docker Compose 的 args 字段固化构建参数:
services:
  app:
    build:
      context: .
      args:
        HTTP_PROXY: "http://proxy.example.com:7890"
        HTTPS_PROXY: "http://proxy.example.com:7890"

4️⃣ 全局配置(Docker Desktop GUI)

macOS / Windows 用户可以直接在 Docker Desktop 界面配置,不涉及命令行编辑:

Docker Desktop →
  Settings (⚙️) →
    Resources →
      Proxies →
        Manual proxy configuration →
          HTTP:     http://127.0.0.1:7890
          HTTPS:    http://127.0.0.1:7890
          No Proxy: localhost,127.0.0.1,.local,.example.com

→ Apply & Restart

十一、命令速查表

🖼️ 镜像命令

命令作用
docker pull <镜像>拉取镜像
docker images查看镜像列表
docker rmi <镜像>删除镜像
docker tag <镜像> <新标签>打标签
docker build -t <名> .构建镜像
docker save -o file.tar <镜像>导出镜像为 tar
docker load -i file.tar从 tar 导入镜像
docker push <镜像>推送镜像到仓库
docker image prune清理悬空镜像

📦 容器命令

命令作用
docker run [选项] <镜像>创建并启动容器
docker ps查看运行中容器
docker ps -a查看所有容器
docker start <容器>启动容器
docker stop <容器>停止容器
docker restart <容器>重启容器
docker kill <容器>强制杀死容器
docker rm <容器>删除容器(需停止)
docker rm -f <容器>强制删除容器
docker exec -it <容器> bash进入容器
docker logs [-f] <容器>查看日志
docker cp <src> <容器>:<dst>文件拷贝
docker stats资源监控
docker inspect <容器>查看容器详情
docker container prune清理所有停止容器

🌐 网络命令

命令作用
docker network ls查看网络列表
docker network create <名>创建网络
docker network rm <名>删除网络
docker network connect <网络> <容器>连接容器到网络
docker network disconnect <网络> <容器>断开容器网络

💾 卷命令

命令作用
docker volume ls查看卷列表
docker volume create <名>创建卷
docker volume rm <名>删除卷
docker volume prune清理未使用卷

🚢 Compose 命令

命令作用
docker compose up -d启动所有服务
docker compose down停止并删除服务
docker compose ps查看服务状态
docker compose logs -f查看日志
docker compose exec <服务> bash进入服务容器
docker compose restart <服务>重启服务
docker compose stop停止服务
docker compose start启动已停止的服务
docker compose pull拉取所有服务的镜像
docker compose build构建所有服务的镜像
docker compose config验证并查看配置
docker compose top查看各服务进程
docker compose stats查看资源占用
docker compose down -v删除服务 + 卷(数据全清)

🧹 系统级

命令作用
docker system df查看磁盘使用情况
docker system prune清理未使用的资源
docker system prune -a --volumes深度清理所有无用资源
docker info查看 Docker 系统信息
docker version查看版本