什么是 Docker?
Docker 是一个开源的容器化平台,可以将应用程序及其依赖打包到一个可移植的容器中。
核心概念
概念关系流程
镜像与仓库交互
仓库
Image
Container
docker pull 从仓库拉取镜像 → docker run 从镜像启动容器 → docker push 推送镜像到仓库
概念详解
镜像 (Image)
只读模板,包含运行应用所需的代码、运行时、库和配置。
docker pull nginx:alpine
容器 (Container)
镜像的运行实例,独立、隔离的执行环境。
docker run -d -p 80:80 nginx
仓库 (Registry)
存储和分发镜像的服务,如 Docker Hub。
docker push user/image:tag
镜像分层结构
每层只读,容器运行时添加可写层(Copy-on-Write)
Docker 架构图
docker run 请求流程
docker run -d nginx:alpine组件交互关系
Daemon
客户端
仓库
镜像
容器
网络
数据卷
架构说明
| 组件 | 说明 |
|---|---|
| Docker Client | 用户与 Docker 交互的界面,如 docker CLI 命令 |
| Docker Daemon | 后台服务,处理客户端请求,管理镜像和容器 |
| containerd | 容器运行时,管理容器生命周期 |
| runc | OCI 兼容的容器运行时,实际创建容器 |
安装 Docker
macOS
# Homebrew 安装
brew install --cask docker
# 或下载 Docker Desktop
# https://www.docker.com/products/docker-desktop
Windows
# 使用 winget
winget install Docker.DockerDesktop
# 或使用 Chocolatey
choco install docker-desktop
Linux (Ubuntu)
# 官方脚本安装
curl -fsSL https://get.docker.com | sh
# 添加用户到 docker 组
sudo usermod -aG docker $USER
验证安装
docker --version
docker run hello-world
Dockerfile
Dockerfile 是定义镜像构建过程的文本文件,包含一系列指令用于构建 Docker 镜像。
基础示例
# Node.js 应用
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
多阶段构建
多阶段构建可以显著减小最终镜像大小,分离构建环境和运行环境。
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build
# 生产阶段
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
完整指令列表
| 指令 | 说明 | 示例 |
|---|---|---|
FROM |
指定基础镜像(必须为第一条指令) | FROM node:20-alpine |
WORKDIR |
设置工作目录 | WORKDIR /app |
COPY |
复制文件到镜像 | COPY . . |
ADD |
复制文件(支持 URL 和解压) | ADD app.tar.gz /app |
RUN |
执行命令并提交结果 | RUN npm install |
CMD |
容器启动时执行的默认命令 | CMD ["node", "app.js"] |
ENTRYPOINT |
配置容器为可执行程序 | ENTRYPOINT ["node"] |
ENV |
设置环境变量 | ENV NODE_ENV=production |
ARG |
构建时的变量 | ARG VERSION=1.0 |
EXPOSE |
声明端口 | EXPOSE 3000 |
VOLUME |
创建挂载点 | VOLUME /data |
USER |
指定运行用户 | USER node |
HEALTHCHECK |
健康检查 | HEALTHCHECK CMD curl -f http://localhost/ |
LABEL |
添加元数据 | LABEL version="1.0" |
CMD vs ENTRYPOINT
| 特性 | CMD | ENTRYPOINT |
|---|---|---|
| 目的 | 设置默认命令和参数 | 配置容器为可执行程序 |
| 覆盖方式 | docker run 时可直接替换 | 需要 --entrypoint 参数 |
| 组合使用 | 作为 ENTRYPOINT 的默认参数 | 定义主命令 |
# 组合使用示例
ENTRYPOINT ["node"]
CMD ["app.js"]
# docker run myapp → node app.js
# docker run myapp server.js → node server.js
常犯错误
❌ 错误:使用 latest 标签
FROM node:latest # 不推荐
✅ 正确:指定版本
FROM node:20-alpine # 推荐
latest 标签会变化,导致构建不可重复
❌ 错误:忽略缓存顺序
COPY . .
RUN npm install # 任何文件变化都会重新执行
✅ 正确:利用缓存
COPY package*.json ./
RUN npm install
COPY . . # 只在代码变化时才重新复制
❌ 错误:以 root 运行
FROM node:20-alpine
# 默认 root 用户
CMD ["node", "app.js"]
✅ 正确:非 root 用户
FROM node:20-alpine
RUN addgroup -g 1001 app && \
adduser -u 1001 -G app user
USER user
CMD ["node", "app.js"]
❌ 错误:镜像过大
FROM node:20 # Debian 基础镜像 ~900MB
RUN npm install
✅ 正确:使用 Alpine
FROM node:20-alpine # Alpine ~170MB
RUN npm install
❌ 错误:多层 RUN 指令
RUN apk add --no-cache git
RUN apk add --no-cache curl
RUN apk add --no-cache vim
✅ 正确:合并命令
RUN apk add --no-cache \
git curl vim
❌ 错误:复制无用文件
COPY . . # 复制所有文件
✅ 正确:使用 .dockerignore
# .dockerignore
node_modules
.git
*.md
.env
最佳实践清单
# 1. 使用特定版本的基础镜像
FROM node:20-alpine3.19
# 2. 设置工作目录
WORKDIR /app
# 3. 先复制依赖文件,利用缓存
COPY package*.json ./
RUN npm ci --only=production
# 4. 再复制源代码
COPY . .
# 5. 创建非 root 用户
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
# 6. 设置环境变量
ENV NODE_ENV=production
# 7. 声明端口
EXPOSE 3000
# 8. 切换用户
USER appuser
# 9. 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -q --spider http://localhost:3000/health || exit 1
# 10. 设置启动命令
CMD ["node", "server.js"]
构建镜像
# 构建镜像
docker build -t myapp:v1 .
# 使用 BuildKit(推荐)
DOCKER_BUILDKIT=1 docker build -t myapp:v1 .
# 多平台构建
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:v1 .
Docker Compose
Docker Compose 是定义和运行多容器应用的工具,使用 YAML 文件配置服务、网络和数据卷。
服务架构示意
网关
前端
后端
数据库
缓存
服务启动顺序
配置文件结构
基本结构
# docker-compose.yml 基本结构
version: "3.8" # 可选,新版本已不需要
services: # 定义服务
webapp:
# 服务配置...
networks: # 定义网络(可选)
frontend:
volumes: # 定义数据卷(可选)
db-data:
configs: # 定义配置(可选)
my-config:
secrets: # 定义机密(可选)
db-password:
完整示例
services:
web:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_ENV=production
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/myapp
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- frontend
- backend
volumes:
- ./logs:/app/logs
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: '1'
memory: 512M
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- backend
restart: unless-stopped
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,外部无法访问
volumes:
db-data:
redis-data:
常用命令
# 服务管理
docker compose up -d # 后台启动所有服务
docker compose up -d --build # 重建镜像后启动
docker compose up -d web db # 只启动指定服务
docker compose down # 停止并删除容器、网络
docker compose down -v # 同时删除数据卷
docker compose down --rmi all # 同时删除镜像
# 查看状态
docker compose ps # 查看服务状态
docker compose logs # 查看所有日志
docker compose logs -f web # 实时查看 web 服务日志
docker compose top # 查看进程
# 服务操作
docker compose start web # 启动服务
docker compose stop web # 停止服务
docker compose restart web # 重启服务
docker compose pause web # 暂停服务
docker compose unpause web # 恢复服务
# 执行命令
docker compose exec web sh # 进入容器
docker compose exec db psql -U user myapp # 在 db 容器执行命令
docker compose run --rm web npm test # 一次性运行命令
# 其他
docker compose config # 验证配置文件
docker compose config --services # 列出所有服务
docker compose pull # 拉取所有镜像
docker compose push # 推送所有镜像
常用场景
场景 1:开发环境
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app # 挂载代码目录,支持热重载
- /app/node_modules # 防止本地 node_modules 覆盖
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true # 支持文件监听
command: npm run dev
db:
image: postgres:16-alpine
ports:
- "5432:5432" # 暴露端口便于本地连接
environment:
POSTGRES_DB: dev
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
volumes:
- dev-data:/var/lib/postgresql/data
volumes:
dev-data:
场景 2:微服务架构
services:
gateway:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- api
- web
networks:
- frontend
api:
build: ./api
environment:
- DATABASE_URL=postgres://db:5432/myapp
depends_on:
- db
- redis
networks:
- frontend
- backend
web:
build: ./web
networks:
- frontend
db:
image: postgres:16-alpine
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
redis:
image: redis:7-alpine
networks:
- backend
networks:
frontend:
backend:
internal: true # 只有内部服务可访问
场景 3:CI/CD 测试
services:
app:
build: .
depends_on:
db:
condition: service_healthy
environment:
- DATABASE_URL=postgres://test:test@db:5432/test
command: npm test
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
healthcheck:
test: ["CMD-SHELL", "pg_isready -U test"]
interval: 5s
timeout: 5s
retries: 10
tmpfs:
- /var/lib/postgresql/data # 使用内存存储,测试更快
场景 4:多环境配置
# docker-compose.yml(基础配置)
services:
web:
image: myapp
ports:
- "3000:3000"
# docker-compose.override.yml(开发环境,自动加载)
services:
web:
build: .
volumes:
- .:/app
environment:
- DEBUG=true
# docker-compose.prod.yml(生产环境)
services:
web:
image: myapp:latest
restart: always
deploy:
replicas: 3
# 使用方式:
# 开发环境: docker compose up
# 生产环境: docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
常见错误
❌ 错误:端口冲突
ports:
- "80:80" # 本地 80 端口已被占用
✅ 解决方案
ports:
- "8080:80" # 使用其他本地端口
❌ 错误:服务启动顺序
depends_on:
- db # 只等待容器启动,不等待服务就绪
✅ 解决方案
depends_on:
db:
condition: service_healthy # 等待健康检查通过
❌ 错误:数据丢失
docker compose down # 默认不删除卷
✅ 注意事项
# 删除所有数据(危险操作)
docker compose down -v
# 生产环境建议定期备份
docker compose exec db pg_dump ...
❌ 错误:环境变量未传递
environment:
- DB_PASS=$DB_PASSWORD # 变量未定义时为空
✅ 解决方案
# 使用 .env 文件
# .env
DB_PASSWORD=secret
# 或设置默认值
environment:
- DB_PASS=${DB_PASSWORD:-default}
❌ 错误:版本兼容问题
version: "2" # 旧版格式
✅ 解决方案
version: "3.8" # 使用最新格式
# 或直接省略 version(新版本推荐)
❌ 错误:网络隔离问题
# 服务 A 无法访问服务 B
✅ 解决方案
# 确保服务在同一网络
services:
a:
networks:
- mynet
b:
networks:
- mynet
networks:
mynet:
配置文件最佳实践
# 1. 使用 .env 文件管理环境变量
# .env
COMPOSE_PROJECT_NAME=myapp
POSTGRES_PASSWORD=secret
API_KEY=xxx
# 2. 使用命名卷而非绑定挂载(生产环境)
volumes:
db-data: # 命名卷
# 3. 限制资源
deploy:
resources:
limits:
cpus: '0.5'
memory: 256M
# 4. 设置重启策略
restart: unless-stopped
# 5. 使用健康检查
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
# 6. 使用网络隔离
networks:
frontend:
backend:
internal: true
# 7. 使用 secrets 管理敏感数据
secrets:
db_password:
file: ./secrets/db_password.txt
服务配置指令详解
| 指令 | 说明 | 示例 |
|---|---|---|
image |
指定镜像名称 | image: nginx:alpine |
build |
构建配置 | build: ./dir 或详细配置 |
ports |
端口映射 | ["3000:3000", "80:80"] |
expose |
暴露端口(仅内部) | ["3000"] |
environment |
环境变量 | KEY=value 或 ["KEY=value"] |
env_file |
从文件加载环境变量 | env_file: .env |
volumes |
挂载卷 | ["./data:/app/data"] |
networks |
连接的网络 | ["frontend", "backend"] |
depends_on |
服务依赖 | ["db", "redis"] |
restart |
重启策略 | always / unless-stopped / on-failure |
command |
覆盖默认命令 | ["node", "server.js"] |
entrypoint |
覆盖入口点 | ["/app/entrypoint.sh"] |
working_dir |
工作目录 | /app |
user |
运行用户 | node 或 1000:1000 |
healthcheck |
健康检查 | test, interval, timeout, retries |
deploy |
部署配置(Swarm) | replicas, resources, update_config |
profiles |
服务配置文件 | ["debug", "test"] |
extra_hosts |
添加主机名映射 | "myhost:192.168.1.1" |
dns |
自定义 DNS | ["8.8.8.8", "8.8.4.4"] |
labels |
添加元数据标签 | "com.example.description=Web app" |
变量替换
# .env 文件
DB_HOST=db
DB_PORT=5432
DB_NAME=myapp
DB_USER=${DB_USER:-admin} # 默认值
DB_PASS=${DB_PASS:?密码未设置} # 必须设置,否则报错
# docker-compose.yml
services:
app:
environment:
- DATABASE_URL=postgres://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}
ports:
- "${APP_PORT:-3000}:3000" # 使用默认值
# 使用方式
DB_PASS=secret docker compose up -d
# 或
cp .env.example .env && docker compose up -d
Profiles 功能
Profiles 允许按需启动不同服务组合:
services:
web:
image: nginx
ports:
- "80:80"
# 只在 debug profile 启用
debug:
image: busybox
command: tail -f /dev/null
profiles:
- debug
# 只在 test profile 启用
selenium:
image: selenium/standalone-chrome
profiles:
- test
# 多个 profile
adminer:
image: adminer
profiles:
- debug
- admin
# 使用方式
docker compose up -d # 只启动 web
docker compose --profile debug up -d # 启动 web + debug + adminer
docker compose --profile test up -d # 启动 web + selenium
docker compose --profile debug --profile test up -d # 启动全部
更多应用场景
场景 5:负载均衡
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- web
web:
image: myapp:latest
deploy:
replicas: 3 # 运行 3 个副本
environment:
- NODE_ENV=production
networks:
- app-network
networks:
app-network:
场景 6:日志收集
services:
app:
image: myapp
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
depends_on:
- elasticsearch
- logstash
elasticsearch:
image: elasticsearch:8-alpine
environment:
- discovery.type=single-node
volumes:
- es-data:/usr/share/elasticsearch/data
logstash:
image: logstash:8-alpine
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
kibana:
image: kibana:8-alpine
ports:
- "5601:5601"
depends_on:
- elasticsearch
volumes:
es-data:
场景 7:消息队列
services:
producer:
build: ./producer
environment:
- RABBITMQ_HOST=rabbitmq
depends_on:
rabbitmq:
condition: service_healthy
consumer:
build: ./consumer
environment:
- RABBITMQ_HOST=rabbitmq
depends_on:
rabbitmq:
condition: service_healthy
deploy:
replicas: 3 # 多个消费者
rabbitmq:
image: rabbitmq:3-management-alpine
ports:
- "5672:5672" # AMQP
- "15672:15672" # 管理界面
healthcheck:
test: ["CMD", "rabbitmqctl", "status"]
interval: 10s
timeout: 10s
retries: 5
volumes:
- rabbit-data:/var/lib/rabbitmq
volumes:
rabbit-data:
场景 8:数据库主从复制
services:
pg-master:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_REPLICATION_USER: replicator
POSTGRES_REPLICATION_PASSWORD: repl_pass
volumes:
- master-data:/var/lib/postgresql/data
command: >
postgres
-c wal_level=replica
-c max_wal_senders=3
-c max_replication_slots=3
pg-replica:
image: postgres:16-alpine
environment:
PGUSER: replicator
PGPASSWORD: repl_pass
PGHOST: pg-master
depends_on:
- pg-master
volumes:
- replica-data:/var/lib/postgresql/data
volumes:
master-data:
replica-data:
扩展和继承
# 使用 extends 继承配置(已弃用,推荐使用 YAML 锚点)
# docker-compose.yml
x-common-config: &common-config
restart: unless-stopped
networks:
- app-network
logging:
driver: json-file
options:
max-size: "10m"
services:
api:
<<: *common-config
image: myapp:api
ports:
- "3000:3000"
worker:
<<: *common-config
image: myapp:worker
command: node worker.js
networks:
app-network:
常用命令
镜像管理
docker images # 列出镜像
docker pull nginx:alpine # 拉取镜像
docker rmi nginx:alpine # 删除镜像
docker tag myapp:v1 myapp:latest # 标记镜像
docker save -o app.tar myapp:v1 # 导出镜像
docker load -i app.tar # 导入镜像
容器管理
docker ps # 列出运行中容器
docker ps -a # 列出所有容器
docker run -d -p 80:80 nginx # 后台运行容器
docker stop container_id # 停止容器
docker rm container_id # 删除容器
docker exec -it container_id sh # 进入容器
docker logs -f container_id # 查看日志
docker cp file.txt container:/app # 复制文件到容器
系统管理
docker system df # 查看磁盘使用
docker system prune # 清理未使用资源
docker system prune -a # 清理所有未使用资源
docker stats # 实时资源使用
网络
Docker 提供多种网络模式,满足不同应用场景:
网络类型
| 类型 | 说明 | 应用场景 |
|---|---|---|
| bridge | 默认网络,容器间可通过 IP 通信 | 单机多容器应用 |
| host | 容器共享主机网络,无网络隔离 | 高性能网络应用、监控 |
| none | 禁用网络 | 安全隔离、离线任务 |
| overlay | 跨主机网络(需 Swarm) | 分布式集群应用 |
| macvlan | 容器拥有独立 MAC 地址 | 需要物理网络直接访问 |
网络架构示意图
172.17.0.2
172.17.0.3
172.17.0.4
常用命令
# 查看网络列表
docker network ls
# 创建自定义网络
docker network create mynet
# 创建指定类型的网络
docker network create -d bridge mynet
docker network create -d host myhost
# 查看网络详情
docker network inspect mynet
# 连接容器到网络
docker network connect mynet container_name
# 断开容器网络
docker network disconnect mynet container_name
# 删除网络
docker network rm mynet
应用场景示例
场景 1:微服务通信
# 创建应用网络
docker network create app-network
# 启动服务,同一网络内可通过服务名访问
docker run -d --name api --network app-network myapi
docker run -d --name web --network app-network nginx
# web 容器可通过 http://api:8080 访问 API
场景 2:隔离不同环境
# 开发环境网络
docker network create dev-network
# 测试环境网络
docker network create test-network
# 开发和测试环境完全隔离
docker run -d --name dev-db --network dev-network postgres
docker run -d --name test-db --network test-network postgres
场景 3:DNS 解析
# 同一网络内的容器自动获得 DNS 解析
docker run -d --name redis --network mynet redis
docker run -d --name app --network mynet myapp
# app 容器内可直接使用主机名连接
# redis://redis:6379
容器与外界通讯过程
理解容器如何与外界通讯是掌握 Docker 网络的关键。
通讯架构图
┌─────────────────────────────────────────────────────────────────┐
│ 外部网络(互联网) │
└─────────────────────────────────────────────────────────────────┘
↑↓
┌─────────────────────────────────────────────────────────────────┐
│ 宿主机 (Host) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Docker 网桥 (docker0) │ │
│ │ 172.17.0.1 (网关) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ ↑ ↑ ↑ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ 容器 A │ │ 容器 B │ │ 容器 C │ │
│ │172.17.0.2│ │172.17.0.3│ │172.17.0.4│ │
│ │ 端口 80 │ │ 端口 3000│ │ 端口 5432│ │
│ └────────┘ └────────┘ └────────┘ │
│ ↑ ↑ ↑ │
│ 主机端口 主机端口 主机端口 │
│ 8080→80 3000→3000 5432→5432 │
└─────────────────────────────────────────────────────────────────┘
1. 容器访问外部网络
# 容器访问互联网的过程:
# 1. 容器发送请求(源 IP: 172.17.0.2)
# 2. 请求经过 docker0 网桥
# 3. 通过 NAT(网络地址转换)转换为宿主机 IP
# 4. 请求发送到外部网络
# 5. 响应按原路返回
# 示例:容器内访问外部 API
docker run --rm alpine wget -qO- https://api.github.com
# 查看容器的网络配置
docker run --rm alpine ip addr show
# eth0: 172.17.0.x → docker0 网桥
# 查看宿主机的 iptables NAT 规则
sudo iptables -t nat -L -n
2. 外部访问容器(端口映射)
# 端口映射原理:
# 外部请求 → 宿主机端口 → iptables 转发 → 容器端口
# 映射单个端口
docker run -d -p 8080:80 nginx
# 宿主机 8080 → 容器 80
# 映射多个端口
docker run -d -p 8080:80 -p 8443:443 nginx
# 指定 IP 绑定
docker run -d -p 127.0.0.1:8080:80 nginx
# 只允许本地访问
# 映射 UDP 端口
docker run -d -p 53:53/udp dns-server
# 查看端口映射
docker port container_name
docker ps --format "table {{.Names}}\t{{.Ports}}"
# 验证端口监听
netstat -tlnp | grep 8080
# 或
lsof -i :8080
3. 容器间通讯
# 同一 bridge 网络内的容器通讯:
# 方式 1:通过 IP 地址
# 容器 A (172.17.0.2) → 容器 B (172.17.0.3)
curl http://172.17.0.3:3000
# 方式 2:通过容器名称(需要自定义网络)
docker network create mynet
docker run -d --name db --network mynet postgres
docker run -d --name app --network mynet myapp
# app 容器可以通过名称访问 db
# postgresql://db:5432/mydb
# 查看网络内容器的 IP
docker network inspect mynet
# 进入容器测试连通性
docker exec -it app ping db
docker exec -it app curl http://db:5432
4. 不同网络模式对比
| 网络模式 | 容器 IP | 访问外部 | 外部访问容器 | 容器间通讯 |
|---|---|---|---|---|
| bridge | 独立 IP(如 172.17.0.x) | ✅ 通过 NAT | ✅ 需要端口映射 | ✅ 通过 IP 或名称 |
| host | 共享宿主机 IP | ✅ 直接访问 | ✅ 直接访问容器端口 | ✅ 通过 localhost |
| none | 无 | ❌ 无法访问 | ❌ 无法访问 | ❌ 无法通讯 |
| macvlan | 物理网络 IP | ✅ 直接访问 | ✅ 直接访问 | ✅ 通过物理网络 |
5. 网络通讯完整示例
# 场景:Web 应用 + 数据库 + Redis
# 1. 创建网络
docker network create app-network
# 2. 启动数据库(内部端口,不映射到外部)
docker run -d \
--name db \
--network app-network \
-e POSTGRES_PASSWORD=secret \
postgres:16-alpine
# 数据库只能在网络内部访问,外部无法直接连接
# 3. 启动 Redis(内部端口)
docker run -d \
--name redis \
--network app-network \
redis:7-alpine
# 4. 启动 Web 应用(映射端口到外部)
docker run -d \
--name web \
--network app-network \
-p 3000:3000 \
-e DATABASE_URL=postgres://postgres:secret@db:5432 \
-e REDIS_URL=redis://redis:6379 \
myapp
# 通讯路径:
# 外部用户 → 宿主机:3000 → web 容器:3000
# web 容器 → db:5432(内部 DNS 解析)
# web 容器 → redis:6379(内部 DNS 解析)
# 验证通讯
docker exec -it web ping db # Web → DB
docker exec -it web ping redis # Web → Redis
curl http://localhost:3000 # 外部 → Web
6. 常见网络问题排查
# 问题 1:容器无法访问外部网络
# 检查 DNS
docker run --rm alpine nslookup google.com
docker run --rm alpine ping -c 3 8.8.8.8
# 问题 2:外部无法访问容器端口
# 检查端口映射
docker port container_name
# 检查防火墙
sudo ufw status
sudo iptables -L -n | grep 8080
# 问题 3:容器间无法通讯
# 确认在同一网络
docker network inspect mynet
# 检查容器网络配置
docker exec container_name ip addr show
# 问题 4:DNS 解析失败
# 使用自定义 DNS
docker run --dns 8.8.8.8 myapp
# 问题 5:端口冲突
# 查看端口占用
lsof -i :8080
netstat -tlnp | grep 8080
数据卷
数据卷用于持久化容器数据,独立于容器生命周期。
存储架构关系
Container
Docker管理
主机目录
内存存储
存储类型对比
| 类型 | 说明 | 应用场景 |
|---|---|---|
| Volume | Docker 管理的存储,存储在 /var/lib/docker/volumes | 数据库、持久化数据、多容器共享 |
| Bind Mount | 绑定主机目录到容器 | 开发环境、配置文件挂载 |
| tmpfs | 存储在内存中,容器停止即消失 | 敏感数据、临时缓存 |
数据流向示意
/app/data
mydata
/volumes/mydata
常用命令
# 创建数据卷
docker volume create mydata
# 列出所有数据卷
docker volume ls
# 查看数据卷详情
docker volume inspect mydata
# 删除数据卷
docker volume rm mydata
# 清理未使用的数据卷
docker volume prune
应用场景示例
场景 1:数据库持久化
# PostgreSQL 数据持久化
docker run -d \
--name postgres \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:16-alpine
# 即使容器删除,数据仍然保留
docker rm -f postgres
docker run -d \
--name postgres \
-v pgdata:/var/lib/postgresql/data \
postgres:16-alpine
# 数据恢复
场景 2:开发环境热重载
# 挂载本地代码目录,修改立即生效
docker run -d \
--name dev-app \
-v $(pwd)/src:/app/src \
-v $(pwd)/package.json:/app/package.json \
-p 3000:3000 \
node:20-alpine \
npm run dev
# 本地修改代码,容器内自动更新
场景 3:配置文件管理
# 挂载配置文件
docker run -d \
--name nginx \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
-v $(pwd)/html:/usr/share/nginx/html:ro \
-p 80:80 \
nginx:alpine
# :ro 表示只读挂载,防止容器修改配置
场景 4:多容器共享数据
# 创建共享数据卷
docker volume create shared-data
# 写入容器
docker run -d --name writer \
-v shared-data:/data \
alpine sh -c "echo 'hello' > /data/file.txt"
# 读取容器
docker run --name reader \
-v shared-data:/data \
alpine cat /data/file.txt
# 输出: hello
场景 5:敏感数据(tmpfs)
# 使用内存存储敏感数据
docker run -d \
--name app \
--tmpfs /run/secrets:rw,size=10m,mode=1777 \
myapp
# 数据不会写入磁盘,容器停止即消失
容器与文件系统交互原理
理解容器如何与文件系统交互,有助于更好地管理数据。
存储架构图
容器存储系统由多个层次组成,从下到上分别是:
挂载点示例: /app/data → 宿主机目录,/app/src → 代码目录
1. 镜像分层与联合文件系统
# Docker 使用联合文件系统(UnionFS)将多个层合并为一个文件系统
# 查看镜像层
docker image inspect nginx:alpine --format='{{json .RootFS.Layers}}'
# 镜像层特点:
# - 只读:镜像层不可修改
# - 分层存储:相同基础镜像的层共享
# - 按需加载:只加载需要的层
# 容器层特点:
# - 可写:容器运行时的所有修改都在这里
# - 写时复制(Copy-on-Write):
# 修改镜像中的文件时,先复制到容器层再修改
# - 容器删除后,容器层消失
# 示例:查看容器的存储驱动
docker info | grep "Storage Driver"
# 通常为 overlay2
2. 写时复制(Copy-on-Write)机制
# 场景:修改镜像中的文件
# 1. 容器启动时,文件在镜像层(只读)
# /etc/nginx/nginx.conf → 镜像层
# 2. 容器修改文件时:
# - Docker 将文件从镜像层复制到容器层
# - 容器层现在有一个可写副本
# - 镜像层的原文件保持不变
# 3. 后续读取时:
# - 优先读取容器层的文件
# - 容器层没有才读取镜像层
# 验证写时复制
docker run --name test nginx:alpine
docker exec test sh -c "ls -la /etc/nginx/nginx.conf"
# 此时文件在镜像层
docker exec test sh -c "echo 'modified' >> /etc/nginx/nginx.conf"
# 触发写时复制,文件被复制到容器层
# 查看容器层的修改
docker diff test
# C /etc/nginx (C = Changed)
# C /etc/nginx/nginx.conf
3. 三种存储类型的交互方式
# ===== 1. Volume(命名卷)=====
# Docker 管理的存储,与容器完全解耦
# 创建与挂载过程:
# 1. docker volume create mydata
# → 在 /var/lib/docker/volumes/mydata/_data 创建目录
# 2. docker run -v mydata:/app/data myapp
# → 将 /var/lib/docker/volumes/mydata/_data 挂载到容器 /app/data
# 3. 容器写入 /app/data/file.txt
# → 文件实际写入 /var/lib/docker/volumes/mydata/_data/file.txt
# 验证
docker volume create test-vol
docker run --rm -v test-vol:/data alpine sh -c "echo 'hello' > /data/test.txt"
sudo ls -la /var/lib/docker/volumes/test-vol/_data/
# 可以看到 test.txt 文件
# ===== 2. Bind Mount(绑定挂载)=====
# 直接映射主机目录到容器
# 挂载过程:
# docker run -v /host/path:/container/path myapp
# → 将主机 /host/path 直接映射到容器 /container/path
# 特点:
# - 双向同步:主机修改 → 容器可见,容器修改 → 主机可见
# - 性能最好(无额外抽象层)
# - 路径依赖主机
# 验证
mkdir -p /tmp/bind-test
echo "from host" > /tmp/bind-test/host.txt
docker run --rm -v /tmp/bind-test:/data alpine cat /data/host.txt
# 输出: from host
docker run --rm -v /tmp/bind-test:/data alpine sh -c "echo 'from container' > /data/container.txt"
cat /tmp/bind-test/container.txt
# 输出: from container
# ===== 3. tmpfs(内存存储)=====
# 数据存储在内存中
# 挂载过程:
# docker run --tmpfs /data myapp
# → 在内存中创建临时文件系统,挂载到容器 /data
# 特点:
# - 最快的存储方式(内存速度)
# - 容器停止后数据消失
# - 不会写入磁盘
# 验证
docker run --rm --tmpfs /data alpine sh -c "mount | grep /data"
# 输出: tmpfs on /data type tmpfs ...
4. 挂载行为详解
# 挂载时容器目录的行为:
# 情况 1:挂载到空目录
docker run -v mydata:/app/data nginx
# 容器 /app/data 为空 → 挂载后显示卷内容(可能为空)
# 情况 2:挂载到有内容的目录
docker run -v mydata:/usr/share/nginx/html nginx
# 容器 /usr/share/nginx/html 有默认文件
# 挂载后:容器原内容被隐藏,显示卷内容
# 注意:如果卷为空,目录变空!
# 情况 3:绑定挂载覆盖
docker run -v /host/html:/usr/share/nginx/html nginx
# 主机目录内容覆盖容器目录内容
# 安全做法:先检查卷内容
docker run --rm -v mydata:/data alpine ls -la /data/
# 使用只读挂载防止意外修改
docker run -v mydata:/app/data:ro nginx
# 容器无法写入 /app/data
5. 数据流向示例
# 完整示例:Web 应用数据流向
# 启动一个完整的 Web 应用栈
docker run -d \
--name web \
-v web-code:/var/www/html \ # 网站代码(命名卷)
-v /host/config:/etc/nginx:ro \ # 配置文件(绑定挂载,只读)
-v web-logs:/var/log/nginx \ # 日志(命名卷)
--tmpfs /var/cache/nginx \ # 缓存(内存)
-p 80:80 \
nginx:alpine
# 数据流向分析:
# 1. 用户访问 → Nginx 读取 /var/www/html/index.html
# → 实际读取 /var/lib/docker/volumes/web-code/_data/index.html
# 2. Nginx 启动时读取配置 /etc/nginx/nginx.conf
# → 实际读取 /host/config/nginx.conf(主机文件)
# 3. Nginx 写入日志 /var/log/nginx/access.log
# → 实际写入 /var/lib/docker/volumes/web-logs/_data/access.log
# 4. Nginx 写入缓存 /var/cache/nginx/...
# → 写入内存,容器停止后消失
# 验证各存储位置
sudo ls -la /var/lib/docker/volumes/web-code/_data/
sudo ls -la /var/lib/docker/volumes/web-logs/_data/
ls -la /host/config/
6. 文件系统问题排查
# 问题 1:磁盘空间不足
docker system df # 查看磁盘使用
docker volume ls # 列出所有卷
docker volume prune # 清理未使用的卷
# 问题 2:权限问题
# 容器内用户 ID 与主机不匹配
docker run -v /host/data:/data myapp
# 解决方案:使用相同的用户 ID
docker run -u 1000:1000 -v /host/data:/data myapp
# 问题 3:找不到挂载的文件
# 检查挂载点
docker inspect container_name --format='{{json .Mounts}}'
# 或
docker inspect container_name | grep -A 10 "Mounts"
# 问题 4:绑定挂载不生效
# 检查路径是否存在
ls -la /host/path
# 检查权限
ls -la /host/path
# 检查 Docker Desktop 设置(macOS/Windows 需要共享目录)
# 问题 5:容器内文件被覆盖
# 了解挂载行为:挂载会覆盖容器内原有内容
# 解决:先备份数据,或使用命名卷的初始化功能
# 查看容器的存储使用
docker ps -s # 显示容器大小
# SIZE:容器可写层大小
# VIRTUAL SIZE:镜像 + 容器层总大小
7. 存储类型选择指南
| 需求 | 推荐类型 | 原因 |
|---|---|---|
| 数据库持久化 | Volume | Docker 管理,易于备份迁移 |
| 开发时代码同步 | Bind Mount | 实时同步,IDE 直接编辑 |
| 配置文件 | Bind Mount (:ro) | 版本控制,只读防误改 |
| 敏感数据 | tmpfs | 内存存储,不留痕迹 |
| 多容器共享 | Volume | 独立于容器,可共享 |
| 临时缓存 | tmpfs | 高速访问,自动清理 |
企业内部 Registry
Docker Registry 是存储和分发 Docker 镜像的服务,企业可自建私有 Registry 来管理内部镜像。
为什么需要私有 Registry?
- 安全合规:敏感镜像不上传公网,数据完全自主可控
- 访问速度:内网拉取镜像更快,不占用公网带宽
- 成本控制:避免 Docker Hub 拉取次数限制和付费
- 版本管理:统一管理内部应用的镜像版本
快速搭建 Registry
# 1. 最简单的启动方式
docker run -d \
--name registry \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
--restart always \
registry:2
# 2. 使用 Docker Compose(推荐)
# docker-compose.yml
services:
registry:
image: registry:2
ports:
- "5000:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
volumes:
- registry-data:/var/lib/registry
restart: always
volumes:
registry-data:
推送和拉取镜像
# 1. 标记镜像指向私有仓库
docker tag myapp:v1 localhost:5000/myapp:v1
# 2. 推送镜像
docker push localhost:5000/myapp:v1
# 3. 拉取镜像
docker pull localhost:5000/myapp:v1
# 4. 查看仓库中的镜像
curl http://localhost:5000/v2/_catalog
curl http://localhost:5000/v2/myapp/tags/list
配置 HTTPS(生产必需)
# 方案 1:使用 Nginx 反向代理 + Let's Encrypt
# docker-compose.yml
services:
registry:
image: registry:2
volumes:
- registry-data:/var/lib/registry
restart: always
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- registry
volumes:
registry-data:
# nginx.conf 示例
# server {
# listen 443 ssl;
# server_name registry.example.com;
# ssl_certificate /etc/nginx/certs/fullchain.pem;
# ssl_certificate_key /etc/nginx/certs/privkey.pem;
# client_max_body_size 0; # 不限制上传大小
# location / {
# proxy_pass http://registry:5000;
# }
# }
配置认证
# 1. 创建用户密码文件
docker run --rm \
--entrypoint htpasswd \
httpd:2 -Bbn admin password123 > htpasswd
# 2. 启动带认证的 Registry
docker run -d \
--name registry \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
-v $(pwd)/htpasswd:/etc/docker/registry/htpasswd \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/etc/docker/registry/htpasswd \
registry:2
# 3. 登录私有仓库
docker login localhost:5000
# 输入用户名和密码
# 4. 推送镜像(需要先登录)
docker push localhost:5000/myapp:v1
# 5. 退出登录
docker logout localhost:5000
完整生产配置
# docker-compose.yml - 生产环境完整配置
services:
registry:
image: registry:2
volumes:
- registry-data:/var/lib/registry
- ./config.yml:/etc/docker/registry/config.yml:ro
environment:
- REGISTRY_HTTP_ADDR=0.0.0.0:5000
- REGISTRY_LOG_LEVEL=info
labels:
- "traefik.enable=true"
- "traefik.http.routers.registry.rule=Host(`registry.example.com`)"
- "traefik.http.routers.registry.tls.certresolver=letsencrypt"
restart: always
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5000/v2/"]
interval: 30s
timeout: 10s
retries: 3
# 可选:Web 管理界面
registry-ui:
image: joxit/docker-registry-ui:latest
ports:
- "8080:80"
environment:
- REGISTRY_TITLE=My Private Registry
- REGISTRY_URL=http://registry:5000
- DELETE_IMAGES=true
- SHOW_CONTENT_DIGEST=true
depends_on:
- registry
# 可选:镜像清理服务
registry-gc:
image: registry:2
entrypoint: ["bin/registry", "garbage-collect", "/etc/docker/registry/config.yml"]
volumes:
- registry-data:/var/lib/registry
- ./config.yml:/etc/docker/registry/config.yml:ro
volumes:
registry-data:
客户端配置
# 配置 Docker 客户端信任私有仓库
# 1. 配置 insecure-registry(仅用于 HTTP,不推荐生产)
# /etc/docker/daemon.json
{
"insecure-registries": ["registry.example.com:5000"]
}
# 重启 Docker
sudo systemctl restart docker
# 2. 对于自签名证书,需要信任证书
sudo mkdir -p /etc/docker/certs.d/registry.example.com
sudo cp ca.crt /etc/docker/certs.d/registry.example.com/
# 3. 企业环境建议使用企业 CA 证书
# 或使用 Let's Encrypt 等受信任的证书
镜像管理操作
# 查看所有仓库
curl -u admin:password123 http://localhost:5000/v2/_catalog
# 查看某镜像的所有标签
curl -u admin:password123 http://localhost:5000/v2/myapp/tags/list
# 删除镜像(需要配置 DELETE_IMAGES=true)
curl -X DELETE -u admin:password123 \
http://localhost:5000/v2/myapp/manifests/sha256:xxx
# 获取镜像 digest
curl -I -u admin:password123 \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
http://localhost:5000/v2/myapp/manifests/v1
# 清理未引用的层(垃圾回收)
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
备份与迁移
# 备份 Registry 数据
docker run --rm \
-v registry-data:/data \
-v $(pwd)/backup:/backup \
alpine tar czf /backup/registry-backup.tar.gz -C /data .
# 恢复数据
docker run --rm \
-v registry-data:/data \
-v $(pwd)/backup:/backup \
alpine sh -c "cd /data && tar xzf /backup/registry-backup.tar.gz"
# 迁移到新服务器
# 1. 停止原 Registry
docker stop registry
# 2. 打包数据卷
docker run --rm \
-v registry-data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/registry-data.tar.gz -C /data .
# 3. 复制到新服务器并解压
scp registry-data.tar.gz user@new-server:/tmp/
ssh user@new-server
docker volume create registry-data
docker run --rm \
-v registry-data:/data \
-v /tmp:/backup \
alpine sh -c "cd /data && tar xzf /backup/registry-data.tar.gz"
Harbor - 企业级 Registry
对于大型企业,推荐使用 Harbor,它提供了更丰富的功能:
# Harbor 功能特点:
# - Web 管理界面
# - 基于角色的访问控制(RBAC)
# - 漏洞扫描(Trivy 集成)
# - 镜像签名(Notary)
# - 镜像复制(跨区域同步)
# - 垃圾回收自动化
# - 审计日志
# 快速安装 Harbor
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
tar xzf harbor-offline-installer-v2.10.0.tgz
cd harbor
# 配置 harbor.yml
cp harbor.yml.tmpl harbor.yml
# 编辑 harbor.yml,设置 hostname、密码等
# 安装
./install.sh
# 或使用 Docker Compose
docker compose -f docker-compose.yml up -d
# 访问:https://your-harbor-domain
# 默认用户名:admin
# 默认密码:Harbor12345
Registry 方案对比
| 方案 | 复杂度 | 功能 | 适用场景 |
|---|---|---|---|
| Docker Registry | ⭐ 简单 | 基础存储分发 | 小型团队、测试环境 |
| Registry + Nginx | ⭐⭐ 中等 | HTTPS、认证 | 中型团队、生产环境 |
| Harbor | ⭐⭐⭐ 复杂 | 全功能企业级 | 大型企业、合规要求 |
| Nexus | ⭐⭐⭐ 复杂 | 多格式仓库 | 统一制品管理 |
安全最佳实践
✅ 使用非 root 用户
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup appuser
USER appuser
✅ 最小化镜像
FROM alpine:3.19
# 或使用 distroless
FROM gcr.io/distroless/static
✅ 健康检查
HEALTHCHECK --interval=30s \
CMD wget -q --spider \
http://localhost:3000/health
Docker 周边工具
Docker 生态系统拥有丰富的周边工具,覆盖管理、监控、安全、开发等多个领域,帮助提升工作效率。
🔍 Docker Scout - 安全扫描工具
什么是 Docker Scout?
Docker Scout 是 Docker 官方的安全分析工具,可以扫描你的镜像,找出其中的安全漏洞,并告诉你如何修复。
为什么需要它?
- 你的镜像可能包含有漏洞的软件包
- 新漏洞每天都在被发现,需要定期检查
- 生产环境必须确保安全合规
如何使用?
# 1. 快速查看镜像安全概况
docker scout quickview nginx:latest
# 2. 详细漏洞扫描
docker scout cves myapp:latest
# 3. 只显示高危漏洞
docker scout cves --severity HIGH,CRITICAL myapp:latest
# 4. 生成软件物料清单(SBOM)
docker scout sbom --format spdx-json --output sbom.json myapp:latest
# 5. 比较两个镜像的安全差异
docker scout compare --from myapp:v1 --to myapp:v2
# 6. 在 CI/CD 中自动阻断不安全镜像
docker scout cves --exit-code 1 --severity HIGH,CRITICAL myapp:latest
初学者常见问题
Q: 扫描结果显示很多漏洞,我该怎么办?
A: 优先修复 CRITICAL 和 HIGH 级别的漏洞,Docker Scout 会给出具体的修复建议。
Q: 每次构建都需要扫描吗?
A: 建议在 CI/CD 流程中加入自动扫描,确保不安全的镜像不会部署到生产环境。
🤖 Ask Gordon - Docker AI 助手
什么是 Ask Gordon?
Ask Gordon 是 Docker 内置的 AI 助手,你可以用自然语言与它对话,让它帮你编写 Dockerfile、诊断问题、优化配置。
为什么需要它?
- 不懂 Dockerfile 语法?让 AI 帮你写
- 遇到错误不知道怎么解决?问 Gordon
- 想知道最佳实践?直接问
如何使用?
# 启动 Ask Gordon(需要 Docker Desktop)
docker ai
# 示例对话:
You: 帮我为 Node.js 应用写一个 Dockerfile
Gordon: 好的,这是为你生成的 Dockerfile...
[生成优化的 Dockerfile]
You: 我的容器启动后立即退出了,怎么回事?
Gordon: 让我帮你分析可能的原因...
[给出诊断建议]
You: 如何减小镜像大小?
Gordon: 这里有一些优化建议...
[列出具体的优化方法]
常见使用场景
# 场景 1:生成 Dockerfile
"帮我为一个 Python Flask 应用创建 Dockerfile"
# 场景 2:诊断问题
"容器报错 'connection refused',如何排查?"
# 场景 3:优化建议
"这个 Dockerfile 有什么可以优化的地方?"
# 场景 4:学习概念
"什么是多阶段构建?为什么要用它?"
📦 Dockerizer - 自动容器化工具
什么是 Dockerizer?
Dockerizer 是一个 AI 驱动的工具,可以自动分析你的项目代码,生成 Dockerfile 和 docker-compose.yml,无需手动编写。
为什么需要它?
- 不知道如何为项目写 Dockerfile?自动生成
- 不确定最佳实践?AI 帮你优化
- 项目结构复杂?自动识别依赖
如何使用?
# 1. 安装 Dockerizer
npm install -g dockerizer
# 2. 在项目目录中初始化
cd my-project
npx dockerizer init
# Dockerizer 会:
# - 分析 package.json / requirements.txt 等依赖文件
# - 检测项目类型(Node.js / Python / Java 等)
# - 生成优化的 Dockerfile
# - 生成 docker-compose.yml(可选)
# 3. 分析现有项目
npx dockerizer analyze
# 4. 生成多阶段构建的 Dockerfile
npx dockerizer init --multi-stage
# 5. 为特定框架生成
npx dockerizer init --framework nextjs
npx dockerizer init --framework django
生成示例
# Dockerizer 自动生成的 Dockerfile 示例
# 项目类型:Node.js Express
# --- 基础阶段 ---
FROM node:20-alpine AS base
WORKDIR /app
# --- 依赖阶段 ---
FROM base AS deps
COPY package*.json ./
RUN npm ci --only=production
# --- 运行阶段 ---
FROM base
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]
🖥️ Dockge - 可视化管理界面
什么是 Dockge?
Dockge 是一个现代化的 Docker Compose 可视化管理界面,让你通过网页界面管理容器,无需记住复杂的命令。
为什么需要它?
- 不喜欢命令行?用图形界面操作
- 想查看容器日志?一键查看
- 需要管理多个项目?统一界面管理
如何安装?
# 方法 1:Docker 命令(推荐)
docker run -d \
--name dockge \
-p 5001:5001 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/dockge/data:/app/data \
louislam/dockge:latest
# 方法 2:Docker Compose
services:
dockge:
image: louislam/dockge:latest
ports:
- "5001:5001"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/app/data
restart: unless-stopped
# 访问界面
# 打开浏览器:http://localhost:5001
主要功能
# 1. 管理 Compose 项目
# - 查看所有服务状态
# - 启动/停止/重启服务
# - 查看实时日志
# 2. 编辑 compose 文件
# - 内置 YAML 编辑器
# - 语法高亮
# - 自动补全
# 3. 容器终端
# - 直接在网页中进入容器
# - 执行命令
# 4. 资源监控
# - CPU/内存使用情况
# - 网络流量
🧠 Docker GenAI Stack - AI 应用开发栈
什么是 Docker GenAI Stack?
Docker GenAI Stack 是 Docker 官方提供的生成式 AI 开发模板,包含运行大语言模型所需的所有组件。
为什么需要它?
- 想本地运行 AI 模型?一键部署
- 开发 AI 应用?提供完整模板
- 学习大语言模型?开箱即用
如何使用?
# 1. 克隆项目
git clone https://github.com/docker/genai-stack
cd genai-stack
# 2. 启动服务
docker compose up -d
# 3. 访问应用
# 打开浏览器:http://localhost:8501
# 包含的组件:
# - Ollama:本地运行大语言模型
# - LangChain:AI 应用开发框架
# - Neo4j:图数据库(可选)
# - Streamlit:Web 界面
运行 AI 模型示例
# 在容器中运行 Ollama
docker exec -it ollama ollama pull llama2
docker exec -it ollama ollama run llama2
# 或者使用 Docker 直接运行 Ollama
docker run -d \
--name ollama \
-p 11434:11434 \
-v ollama-data:/root/.ollama \
ollama/ollama
# 拉取并运行模型
docker exec -it ollama ollama pull llama2
docker exec -it ollama ollama pull codellama
docker exec -it ollama ollama pull mistral
🔒 Trivy AI 增强版 - 漏洞扫描工具
什么是 Trivy?
Trivy 是一个全面的安全扫描器,可以扫描容器镜像、文件系统、Git 仓库,发现漏洞、配置问题和敏感信息泄露。AI 增强版提供智能修复建议。
为什么需要它?
- Docker Scout 的开源替代方案
- 扫描更全面(漏洞+配置+密钥)
- AI 提供智能修复建议
如何安装和使用?
# 安装 Trivy
# macOS
brew install trivy
# Windows (使用 Scoop)
scoop install trivy
# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# 基本使用
# 1. 扫描镜像
trivy image nginx:latest
# 2. 扫描本地文件系统
trivy fs .
# 3. 扫描配置文件
trivy config .
# 4. 扫描多种类型
trivy image --scanners vuln,secret,misconfig myapp:latest
# 5. 输出 JSON 格式
trivy image --format json --output report.json myapp:latest
# 6. 只显示高危漏洞
trivy image --severity HIGH,CRITICAL myapp:latest
CI/CD 集成示例
# GitHub Actions
name: Security Scan
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
severity: 'HIGH,CRITICAL'
exit-code: '1' # 发现漏洞时失败
扫描结果解读
trivy image myapp:latest
# 输出示例:
# ┌──────────────┬───────────────┬──────────────┬─────────────┐
# │ Library │ Vulnerability │ Severity │ Version │
# ├──────────────┼───────────────┼──────────────┼─────────────┤
# │ openssl │ CVE-2024-1234 │ CRITICAL │ 1.1.1k │
# │ node │ CVE-2024-5678 │ HIGH │ 18.0.0 │
# └──────────────┴───────────────┴──────────────┴─────────────┘
# 解读:
# - CRITICAL: 必须立即修复
# - HIGH: 应尽快修复
# - MEDIUM: 计划修复
# - LOW: 可忽略
工具对比与选择指南
| 工具 | 主要用途 | 适合人群 | 难度 |
|---|---|---|---|
| Docker Scout | 官方安全扫描 | 所有 Docker 用户 | ⭐ 简单 |
| Ask Gordon | AI 助手、学习指导 | 初学者 | ⭐ 简单 |
| Dockerizer | 自动生成配置 | 不想手写配置的人 | ⭐ 简单 |
| Dockge | 可视化管理 | 喜欢图形界面的人 | ⭐ 简单 |
| GenAI Stack | AI 应用开发 | AI 开发者 | ⭐⭐ 中等 |
| Trivy | 全面安全扫描 | 安全运维人员 | ⭐⭐ 中等 |
🖥️ 可视化管理工具
Portainer - 最流行的管理界面
Portainer 是一个轻量级的 Docker 管理界面,提供直观的 Web UI 来管理容器、镜像、网络和卷。
# 快速启动
docker run -d \
--name portainer \
-p 9443:9443 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer-data:/data \
--restart always \
portainer/portainer-ce:latest
# 访问:https://localhost:9443
# 首次访问需要设置管理员密码
# Docker Compose 方式
services:
portainer:
image: portainer/portainer-ce:latest
ports:
- "9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer-data:/data
restart: always
volumes:
portainer-data:
主要功能:容器管理、镜像管理、网络配置、卷管理、用户权限控制、Stack 管理、模板部署
Lazydocker - 终端交互式管理
Lazydocker 是一个终端 UI 工具,用键盘即可管理 Docker,适合喜欢命令行的用户。
# 安装(macOS)
brew install jesseduffield/lazydocker/lazydocker
# 安装(Linux)
curl https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash
# 安装(Windows)
scoop install lazydocker
# 或使用 Docker 运行
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
lazyteam/lazydocker
# 启动
lazydocker
# 快捷键:
# - 上/下:选择项目
# - Enter:查看详情
# - x:停止/删除
# - l:查看日志
# - s:进入容器 Shell
# - ?:帮助
ctop - 容器实时监控
ctop 提供实时的容器资源监控视图,类似 top 命令但专为容器设计。
# 安装(macOS)
brew install ctop
# 安装(Linux)
sudo wget https://github.com/bcicen/ctop/releases/download/v1.0.7/ctop-1.0.7-linux-amd64 -O /usr/local/bin/ctop
sudo chmod +x /usr/local/bin/ctop
# 使用 Docker 运行
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
quay.io/vektorlab/ctop:latest
# 启动
ctop
# 快捷键:
# - a:切换显示所有/运行中容器
# - l:查看容器日志
# - s:进入容器 Shell
# - e:显示环境变量
# - h:帮助
🔧 开发辅助工具
Dive - 镜像分析工具
Dive 帮助你分析 Docker 镜像每一层的内容,找出可以优化的地方,减小镜像体积。
# 安装(macOS)
brew install dive
# 安装(Linux)
wget https://github.com/wagoodman/dive/releases/download/v0.12.0/dive_0.12.0_linux_amd64.deb
sudo apt install ./dive_0.12.0_linux_amd64.deb
# 分析镜像
dive nginx:alpine
# 分析本地构建的镜像
dive myapp:latest
# 在 CI 中使用
dive --ci myapp:latest
# 输出信息:
# - 每层的文件变更
# - 可能的优化建议
# - 镜像效率评分
# - 重复文件检测
Hadolint - Dockerfile 语法检查
Hadolint 是 Dockerfile 的 lint 工具,检查语法错误和最佳实践违反。
# 安装(macOS)
brew install hadolint
# 安装(Linux)
wget -O hadolint https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64
chmod +x hadolint
sudo mv hadolint /usr/local/bin/
# 使用 Docker 运行
docker run --rm -i hadolint/hadolint < Dockerfile
# 检查 Dockerfile
hadolint Dockerfile
# 只显示错误(忽略警告)
hadolint --ignore DL3008 Dockerfile
# 输出 JSON 格式
hadolint -f json Dockerfile
# 常见规则:
# DL3000: 使用绝对 WORKDIR
# DL3001: 不要使用 MAINTAINER(已废弃)
# DL3003: 不要使用 WORKDIR 切换目录
# DL3004: 不要以 root 用户构建
# DL3008: 固定 apt 包版本
# DL3015: 避免使用 --no-install-recommends 以外的选项
# VS Code 集成
# 安装扩展:exiasr.hadolint
DevContainer - 开发容器化
DevContainer 让你在容器中进行开发,确保开发环境一致性,支持 VS Code 和 GitHub Codespaces。
# .devcontainer/devcontainer.json
{
"name": "My Dev Container",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-sqlite",
"esbenp.prettier-vscode"
]
}
},
"forwardPorts": [3000],
"postCreateCommand": "npm install",
"remoteUser": "vscode"
}
# 或使用 Docker Compose
# .devcontainer/docker-compose.yml
services:
app:
build:
context: ..
dockerfile: Dockerfile.dev
volumes:
- ../..:/workspaces:cached
command: sleep infinity
environment:
- DATABASE_URL=postgres://db:5432/dev
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: dev
POSTGRES_PASSWORD: dev
# VS Code 命令面板:
# Dev Containers: Reopen in Container
# Dev Containers: Rebuild Container
⚙️ 自动化工具
Watchtower - 自动更新容器
Watchtower 监控运行中的容器,当镜像有更新时自动拉取并重启容器。
# 基本启动
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower
# 指定检查间隔(秒)
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_POLL_INTERVAL=3600 \
containrrr/watchtower
# 只监控特定容器
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower myapp nginx
# Docker Compose
services:
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WATCHTOWER_POLL_INTERVAL=3600
- WATCHTOWER_CLEANUP=true # 删除旧镜像
- WATCHTOWER_INCLUDE_STOPPED=true # 包括停止的容器
- WATCHTOWER_NOTIFICATIONS=email # 发送通知
restart: always
# 通知配置(邮件示例)
environment:
- WATCHTOWER_NOTIFICATIONS=email
- WATCHTOWER_NOTIFICATION_EMAIL_FROM=sender@example.com
- WATCHTOWER_NOTIFICATION_EMAIL_TO=admin@example.com
- WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.example.com
- WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587
- WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=user
- WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=pass
Skaffold - Kubernetes 开发工具
Skaffold 是 Google 开发的命令行工具,简化 Kubernetes 应用的持续开发。
# 安装(macOS)
brew install skaffold
# 安装(Linux)
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
chmod +x skaffold
sudo mv skaffold /usr/local/bin
# 初始化项目
skaffold init
# 开发模式(文件变化自动重新部署)
skaffold dev
# 构建并部署
skaffold run
# 清理部署
skaffold delete
# skaffold.yaml 示例
apiVersion: skaffold/v4beta9
kind: Config
build:
artifacts:
- image: myapp
docker:
dockerfile: Dockerfile
manifests:
rawYaml:
- k8s/*.yaml
deploy:
kubectl: {}
Tilt - 本地 Kubernetes 开发
Tilt 为 Kubernetes 微服务开发提供即时反馈,支持多服务同时开发。
# 安装(macOS/Linux)
curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
# 安装(macOS with Homebrew)
brew install tilt-dev/tap/tilt
# 启动 Tilt
tilt up
# Tiltfile 示例
# Tiltfile
docker_build('myapp', '.')
k8s_yaml('k8s/')
k8s_resource('myapp', port_forwards=3000)
# 多服务示例
docker_build('api', './api')
docker_build('web', './web')
k8s_yaml('k8s/')
k8s_resource('api', port_forwards=8080)
k8s_resource('web', port_forwards=3000)
# 特点:
# - 实时日志查看
# - 资源监控面板
# - 文件变化自动构建
# - 支持 live_update(不重建镜像更新代码)
🌐 网络与代理
Traefik - 云原生边缘路由器
Traefik 是现代化的反向代理和负载均衡器,自动发现 Docker 服务并配置路由。
# docker-compose.yml
services:
traefik:
image: traefik:v3.0
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./certs:/etc/certs:ro
restart: always
whoami:
image: traefik/whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.example.com`)"
- "traefik.http.routers.whoami.entrypoints=web"
# traefik.yml
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
docker:
exposedByDefault: false
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /etc/certs/acme.json
httpChallenge:
entryPoint: web
📊 监控与日志
Prometheus + Grafana - 监控方案
完整的 Docker 监控方案,Prometheus 收集指标,Grafana 可视化展示。
# docker-compose.yml
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
command:
- '--config.file=/etc/prometheus/prometheus.yml'
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
ports:
- "8081:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
node-exporter:
image: prom/node-exporter:latest
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
volumes:
grafana-data:
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
# 导入 Grafana Dashboard
# 推荐 ID: 11600 (Docker and system monitoring)
# 或 893 (Node Exporter Full)
Dozzle - 轻量级日志查看
Dozzle 是一个轻量级的容器日志查看工具,实时显示容器日志。
# 快速启动
docker run -d \
--name dozzle \
-p 9999:8080 \
-v /var/run/docker.sock:/var/run/docker.sock \
amir20/dozzle:latest
# Docker Compose
services:
dozzle:
image: amir20/dozzle:latest
ports:
- "9999:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOZZLE_LEVEL=info
- DOZZLE_TAILSIZE=300
# 访问:http://localhost:9999
# 特点:
# - 实时日志流
# - 多容器同时查看
# - 日志搜索过滤
# - 无需配置
🔐 安全加固工具
Docker Bench for Security
Docker 官方安全检查脚本,检查主机和 Docker 配置是否符合 CIS 安全基准。
# 运行检查
docker run --rm \
--net host \
--pid host \
--cap-add audit_control \
-v /var/lib:/var/lib \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib/systemd:/usr/lib/systemd \
-v /etc:/etc \
--label docker_bench_security \
docker/docker-bench-security
# 输出分类:
# [INFO] 检查项
# [PASS] 通过
# [WARN] 警告(需要关注)
# [FAIL] 失败(需要修复)
# [NOTE] 说明
# 常见修复建议:
# 1. 设置日志驱动
# --log-driver json-file --log-opts max-size=10m
# 2. 禁用 inter-container communication
# --icc=false
# 3. 启用 user namespace
# /etc/docker/daemon.json: {"userns-remap": "default"}
# 4. 限制容器 capabilities
# --cap-drop ALL --cap-add CHOWN
# 5. 使用 seccomp profile
# --security-opt seccomp=default.json
Clair - 镜像漏洞扫描
Clair 是 CoreOS 开发的开源镜像漏洞扫描器,可集成到 CI/CD 流程。
# 使用 Clair 的客户端工具 clair-scanner
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd)/reports:/reports \
arminc/clair-local-scan:v2.0.8 \
--clair http://clair:6060 \
--report /reports/$(basename $IMAGE).json \
myapp:latest
# 或使用 Clair V4
services:
clair:
image: quay.io/coreos/clair:v4.5.0
ports:
- "6060:6060"
- "6061:6061"
volumes:
- ./config.yaml:/etc/clair/config.yaml
# 与 Harbor 集成
# Harbor 内置 Clair 扫描器
# 在 Harbor 配置中启用漏洞扫描即可
🛠️ 完整工具清单
| 类别 | 工具 | 用途 |
|---|---|---|
| 可视化管理 | Portainer | Web 管理界面 |
| Lazydocker | 终端 UI 管理 | |
| Dockge | Compose 项目管理 | |
| 监控 | ctop | 容器资源监控 |
| Prometheus + Grafana | 完整监控方案 | |
| 日志 | Dozzle | 轻量级日志查看 |
| 开发 | Dive | 镜像层分析 |
| Hadolint | Dockerfile 检查 | |
| DevContainer | 容器化开发环境 | |
| 自动化 | Watchtower | 自动更新容器 |
| Skaffold/Tilt | K8s 开发流程 | |
| 网络 | Traefik | 反向代理/负载均衡 |
| 安全 | Docker Scout | 官方安全扫描 |
| Trivy | 漏洞扫描 | |
| Docker Bench | 安全基准检查 | |
| AI 相关 | Ask Gordon | AI 助手 |
| GenAI Stack | AI 应用开发栈 |
Docker 替代品
虽然 Docker 是最流行的容器化平台,但市面上还有其他优秀的替代方案,各有特点和适用场景。
容器运行时替代品
Podman - 无守护进程的容器引擎
Podman 是 Red Hat 开发的容器引擎,与 Docker 完全兼容,但不需要守护进程,支持 rootless 模式。
核心特点
# 与 Docker 的主要区别:
# 1. 无守护进程(daemonless)
# 2. 默认 rootless 运行(更安全)
# 3. 支持 Kubernetes YAML
# 4. 兼容 Docker CLI 命令
# 安装(macOS)
brew install podman
podman machine init
podman machine start
# 安装(Linux - Ubuntu)
sudo apt update
sudo apt install podman
# 安装(Linux - Fedora/RHEL)
sudo dnf install podman
基本使用
# 命令与 Docker 几乎相同
podman pull nginx:alpine
podman run -d -p 8080:80 nginx
podman ps
podman images
podman exec -it container_id sh
podman logs container_id
# 构建镜像
podman build -t myapp:v1 .
# 使用 Docker Compose 兼容工具
podman-compose up -d
# 生成 Kubernetes YAML
podman generate kube mycontainer > pod.yaml
# 从 Kubernetes YAML 部署
podman play kube pod.yaml
Podman vs Docker
| 特性 | Docker | Podman |
|---|---|---|
| 守护进程 | 需要 dockerd | 无守护进程 |
| Root 权限 | 默认需要 root | 默认 rootless |
| Docker 兼容 | - | CLI 完全兼容 |
| Kubernetes 集成 | 需要额外工具 | 原生支持 |
| 安全性 | 中等 | 更高(rootless) |
别名配置
# 在 ~/.bashrc 或 ~/.zshrc 添加别名
alias docker=podman
alias docker-compose=podman-compose
# 这样可以直接使用 Docker 命令习惯
containerd - 工业级容器运行时
containerd 是从 Docker 分离出来的容器运行时,专注于运行容器,被 Kubernetes 作为默认运行时。
# 安装(Linux)
wget https://github.com/containerd/containerd/releases/download/v1.7.13/containerd-1.7.13-linux-amd64.tar.gz
tar xzf containerd-1.7.13-linux-amd64.tar.gz
sudo mv bin/* /usr/local/bin/
# 创建 systemd 服务
sudo mkdir -p /usr/local/lib/systemd/system/
sudo cat > /usr/local/lib/systemd/system/containerd.service << EOF
[Unit]
Description=containerd container runtime
After=network.target
[Service]
ExecStart=/usr/local/bin/containerd
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now containerd
# 使用 ctr 命令管理容器
ctr images pull docker.io/library/nginx:alpine
ctr run -d docker.io/library/nginx:alpine mynginx
ctr containers list
ctr tasks list
适用场景
- Kubernetes 集群节点运行时
- 需要轻量级容器运行时的场景
- 嵌入式或边缘计算环境
CRI-O - Kubernetes 专用运行时
CRI-O 是专门为 Kubernetes 设计的轻量级容器运行时,实现 CRI(Container Runtime Interface)。
# 安装(Fedora/RHEL)
sudo dnf install cri-o
# 安装(Ubuntu)
sudo apt install cri-o
# 启动服务
sudo systemctl enable --now crio
# CRI-O 专为 Kubernetes 优化
# 不提供独立 CLI,通过 crictl 管理
# 安装 crictl
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.29.0/crictl-v1.29.0-linux-amd64.tar.gz
tar xzf crictl-v1.29.0-linux-amd64.tar.gz
sudo mv crictl /usr/local/bin/
# 常用命令
crictl pull nginx:alpine
crictl images
crictl pods
crictl ps
crictl logs container_id
镜像构建工具
Kaniko - 无 Docker 构建镜像
Kaniko 可以在不需要 Docker 守护进程的情况下构建镜像,适合 CI/CD 环境。
# 在 Kubernetes 中使用
apiVersion: v1
kind: Pod
metadata:
name: kaniko
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:latest
args:
- "--dockerfile=Dockerfile"
- "--context=git://github.com/user/repo"
- "--destination=user/image:tag"
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker
volumes:
- name: docker-config
configMap:
name: docker-config
# 在容器中运行
docker run -it \
-v $(pwd):/workspace \
-v ~/.docker/config.json:/kaniko/.docker/config.json \
gcr.io/kaniko-project/executor:latest \
--dockerfile=Dockerfile \
--context=/workspace \
--destination=myregistry/myapp:v1
Buildah - 无守护进程构建
Buildah 是 Podman 的姐妹项目,专注于构建 OCI 镜像,无需 root 权限。
# 安装(Linux)
sudo apt install buildah # Ubuntu/Debian
sudo dnf install buildah # Fedora/RHEL
# 从 Dockerfile 构建
buildah build -t myapp:v1 .
# 交互式构建
container=$(buildah from alpine)
buildah run $container -- apk add nginx
buildah config --cmd "nginx -g 'daemon off;'" $container
buildah commit $container myapp:nginx
# 推送镜像
buildah push myapp:v1 docker://registry.example.com/myapp:v1
# 无需 Dockerfile 的构建方式
buildah from alpine
buildah copy mycontainer app.py /app/
buildah run mycontainer -- pip install flask
buildah commit mycontainer myapp:latest
BuildKit - Docker 下一代构建器
BuildKit 是 Docker 的新一代构建引擎,性能更强,支持并行构建和更好的缓存。
# 启用 BuildKit
export DOCKER_BUILDKIT=1
docker build -t myapp:v1 .
# 使用 buildx(Docker 内置)
docker buildx version
# 创建多平台构建器
docker buildx create --name mybuilder --use
docker buildx inspect --bootstrap
# 多平台构建
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:v1 .
# 直接使用 BuildKit daemon
# 安装
wget https://github.com/moby/buildkit/releases/download/v0.12.5/buildkit-v0.12.5.linux-amd64.tar.gz
tar xzf buildkit-v0.12.5.linux-amd64.tar.gz
sudo mv bin/* /usr/local/bin/
# 启动服务
sudo buildkitd &
# 使用 buildctl 构建
buildctl build \
--frontend dockerfile.v0 \
--local context=. \
--local dockerfile=. \
--output type=docker,name=myapp:v1 | docker load
容器编排平台
Kubernetes - 容器编排标准
Kubernetes 是容器编排的事实标准,适合大规模生产环境。
# 本地开发环境选择
# 1. minikube
minikube start
minikube dashboard
# 2. kind(Kubernetes in Docker)
kind create cluster
kind delete cluster
# 3. k3s(轻量级 Kubernetes)
curl -sfL https://get.k3s.io | sh -
# 4. k3d(k3s in Docker)
k3d cluster create mycluster
# 基本概念
# Pod: 最小部署单元
# Deployment: 管理 Pod 副本
# Service: 网络服务发现
# ConfigMap/Secret: 配置管理
# Ingress: HTTP 路由
# 示例部署
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
kubectl get pods,svc
# YAML 部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 3
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: myapp:v1
ports:
- containerPort: 3000
Nomad - HashiCorp 编排工具
Nomad 是 HashiCorp 开发的简单灵活的工作负载编排器。
# 安装(macOS)
brew install nomad
# 安装(Linux)
wget https://releases.hashicorp.com/nomad/1.7.7/nomad_1.7.7_linux_amd64.zip
unzip nomad_1.7.7_linux_amd64.zip
sudo mv nomad /usr/local/bin/
# 启动开发模式
nomad agent -dev
# 运行 Docker 任务
job "webapp" {
datacenters = ["dc1"]
type = "service"
group "web" {
count = 2
task "server" {
driver = "docker"
config {
image = "nginx:alpine"
port_map {
http = 80
}
}
resources {
cpu = 500
memory = 256
network {
mbits = 10
port "http" {}
}
}
}
}
}
# 运行作业
nomad job run webapp.nomad
nomad job status webapp
Docker Swarm - Docker 原生编排
Docker Swarm 是 Docker 内置的编排功能,简单易用,适合中小规模集群。
# 初始化 Swarm
docker swarm init --advertise-addr
# 添加工作节点
docker swarm join-token worker
# 部署服务
docker service create \
--name web \
--replicas 3 \
--publish 80:80 \
nginx:alpine
# 管理服务
docker service ls
docker service ps web
docker service scale web=5
docker service update --image nginx:latest web
# 使用 Stack 部署
# docker-compose.yml
version: "3.8"
services:
web:
image: nginx
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
ports:
- "80:80"
# 部署 Stack
docker stack deploy -c docker-compose.yml myapp
docker stack ls
docker stack services myapp
开发环境工具
Dagger - 可编程 CI/CD
Dagger 使用代码定义 CI/CD 流水线,在容器中运行,无需专有 CI 服务器。
# 安装
curl -fsSL https://dl.dagger.io/dagger/install.sh | sh
dagger version
# 使用 Go SDK 编写流水线
# main.go
package main
import (
"context"
"dagger.io/dagger"
)
func main() {
ctx := context.Background()
client, _ := dagger.Connect(ctx)
defer client.Close()
// 获取源代码
source := client.Host().Directory()
// 构建镜像
image := client.Container().
Build(source)
// 运行测试
_, err := image.
WithExec([]string{"go", "test", "./..."}).
ExitCode(ctx)
}
# 运行
dagger run go run main.go
Earthly - Make + Docker
Earthly 结合 Makefile 和 Dockerfile 的优点,提供可重复的构建。
# 安装(macOS)
brew install earthly/earthly/earthly
# 安装(Linux)
sudo /bin/sh -c 'wget https://github.com/earthly/earthly/releases/download/v0.8.0/earthly-linux-amd64 -O /usr/local/bin/earthly && chmod +x /usr/local/bin/earthly'
# Earthfile
VERSION 0.8
FROM golang:1.22-alpine
build:
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o app .
SAVE ARTIFACT app
docker:
FROM alpine:3.19
COPY +build/app /app
ENTRYPOINT ["/app"]
SAVE IMAGE myapp:latest
test:
FROM +build
RUN go test ./...
# 执行构建
earthly +build
earthly +docker
earthly +test
替代品对比总结
| 类别 | 工具 | 主要优势 | 适用场景 |
|---|---|---|---|
| 容器运行时 | Podman | 无守护进程、rootless | 安全要求高的环境 |
| containerd | 轻量、稳定 | Kubernetes 节点 | |
| CRI-O | K8s 原生 | Kubernetes 专用 | |
| 镜像构建 | Kaniko | 无 Docker 构建 | CI/CD 流水线 |
| Buildah | rootless 构建 | 安全构建环境 | |
| BuildKit | 高性能、多平台 | 现代 Docker 构建 | |
| 容器编排 | Kubernetes | 行业标准、功能强大 | 大规模生产环境 |
| Nomad | 简单灵活 | 混合工作负载 | |
| Docker Swarm | Docker 原生、易用 | 中小规模集群 |
如何选择?
继续使用 Docker
- 个人开发和学习
- 中小团队项目
- 需要最广泛的社区支持
- 使用 Docker Desktop 的 macOS/Windows 用户
考虑 Podman
- 需要更高的安全性
- Linux 服务器环境
- 想要 rootless 容器
- 企业级 Red Hat 环境
考虑 Kubernetes
- 大规模微服务架构
- 需要自动扩缩容
- 多云/混合云部署
- 企业生产环境
考虑 Nomad
- 需要编排多种工作负载
- 想要更简单的操作
- 已有 HashiCorp 工具栈
- 边缘计算场景
实战案例
CI/CD 容器化流程
开发环境架构
:3000
:5432
:6379
案例 1:Web 应用
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
案例 2:Python 应用
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
案例 3:完整开发环境
:3000
:5432
:6379
# docker-compose.yml
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
environment:
- DATABASE_URL=postgres://user:pass@db:5432/dev
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: dev
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
volumes:
- db-data:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
db-data: