最后更新于:2026年7月

Docker 改变了软件的打包和交付方式。 从"在我的机器上能跑"到"在任何地方都能跑",容器技术让应用部署变得简单、一致、可复制。根据 2025 年 CNCF 调查,超过 90% 的组织在生产环境使用容器。
但很多人对 Docker 的使用还停留在 docker run 和简单的 docker-compose up。镜像是怎么构建的?网络是怎么工作的?数据怎么持久化?多容器怎么编排?生产环境怎么部署?
本文从核心原理到生产级实践,带你全面掌握 Docker 进阶技能。
一、Docker 核心概念回顾
1.1 Docker 架构
PLAINTEXT
Docker 架构:
┌─────────────────────────────────────────┐
│ Docker Client │
│ (docker CLI / API) │
└─────────────────┬───────────────────────┘
│ REST API
┌─────────────────▼───────────────────────┐
│ Docker Daemon │
│ (dockerd, 运行在宿主机上) │
└──────┬──────────────┬───────────────────┘
│ │
┌──────▼──────┐ ┌─────▼──────┐ ┌─────────────┐
│ Images │ │ Containers │ │ Network │
│ 镜像 │ │ 容器 │ │ 网络 │
└─────────────┘ └────────────┘ └─────────────┘
│ │
┌──────▼──────────────▼─────────────────────┐
│ Storage Driver │
│ (overlay2 / devicemapper / btrfs) │
└──────────────────────────────────────────┘
│
┌──────▼──────┐
│ Registry │
│ (镜像仓库) │
│ Docker Hub │
│ 阿里云/腾讯云│
└─────────────┘Docker 架构:
┌─────────────────────────────────────────┐
│ Docker Client │
│ (docker CLI / API) │
└─────────────────┬───────────────────────┘
│ REST API
┌─────────────────▼───────────────────────┐
│ Docker Daemon │
│ (dockerd, 运行在宿主机上) │
└──────┬──────────────┬───────────────────┘
│ │
┌──────▼──────┐ ┌─────▼──────┐ ┌─────────────┐
│ Images │ │ Containers │ │ Network │
│ 镜像 │ │ 容器 │ │ 网络 │
└─────────────┘ └────────────┘ └─────────────┘
│ │
┌──────▼──────────────▼─────────────────────┐
│ Storage Driver │
│ (overlay2 / devicemapper / btrfs) │
└──────────────────────────────────────────┘
│
┌──────▼──────┐
│ Registry │
│ (镜像仓库) │
│ Docker Hub │
│ 阿里云/腾讯云│
└─────────────┘
1.2 核心概念对比
| 概念 | 说明 | 类比 |
|---|---|---|
| Image(镜像) | 只读模板,包含运行应用所需的一切 | 安装光盘/ISO |
| Container(容器) | 镜像的运行实例,可读写的层 | 运行中的虚拟机 |
| Registry(仓库) | 存储和分发镜像的服务 | 应用商店 |
| Dockerfile | 构建镜像的脚本 | 编译脚本 |
| Volume(卷) | 持久化存储,独立于容器生命周期 | 外部硬盘 |
| Network(网络) | 容器间通信的虚拟网络 | 局域网 |
1.3 镜像分层原理
PLAINTEXT
镜像分层结构:
┌──────────────────────┐
│ Container Layer │ ← 容器层(可写,运行时)
│ (R/W) │
├──────────────────────┤
│ Layer N: App Code │ ← 应用代码层
├──────────────────────┤
│ Layer N-1: Runtime │ ← 运行时层(Node/Python)
├──────────────────────┤
│ Layer N-2: OS Base │ ← 基础系统层(alpine/ubuntu)
├──────────────────────┤
│ Layer 1: Kernel │ ← 内核(共享宿主机内核)
└──────────────────────┘
特点:
- 每一层都是只读的
- 镜像复用:相同层只存储一份
- 容器启动时在顶层添加可写层
- UnionFS(联合文件系统)实现多层叠加镜像分层结构:
┌──────────────────────┐
│ Container Layer │ ← 容器层(可写,运行时)
│ (R/W) │
├──────────────────────┤
│ Layer N: App Code │ ← 应用代码层
├──────────────────────┤
│ Layer N-1: Runtime │ ← 运行时层(Node/Python)
├──────────────────────┤
│ Layer N-2: OS Base │ ← 基础系统层(alpine/ubuntu)
├──────────────────────┤
│ Layer 1: Kernel │ ← 内核(共享宿主机内核)
└──────────────────────┘
特点:
- 每一层都是只读的
- 镜像复用:相同层只存储一份
- 容器启动时在顶层添加可写层
- UnionFS(联合文件系统)实现多层叠加
二、镜像优化
2.1 基础镜像选择
DOCKERFILE
# ❌ 不推荐:使用完整版 Ubuntu/Debian
FROM ubuntu:latest
RUN apt-get update && apt-get install -y nodejs npm
# 镜像大小:~700MB
# ✅ 推荐:使用 Alpine 版本
FROM node:20-alpine
# 镜像大小:~150MB
# ✅ 推荐:使用 distroless(Google 出品,最小化)
FROM gcr.io/distroless/nodejs20-debian11
# 镜像大小:~50MB,无 Shell,更安全# ❌ 不推荐:使用完整版 Ubuntu/Debian
FROM ubuntu:latest
RUN apt-get update && apt-get install -y nodejs npm
# 镜像大小:~700MB
# ✅ 推荐:使用 Alpine 版本
FROM node:20-alpine
# 镜像大小:~150MB
# ✅ 推荐:使用 distroless(Google 出品,最小化)
FROM gcr.io/distroless/nodejs20-debian11
# 镜像大小:~50MB,无 Shell,更安全
基础镜像大小对比:
| 镜像 | 大小 | 特点 |
|---|---|---|
ubuntu:latest | ~77MB | 完整版 |
ubuntu:22.04 | ~77MB | LTS 版 |
debian:12-slim | ~74MB | 精简版 |
alpine:3.19 | ~7MB | 超小,musl libc |
gcr.io/distroless/base | ~20MB | 无 Shell,生产推荐 |
2.2 多阶段构建(Multi-stage Build)
DOCKERFILE
# Dockerfile 多阶段构建示例
# ===== 构建阶段 =====
FROM node:20-alpine AS builder
WORKDIR /app
# 安装依赖
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
# 复制源码并构建
COPY . .
RUN pnpm build
# ===== 运行阶段 =====
FROM node:20-alpine AS runner
WORKDIR /app
# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# 只复制构建产物
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV NODE_ENV=production
CMD ["node", "server.js"]
# 构建命令:
# docker build -t myapp:latest .
# 最终镜像大小:~100MB(而不是 ~500MB)# Dockerfile 多阶段构建示例
# ===== 构建阶段 =====
FROM node:20-alpine AS builder
WORKDIR /app
# 安装依赖
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
# 复制源码并构建
COPY . .
RUN pnpm build
# ===== 运行阶段 =====
FROM node:20-alpine AS runner
WORKDIR /app
# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# 只复制构建产物
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV NODE_ENV=production
CMD ["node", "server.js"]
# 构建命令:
# docker build -t myapp:latest .
# 最终镜像大小:~100MB(而不是 ~500MB)
2.3 减少镜像层的技巧
DOCKERFILE
# ❌ 不推荐:多个 RUN 命令,每层都增加大小
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get install -y python3-pip
RUN apt-get clean
# ✅ 推荐:合并为一个 RUN 命令,清理缓存
RUN apt-get update && \
apt-get install -y --no-install-recommends \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# ✅ 推荐:使用 --no-install-recommends
RUN apt-get install -y --no-install-recommends vim
# ✅ 推荐:清理缓存
RUN pip install --no-cache-dir -r requirements.txt
# ✅ 推荐:COPY . 后立即 RUN,利用缓存
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build# ❌ 不推荐:多个 RUN 命令,每层都增加大小
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get install -y python3-pip
RUN apt-get clean
# ✅ 推荐:合并为一个 RUN 命令,清理缓存
RUN apt-get update && \
apt-get install -y --no-install-recommends \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# ✅ 推荐:使用 --no-install-recommends
RUN apt-get install -y --no-install-recommends vim
# ✅ 推荐:清理缓存
RUN pip install --no-cache-dir -r requirements.txt
# ✅ 推荐:COPY . 后立即 RUN,利用缓存
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
2.4 .dockerignore 文件
DOCKERIGNORE
# .dockerignore
# 依赖目录
node_modules
.pnpm-store
# 构建产物
dist
build
.next
.nuxt
out
# 日志
*.log
logs
# 环境变量
.env
.env.*
!.env.example
# IDE
.idea
.vscode
*.swp
# Git
.git
.gitignore
# Docker
Dockerfile*
docker-compose*
.docker
# 测试
coverage
.nyc_output
__tests__
# 文档
*.md
!README.md
docs
# 其他
.DS_Store
Thumbs.db
*.bak
*.tmp# .dockerignore
# 依赖目录
node_modules
.pnpm-store
# 构建产物
dist
build
.next
.nuxt
out
# 日志
*.log
logs
# 环境变量
.env
.env.*
!.env.example
# IDE
.idea
.vscode
*.swp
# Git
.git
.gitignore
# Docker
Dockerfile*
docker-compose*
.docker
# 测试
coverage
.nyc_output
__tests__
# 文档
*.md
!README.md
docs
# 其他
.DS_Store
Thumbs.db
*.bak
*.tmp
2.5 构建缓存优化
DOCKERFILE
# 利用 Docker 构建缓存的正确顺序
# 1. 先复制依赖文件(变化频率低)
COPY package.json pnpm-lock.yaml ./
# 2. 安装依赖(只有依赖变化才重新执行)
RUN pnpm install --frozen-lockfile
# 3. 复制源码(变化频率高,放最后)
COPY . .
# 4. 构建
RUN pnpm build
# 原理:
# Docker 会根据每层的内容计算哈希
# 如果哈希相同,就使用缓存
# 所以把变化最少的层放前面# 利用 Docker 构建缓存的正确顺序
# 1. 先复制依赖文件(变化频率低)
COPY package.json pnpm-lock.yaml ./
# 2. 安装依赖(只有依赖变化才重新执行)
RUN pnpm install --frozen-lockfile
# 3. 复制源码(变化频率高,放最后)
COPY . .
# 4. 构建
RUN pnpm build
# 原理:
# Docker 会根据每层的内容计算哈希
# 如果哈希相同,就使用缓存
# 所以把变化最少的层放前面
三、网络配置
3.1 Docker 网络模式
| 模式 | 说明 | 使用场景 |
|---|---|---|
| bridge | 默认模式,容器有独立 IP | 单机多容器 |
| host | 共享宿主机网络 | 高性能、无网络隔离 |
| none | 无网络 | 安全隔离、离线任务 |
| overlay | 跨主机网络 | Swarm 集群 |
| macvlan | 容器有独立 MAC | 网络设备仿真 |
3.2 自定义网络
BASH
# 创建自定义网络
docker network create my-network
# 创建带子网的网络
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my-network
# 创建网络时指定 IP 范围
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--ip-range 172.20.0.0/24 \
my-network
# 查看网络
docker network ls
docker network inspect my-network
# 删除网络
docker network rm my-network# 创建自定义网络
docker network create my-network
# 创建带子网的网络
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
my-network
# 创建网络时指定 IP 范围
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--ip-range 172.20.0.0/24 \
my-network
# 查看网络
docker network ls
docker network inspect my-network
# 删除网络
docker network rm my-network
3.3 容器连接到网络
BASH
# 启动容器时连接到网络
docker run -d --name app \
--network my-network \
nginx:alpine
# 指定固定 IP
docker run -d --name app \
--network my-network \
--ip 172.20.0.100 \
nginx:alpine
# 运行中的容器连接到网络
docker network connect my-network app
# 断开网络
docker network disconnect my-network app# 启动容器时连接到网络
docker run -d --name app \
--network my-network \
nginx:alpine
# 指定固定 IP
docker run -d --name app \
--network my-network \
--ip 172.20.0.100 \
nginx:alpine
# 运行中的容器连接到网络
docker network connect my-network app
# 断开网络
docker network disconnect my-network app
3.4 容器间通信
YAML
# docker-compose.yml 网络配置示例
services:
web:
image: nginx:alpine
networks:
- frontend
depends_on:
- api
api:
image: node:20-alpine
networks:
- frontend
- backend
environment:
- DB_HOST=db
db:
image: postgres:16-alpine
networks:
- backend
volumes:
- db-data:/var/lib/postgresql/data
networks:
frontend:
backend:
volumes:
db-data:# docker-compose.yml 网络配置示例
services:
web:
image: nginx:alpine
networks:
- frontend
depends_on:
- api
api:
image: node:20-alpine
networks:
- frontend
- backend
environment:
- DB_HOST=db
db:
image: postgres:16-alpine
networks:
- backend
volumes:
- db-data:/var/lib/postgresql/data
networks:
frontend:
backend:
volumes:
db-data:
3.5 端口映射详解
BASH
# 基本端口映射
docker run -d -p 80:80 nginx
# 映射到特定 IP
docker run -d -p 127.0.0.1:80:80 nginx
# 映射 UDP
docker run -d -p 53:53/udp dnsmasq
# 映射多个端口
docker run -d -p 80:80 -p 443:443 nginx
# 随机端口映射
docker run -d -P nginx # 大写 P,随机分配宿主机端口
# 查看端口映射
docker port container_name# 基本端口映射
docker run -d -p 80:80 nginx
# 映射到特定 IP
docker run -d -p 127.0.0.1:80:80 nginx
# 映射 UDP
docker run -d -p 53:53/udp dnsmasq
# 映射多个端口
docker run -d -p 80:80 -p 443:443 nginx
# 随机端口映射
docker run -d -P nginx # 大写 P,随机分配宿主机端口
# 查看端口映射
docker port container_name
四、数据卷管理
4.1 数据持久化方式
| 方式 | 说明 | 生命周期 | 使用场景 |
|---|---|---|---|
| Volume | Docker 管理的存储 | 独立于容器 | 生产推荐 |
| Bind Mount | 挂载宿主机目录 | 依赖宿主机 | 开发环境 |
| tmpfs | 内存存储 | 容器停止即消失 | 敏感数据、临时文件 |
4.2 Volume 操作
BASH
# 创建卷
docker volume create my-data
# 查看所有卷
docker volume ls
# 查看卷详情
docker volume inspect my-data
# 使用卷
docker run -d --name app \
-v my-data:/app/data \
nginx:alpine
# 匿名卷(Docker 自动命名)
docker run -d -v /app/data nginx:alpine
# 删除卷
docker volume rm my-data
# 删除所有未使用的卷
docker volume prune
# 备份卷
docker run --rm \
-v my-data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/my-data.tar.gz -C /data .
# 恢复卷
docker run --rm \
-v my-data:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/my-data.tar.gz -C /data# 创建卷
docker volume create my-data
# 查看所有卷
docker volume ls
# 查看卷详情
docker volume inspect my-data
# 使用卷
docker run -d --name app \
-v my-data:/app/data \
nginx:alpine
# 匿名卷(Docker 自动命名)
docker run -d -v /app/data nginx:alpine
# 删除卷
docker volume rm my-data
# 删除所有未使用的卷
docker volume prune
# 备份卷
docker run --rm \
-v my-data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/my-data.tar.gz -C /data .
# 恢复卷
docker run --rm \
-v my-data:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/my-data.tar.gz -C /data
4.3 Bind Mount
BASH
# 挂载宿主机目录
docker run -d --name app \
-v /path/on/host:/path/in/container \
nginx:alpine
# 只读挂载
docker run -d --name app \
-v /path/on/host:/path/in/container:ro \
nginx:alpine
# 开发环境热更新
docker run -d --name app \
-v $(pwd)/src:/app/src \
-v $(pwd)/package.json:/app/package.json \
node:20-alpine \
npm run dev
# 使用 $PWD 更方便
docker run -d -v ${PWD}:/app node:20-alpine# 挂载宿主机目录
docker run -d --name app \
-v /path/on/host:/path/in/container \
nginx:alpine
# 只读挂载
docker run -d --name app \
-v /path/on/host:/path/in/container:ro \
nginx:alpine
# 开发环境热更新
docker run -d --name app \
-v $(pwd)/src:/app/src \
-v $(pwd)/package.json:/app/package.json \
node:20-alpine \
npm run dev
# 使用 $PWD 更方便
docker run -d -v ${PWD}:/app node:20-alpine
4.4 数据卷容器
BASH
# 创建数据卷容器(只存储数据)
docker create --name db-data \
-v /var/lib/postgresql/data \
postgres:16-alpine /bin/true
# 其他容器使用数据卷容器的卷
docker run -d --name db1 \
--volumes-from db-data \
postgres:16-alpine
docker run -d --name db2 \
--volumes-from db-data \
postgres:16-alpine# 创建数据卷容器(只存储数据)
docker create --name db-data \
-v /var/lib/postgresql/data \
postgres:16-alpine /bin/true
# 其他容器使用数据卷容器的卷
docker run -d --name db1 \
--volumes-from db-data \
postgres:16-alpine
docker run -d --name db2 \
--volumes-from db-data \
postgres:16-alpine
五、资源限制与安全
5.1 资源限制
BASH
# 内存限制
docker run -d --name app \
--memory="512m" \ # 最大内存
--memory-swap="1g" \ # 内存+交换分区上限
--memory-reservation="256m" \ # 内存软限制
nginx:alpine
# CPU 限制
docker run -d --name app \
--cpus="1.5" \ # 最多使用 1.5 个 CPU
--cpu-shares=512 \ # CPU 权重(相对值)
--cpuset-cpus="0,2" \ # 只使用 CPU 0 和 2
nginx:alpine
# IO 限制(需要 --device)
docker run -d --name app \
--device-read-bps=/dev/sda:10mb \
--device-write-bps=/dev/sda:10mb \
nginx:alpine
# PIDs 限制(防止 Fork 炸弹)
docker run -d --name app \
--pids-limit 100 \
nginx:alpine# 内存限制
docker run -d --name app \
--memory="512m" \ # 最大内存
--memory-swap="1g" \ # 内存+交换分区上限
--memory-reservation="256m" \ # 内存软限制
nginx:alpine
# CPU 限制
docker run -d --name app \
--cpus="1.5" \ # 最多使用 1.5 个 CPU
--cpu-shares=512 \ # CPU 权重(相对值)
--cpuset-cpus="0,2" \ # 只使用 CPU 0 和 2
nginx:alpine
# IO 限制(需要 --device)
docker run -d --name app \
--device-read-bps=/dev/sda:10mb \
--device-write-bps=/dev/sda:10mb \
nginx:alpine
# PIDs 限制(防止 Fork 炸弹)
docker run -d --name app \
--pids-limit 100 \
nginx:alpine
5.2 Docker Compose 资源限制
YAML
services:
api:
image: node:20-alpine
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256Mservices:
api:
image: node:20-alpine
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
5.3 安全最佳实践
DOCKERFILE
# 1. 使用非 root 用户
FROM node:20-alpine
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -D appuser
USER appuser
# 2. 只复制必要文件
COPY --chown=appuser:appgroup package.json ./
COPY --chown=appuser:appgroup dist/ ./dist/
# 3. 不暴露敏感信息
# 使用环境变量或 secrets
# 4. 使用 COPY 代替 ADD(除非需要解压)
COPY app.jar /app/
# 5. 指定版本号,不使用 latest
FROM node:20.10.0-alpine# 1. 使用非 root 用户
FROM node:20-alpine
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -D appuser
USER appuser
# 2. 只复制必要文件
COPY --chown=appuser:appgroup package.json ./
COPY --chown=appuser:appgroup dist/ ./dist/
# 3. 不暴露敏感信息
# 使用环境变量或 secrets
# 4. 使用 COPY 代替 ADD(除非需要解压)
COPY app.jar /app/
# 5. 指定版本号,不使用 latest
FROM node:20.10.0-alpine
BASH
# 运行时安全选项
docker run -d --name app \
--read-only \ # 只读文件系统
--cap-drop ALL \ # 删除所有权限
--cap-add NET_BIND_SERVICE \ # 只添加必要权限
--security-opt no-new-privileges \ # 禁止提权
--pids-limit 100 \ # 限制进程数
--tmpfs /tmp:rw,size=100m,mode=1777 \ # tmpfs 挂载
nginx:alpine
# 只读容器 + tmpfs
docker run -d --name app \
--read-only \
--tmpfs /tmp \
--tmpfs /var/run \
--tmpfs /var/cache/nginx \
nginx:alpine# 运行时安全选项
docker run -d --name app \
--read-only \ # 只读文件系统
--cap-drop ALL \ # 删除所有权限
--cap-add NET_BIND_SERVICE \ # 只添加必要权限
--security-opt no-new-privileges \ # 禁止提权
--pids-limit 100 \ # 限制进程数
--tmpfs /tmp:rw,size=100m,mode=1777 \ # tmpfs 挂载
nginx:alpine
# 只读容器 + tmpfs
docker run -d --name app \
--read-only \
--tmpfs /tmp \
--tmpfs /var/run \
--tmpfs /var/cache/nginx \
nginx:alpine
5.4 Docker Content Trust(镜像签名)
BASH
# 启用镜像签名验证
export DOCKER_CONTENT_TRUST=1
# 推送签名镜像
docker push myregistry.com/myapp:1.0
# 拉取时验证签名
docker pull myregistry.com/myapp:1.0
# 管理密钥
docker trust key generate mykey
docker trust signer add --key mykey.pub me myregistry.com/myapp# 启用镜像签名验证
export DOCKER_CONTENT_TRUST=1
# 推送签名镜像
docker push myregistry.com/myapp:1.0
# 拉取时验证签名
docker pull myregistry.com/myapp:1.0
# 管理密钥
docker trust key generate mykey
docker trust signer add --key mykey.pub me myregistry.com/myapp
六、监控与日志
6.1 日志管理
BASH
# 查看容器日志
docker logs app
docker logs -f app # 实时跟踪
docker logs --tail 100 app # 最近 100 行
docker logs --since 1h app # 最近 1 小时
# 日志驱动
docker run -d --name app \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx:alpine
# syslog 日志驱动
docker run -d --name app \
--log-driver syslog \
--log-opt syslog-address=tcp://logserver:514 \
nginx:alpine
# 无日志(用于批处理)
docker run -d --name app \
--log-driver none \
nginx:alpine# 查看容器日志
docker logs app
docker logs -f app # 实时跟踪
docker logs --tail 100 app # 最近 100 行
docker logs --since 1h app # 最近 1 小时
# 日志驱动
docker run -d --name app \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx:alpine
# syslog 日志驱动
docker run -d --name app \
--log-driver syslog \
--log-opt syslog-address=tcp://logserver:514 \
nginx:alpine
# 无日志(用于批处理)
docker run -d --name app \
--log-driver none \
nginx:alpine
6.2 资源监控
BASH
# 实时监控
docker stats
# 只看一次
docker stats --no-stream
# 指定容器
docker stats app1 app2
# 查看进程
docker top app
# 查看容器资源使用
docker container ls -s # -s 显示大小# 实时监控
docker stats
# 只看一次
docker stats --no-stream
# 指定容器
docker stats app1 app2
# 查看进程
docker top app
# 查看容器资源使用
docker container ls -s # -s 显示大小
6.3 cAdvisor + Prometheus + Grafana
YAML
# docker-compose.monitoring.yml
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
restart: always
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
restart: always
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
restart: always
volumes:
grafana-data:# docker-compose.monitoring.yml
services:
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
restart: always
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
restart: always
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
restart: always
volumes:
grafana-data:
七、Docker Compose 进阶
7.1 完整配置示例
YAML
# docker-compose.yml 生产级配置
version: '3.8'
services:
# ===== 前端 =====
web:
build:
context: ./web
dockerfile: Dockerfile
args:
- NODE_ENV=production
image: myapp-web:${VERSION:-latest}
container_name: web
restart: always
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- API_URL=http://api:8000
depends_on:
api:
condition: service_healthy
networks:
- frontend
deploy:
resources:
limits:
cpus: '1'
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# ===== 后端 API =====
api:
build:
context: ./api
dockerfile: Dockerfile
image: myapp-api:${VERSION:-latest}
container_name: api
restart: always
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET}
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- frontend
- backend
volumes:
- api-uploads:/app/uploads
deploy:
resources:
limits:
cpus: '2'
memory: 1G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# ===== 数据库 =====
db:
image: postgres:16-alpine
container_name: db
restart: always
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- db-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
logging:
driver: json-file
options:
max-size: "5m"
max-file: "3"
# ===== Redis =====
redis:
image: redis:7-alpine
container_name: redis
restart: always
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不能访问外网
volumes:
db-data:
redis-data:
api-uploads:# docker-compose.yml 生产级配置
version: '3.8'
services:
# ===== 前端 =====
web:
build:
context: ./web
dockerfile: Dockerfile
args:
- NODE_ENV=production
image: myapp-web:${VERSION:-latest}
container_name: web
restart: always
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- API_URL=http://api:8000
depends_on:
api:
condition: service_healthy
networks:
- frontend
deploy:
resources:
limits:
cpus: '1'
memory: 512M
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# ===== 后端 API =====
api:
build:
context: ./api
dockerfile: Dockerfile
image: myapp-api:${VERSION:-latest}
container_name: api
restart: always
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET}
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- frontend
- backend
volumes:
- api-uploads:/app/uploads
deploy:
resources:
limits:
cpus: '2'
memory: 1G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# ===== 数据库 =====
db:
image: postgres:16-alpine
container_name: db
restart: always
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- db-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
logging:
driver: json-file
options:
max-size: "5m"
max-file: "3"
# ===== Redis =====
redis:
image: redis:7-alpine
container_name: redis
restart: always
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不能访问外网
volumes:
db-data:
redis-data:
api-uploads:
7.2 多环境配置
YAML
# docker-compose.yml(基础配置)
version: '3.8'
services:
web:
build: ./web
ports:
- "${PORT:-3000}:3000"
---
# docker-compose.override.yml(开发环境,自动加载)
version: '3.8'
services:
web:
volumes:
- ./web:/app
environment:
- NODE_ENV=development
---
# docker-compose.prod.yml(生产环境)
version: '3.8'
services:
web:
restart: always
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M# docker-compose.yml(基础配置)
version: '3.8'
services:
web:
build: ./web
ports:
- "${PORT:-3000}:3000"
---
# docker-compose.override.yml(开发环境,自动加载)
version: '3.8'
services:
web:
volumes:
- ./web:/app
environment:
- NODE_ENV=development
---
# docker-compose.prod.yml(生产环境)
version: '3.8'
services:
web:
restart: always
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M
BASH
# 开发环境(自动加载 override)
docker-compose up -d
# 生产环境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d# 开发环境(自动加载 override)
docker-compose up -d
# 生产环境
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
7.3 常用命令
BASH
# 启动
docker-compose up -d
# 构建并启动
docker-compose up -d --build
# 指定文件
docker-compose -f docker-compose.prod.yml up -d
# 查看状态
docker-compose ps
# 查看日志
docker-compose logs -f
docker-compose logs -f web
# 进入容器
docker-compose exec web sh
# 重启服务
docker-compose restart web
# 停止并删除
docker-compose down
# 停止并删除卷
docker-compose down -v
# 拉取镜像
docker-compose pull
# 查看资源使用
docker-compose top
docker-compose stats# 启动
docker-compose up -d
# 构建并启动
docker-compose up -d --build
# 指定文件
docker-compose -f docker-compose.prod.yml up -d
# 查看状态
docker-compose ps
# 查看日志
docker-compose logs -f
docker-compose logs -f web
# 进入容器
docker-compose exec web sh
# 重启服务
docker-compose restart web
# 停止并删除
docker-compose down
# 停止并删除卷
docker-compose down -v
# 拉取镜像
docker-compose pull
# 查看资源使用
docker-compose top
docker-compose stats
八、多架构构建
8.1 buildx 多架构构建
BASH
# 启用 buildx
docker buildx version
# 创建多架构构建器
docker buildx create --name mybuilder --use
# 查看构建器
docker buildx inspect --bootstrap
# 构建多架构镜像
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myregistry.com/myapp:latest \
--push \
.
# 只构建不推送
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myregistry.com/myapp:latest \
--load \
.# 启用 buildx
docker buildx version
# 创建多架构构建器
docker buildx create --name mybuilder --use
# 查看构建器
docker buildx inspect --bootstrap
# 构建多架构镜像
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myregistry.com/myapp:latest \
--push \
.
# 只构建不推送
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myregistry.com/myapp:latest \
--load \
.
8.2 Dockerfile 多架构兼容
DOCKERFILE
# 使用平台参数
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
ARG TARGETPLATFORM
ARG BUILDPLATFORM
WORKDIR /app
COPY . .
RUN echo "Building on $BUILDPLATFORM for $TARGETPLATFORM"
# 或使用条件判断
FROM node:20-alpine AS builder
ARG TARGETARCH
RUN if [ "$TARGETARCH" = "arm64" ]; then \
echo "Building for ARM64"; \
else \
echo "Building for AMD64"; \
fi# 使用平台参数
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
ARG TARGETPLATFORM
ARG BUILDPLATFORM
WORKDIR /app
COPY . .
RUN echo "Building on $BUILDPLATFORM for $TARGETPLATFORM"
# 或使用条件判断
FROM node:20-alpine AS builder
ARG TARGETARCH
RUN if [ "$TARGETARCH" = "arm64" ]; then \
echo "Building for ARM64"; \
else \
echo "Building for AMD64"; \
fi
九、镜像仓库管理
9.1 Docker Hub
BASH
# 登录
docker login
# 推送镜像
docker tag myapp:latest username/myapp:latest
docker push username/myapp:latest
# 推送带标签
docker push username/myapp:v1.0.0
# 拉取镜像
docker pull username/myapp:latest
# 搜索镜像
docker search nginx# 登录
docker login
# 推送镜像
docker tag myapp:latest username/myapp:latest
docker push username/myapp:latest
# 推送带标签
docker push username/myapp:v1.0.0
# 拉取镜像
docker pull username/myapp:latest
# 搜索镜像
docker search nginx
9.2 私有仓库
BASH
# 启动私有仓库
docker run -d -p 5000:5000 --name registry \
-v registry-data:/var/lib/registry \
registry:2
# 推送到私有仓库
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest
# 从私有仓库拉取
docker pull localhost:5000/myapp:latest
# 查看仓库中的镜像
curl -s localhost:5000/v2/_catalog | jq# 启动私有仓库
docker run -d -p 5000:5000 --name registry \
-v registry-data:/var/lib/registry \
registry:2
# 推送到私有仓库
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest
# 从私有仓库拉取
docker pull localhost:5000/myapp:latest
# 查看仓库中的镜像
curl -s localhost:5000/v2/_catalog | jq
9.3 Harbor 企业级仓库
YAML
# docker-compose.harbor.yml(简化版)
# 完整安装请参考 Harbor 官方文档
services:
harbor-core:
image: goharbor/harbor-core:v2.10.0
...
harbor-portal:
image: goharbor/harbor-portal:v2.10.0
...
registry:
image: goharbor/registry-photon:v2.10.0
...# docker-compose.harbor.yml(简化版)
# 完整安装请参考 Harbor 官方文档
services:
harbor-core:
image: goharbor/harbor-core:v2.10.0
...
harbor-portal:
image: goharbor/harbor-portal:v2.10.0
...
registry:
image: goharbor/registry-photon:v2.10.0
...
十、实用技巧与故障排查
10.1 清理空间
BASH
# 删除停止的容器
docker container prune
# 删除未使用的镜像
docker image prune -a
# 删除未使用的卷
docker volume prune
# 删除未使用的网络
docker network prune
# 一键清理所有未使用资源
docker system prune -a --volumes
# 查看空间占用
docker system df
docker system df -v# 删除停止的容器
docker container prune
# 删除未使用的镜像
docker image prune -a
# 删除未使用的卷
docker volume prune
# 删除未使用的网络
docker network prune
# 一键清理所有未使用资源
docker system prune -a --volumes
# 查看空间占用
docker system df
docker system df -v
10.2 常见问题排查
BASH
# 容器无法启动
docker logs container_name
docker inspect container_name
# 镜像拉取慢
# 配置镜像加速
# /etc/docker/daemon.json
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://docker.mirrors.ustc.edu.cn"
]
}
# 重启 Docker
sudo systemctl restart docker
# 网络问题
docker network inspect bridge
iptables -t nat -L -n
# 磁盘空间不足
docker system df
docker system prune -a
# 权限问题
sudo usermod -aG docker $USER
# 重新登录
# 查看 Docker 信息
docker info
docker version# 容器无法启动
docker logs container_name
docker inspect container_name
# 镜像拉取慢
# 配置镜像加速
# /etc/docker/daemon.json
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://docker.mirrors.ustc.edu.cn"
]
}
# 重启 Docker
sudo systemctl restart docker
# 网络问题
docker network inspect bridge
iptables -t nat -L -n
# 磁盘空间不足
docker system df
docker system prune -a
# 权限问题
sudo usermod -aG docker $USER
# 重新登录
# 查看 Docker 信息
docker info
docker version
10.3 调试技巧
BASH
# 进入运行中的容器
docker exec -it container_name sh
# 使用不同 Shell
docker exec -it container_name bash
docker exec -it container_name ash # Alpine
# 复制文件
docker cp file.txt container_name:/path/
docker cp container_name:/path/file.txt ./
# 查看容器变化
docker diff container_name
# 导出容器为镜像
docker export container_name | docker import - myapp:latest
# 保存镜像为文件
docker save -o myapp.tar myapp:latest
# 从文件加载镜像
docker load -i myapp.tar# 进入运行中的容器
docker exec -it container_name sh
# 使用不同 Shell
docker exec -it container_name bash
docker exec -it container_name ash # Alpine
# 复制文件
docker cp file.txt container_name:/path/
docker cp container_name:/path/file.txt ./
# 查看容器变化
docker diff container_name
# 导出容器为镜像
docker export container_name | docker import - myapp:latest
# 保存镜像为文件
docker save -o myapp.tar myapp:latest
# 从文件加载镜像
docker load -i myapp.tar
十一、总结
Docker 进阶技能清单
- 多阶段构建优化镜像大小
- 正确使用 .dockerignore
- 自定义网络配置
- 数据卷管理和备份
- 资源限制和安全配置
- Docker Compose 生产级配置
- 多架构镜像构建
- 日志和监控配置
- 私有仓库部署
- 故障排查和调试
学习路径
PLAINTEXT
入门(第1周):
→ Docker 基础命令
→ Dockerfile 编写
→ Docker Compose 基础
进阶(第2-3周):
→ 镜像优化
→ 网络配置
→ 数据卷管理
高级(第1-2月):
→ 多阶段构建
→ 安全配置
→ 监控日志
→ 多架构构建
专家(第3月+):
→ Kubernetes 迁移
→ Docker Swarm 集群
→ CI/CD 集成
→ 自定义网络插件入门(第1周):
→ Docker 基础命令
→ Dockerfile 编写
→ Docker Compose 基础
进阶(第2-3周):
→ 镜像优化
→ 网络配置
→ 数据卷管理
高级(第1-2月):
→ 多阶段构建
→ 安全配置
→ 监控日志
→ 多架构构建
专家(第3月+):
→ Kubernetes 迁移
→ Docker Swarm 集群
→ CI/CD 集成
→ 自定义网络插件
【相关推荐】
- Docker Compose 配置文件详解 - 容器编排
- Nginx 反向代理与负载均衡 - Web 服务器
- Linux Shell 自动化运维 - 运维脚本
Docker 是现代开发的基石。 掌握 Docker 进阶技能,你才能在微服务、云原生、DevOps 的世界里游刃有余。🚀
