name: docker description: Docker使用指南 - 一个用于在隔离容器中构建、运行和部署应用程序的容器化平台。在容器化应用程序、创建Dockerfile、使用Docker Compose、管理镜像/容器、配置网络和存储、优化构建、部署到生产环境或使用Docker实现CI/CD管道时使用。
Docker技能
本技能提供使用Docker的综合指南,涵盖容器化概念、实际工作流和所有主要技术栈的最佳实践。
何时使用此技能
在以下情况使用此技能:
- 为任何语言或框架容器化应用程序
- 创建或优化Dockerfile和Docker Compose配置
- 使用Docker设置开发环境
- 部署容器化应用程序到生产环境
- 使用Docker实现CI/CD管道
- 管理容器网络、存储和安全
- 排查Docker相关问题
- 构建多平台镜像
- 实现微服务架构
核心Docker概念
容器
- 轻量级、隔离的进程,将应用程序与所有依赖项捆绑在一起
- 通过联合文件系统和命名空间技术提供文件系统隔离
- 默认短暂性 - 容器停止时更改会丢失(除非持久化到卷)
- 单一职责原则:每个容器应做好一件事
- 多个相同容器可以从相同的不可变镜像运行而无需冲突
镜像
- 容器的蓝图/模板 - 只读文件系统 + 配置
- 由分层文件系统组成(不可变、可重用层)
- 根据Dockerfile指令构建或从运行容器提交
- 存储在注册表中(Docker Hub、ECR、ACR、GCR、私有注册表)
- 镜像命名:
REGISTRY/NAMESPACE/REPOSITORY:TAG(例如,docker.io/library/nginx:latest)
卷与存储
- 卷:Docker管理的持久存储,在容器删除后保留
- 绑定挂载:将主机文件系统路径直接映射到容器中
- tmpfs挂载:用于临时数据的内存存储
- 支持容器间数据共享并在容器生命周期后持久化
网络
- 默认桥接网络连接同一主机上的容器
- 自定义网络允许通过DNS解析进行显式容器通信
- 主机网络去除网络隔离以提高性能
- 覆盖网络支持多主机容器通信(Swarm)
- MACVLAN/IPvlan用于需要直接L2/L3网络访问的容器
Dockerfile最佳实践
基本指令
FROM <image>:<tag> # 基础镜像(使用特定版本,非'latest')
WORKDIR /app # 后续命令的工作目录
COPY package*.json ./ # 首先复制依赖文件(用于缓存)
RUN npm install --production # 执行构建命令
COPY . . # 复制应用程序代码
ENV NODE_ENV=production # 环境变量
EXPOSE 3000 # 记录暴露的端口
USER node # 以非root用户运行(安全)
CMD ["node", "server.js"] # 容器启动时的默认命令
多阶段构建(生产关键)
分离构建环境与运行时环境以减少镜像大小并提高安全性:
# 阶段1:构建
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 阶段2:生产
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
好处:最终镜像中没有构建工具,仅包含编译资产,更小尺寸,提高安全性
层缓存优化
顺序重要:如果指令未更改,Docker会重用层:
- 依赖项优先(COPY package.json, RUN npm install)
- 应用程序代码最后(COPY . .)
- 这样,代码更改不会使依赖层失效
安全加固
# 使用特定版本
FROM node:20.11.0-alpine3.19
# 创建非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 设置所有权
COPY --chown=nodejs:nodejs . .
# 切换到非root
USER nodejs
# 只读根文件系统(尽可能)
# 运行容器时添加 --read-only 标志
.dockerignore文件
从构建上下文中排除不必要的文件:
node_modules
.git
.env
.env.local
*.log
.DS_Store
README.md
docker-compose.yml
.dockerignore
Dockerfile
dist
coverage
.vscode
常见工作流
构建镜像
# 构建并标记
docker build -t myapp:1.0 .
# 构建针对特定阶段
docker build -t myapp:dev --target build .
# 使用构建参数构建
docker build --build-arg NODE_ENV=production -t myapp:1.0 .
# 为多平台构建
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:1.0 .
# 查看镜像层和大小
docker image history myapp:1.0
# 列出所有镜像
docker image ls
运行容器
# 基本运行
docker run myapp:1.0
# 后台运行(分离)
docker run -d --name myapp myapp:1.0
# 端口映射(主机:容器)
docker run -p 8080:3000 myapp:1.0
# 环境变量
docker run -e NODE_ENV=production -e API_KEY=secret myapp:1.0
# 卷挂载(命名卷)
docker run -v mydata:/app/data myapp:1.0
# 绑定挂载(开发)
docker run -v $(pwd)/src:/app/src myapp:1.0
# 自定义网络
docker run --network my-network myapp:1.0
# 资源限制
docker run --memory 512m --cpus 0.5 myapp:1.0
# 交互式终端
docker run -it myapp:1.0 /bin/sh
# 覆盖入口点/命令
docker run --entrypoint /bin/sh myapp:1.0
docker run myapp:1.0 custom-command --arg
容器管理
# 列出运行中的容器
docker ps
# 列出所有容器(包括已停止)
docker ps -a
# 查看日志
docker logs myapp
docker logs -f myapp # 跟随日志
docker logs --tail 100 myapp # 最后100行
# 在运行容器中执行命令
docker exec myapp ls /app
docker exec -it myapp /bin/sh # 交互式shell
# 停止容器(优雅)
docker stop myapp
# 杀死容器(立即)
docker kill myapp
# 移除容器
docker rm myapp
docker rm -f myapp # 强制移除运行中的容器
# 查看容器详细信息
docker inspect myapp
# 监控资源使用情况
docker stats myapp
# 查看容器进程
docker top myapp
# 复制文件到/从容器
docker cp myapp:/app/logs ./logs
docker cp ./config.json myapp:/app/config.json
镜像管理
# 标记镜像
docker tag myapp:1.0 registry.example.com/myapp:1.0
# 推送到注册表
docker login registry.example.com
docker push registry.example.com/myapp:1.0
# 从注册表拉取
docker pull nginx:alpine
# 移除镜像
docker image rm myapp:1.0
# 移除未使用的镜像
docker image prune
# 移除所有未使用的资源(镜像、容器、卷、网络)
docker system prune -a
# 查看磁盘使用情况
docker system df
卷管理
# 创建命名卷
docker volume create mydata
# 列出卷
docker volume ls
# 检查卷
docker volume inspect mydata
# 移除卷
docker volume rm mydata
# 移除未使用的卷
docker volume prune
网络管理
# 创建网络
docker network create my-network
docker network create --driver bridge my-bridge
# 列出网络
docker network ls
# 检查网络
docker network inspect my-network
# 将容器连接到网络
docker network connect my-network myapp
# 将容器从网络断开
docker network disconnect my-network myapp
# 移除网络
docker network rm my-network
Docker Compose
何时使用Compose
- 多容器应用程序(web + 数据库 + 缓存)
- 跨团队一致的开发环境
- 简化复杂的docker run命令
- 管理应用程序依赖项和启动顺序
基本Compose文件结构
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:pass@db:5432/app
depends_on:
- db
- redis
volumes:
- ./src:/app/src # 开发:实时代码重载
networks:
- app-network
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: app
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
networks:
- app-network
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge
Compose命令
# 启动所有服务
docker compose up
# 后台启动
docker compose up -d
# 启动前构建镜像
docker compose up --build
# 扩展特定服务
docker compose up -d --scale web=3
# 停止所有服务
docker compose down
# 停止并移除卷
docker compose down --volumes
# 查看日志
docker compose logs
docker compose logs -f web # 跟随特定服务
# 在服务中执行命令
docker compose exec web sh
docker compose exec db psql -U user -d app
# 列出运行中的服务
docker compose ps
# 重启服务
docker compose restart web
# 拉取最新镜像
docker compose pull
# 验证compose文件
docker compose config
开发与生产Compose
compose.yml(基础配置):
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/app
compose.override.yml(开发覆盖,自动加载):
services:
web:
volumes:
- ./src:/app/src # 实时代码重载
environment:
- NODE_ENV=development
- DEBUG=true
command: npm run dev
compose.prod.yml(生产覆盖):
services:
web:
image: registry.example.com/myapp:1.0
restart: always
environment:
- NODE_ENV=production
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
用法:
# 开发(自动使用compose.yml + compose.override.yml)
docker compose up
# 生产(显式覆盖)
docker compose -f compose.yml -f compose.prod.yml up -d
语言特定Dockerfile
Node.js
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package*.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
Python
FROM python:3.11-slim AS build
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
FROM python:3.11-slim AS production
WORKDIR /app
COPY --from=build /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY . .
RUN adduser --disabled-password --gecos '' appuser && \
chown -R appuser:appuser /app
USER appuser
EXPOSE 8000
CMD ["python", "app.py"]
Go
FROM golang:1.21-alpine AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
FROM scratch
COPY --from=build /app/main /main
EXPOSE 8080
CMD ["/main"]
Java (Spring Boot)
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN ./mvnw clean package -DskipTests
FROM eclipse-temurin:21-jre-alpine AS production
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
RUN addgroup -g 1001 -S spring && \
adduser -S spring -u 1001
USER spring
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
React/Vue/Angular (静态SPA)
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
生产部署
健康检查
在Dockerfile中:
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
在Compose中:
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 3s
start-period: 40s
retries: 3
资源限制
services:
web:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
重启策略
services:
web:
restart: unless-stopped # 除非手动停止,否则重启
# 其他选项:"no", "always", "on-failure"
日志配置
services:
web:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
环境变量与秘密
使用.env文件:
# .env
DATABASE_URL=postgresql://user:pass@db:5432/app
API_KEY=secret
services:
web:
env_file:
- .env
使用Docker秘密(Swarm):
services:
web:
secrets:
- db_password
secrets:
db_password:
external: true
生产清单
- ✅ 使用特定镜像版本(非
latest) - ✅ 以非root用户运行
- ✅ 多阶段构建以最小化镜像大小
- ✅ 实施健康检查
- ✅ 配置资源限制
- ✅ 设置重启策略
- ✅ 配置日志
- ✅ 安全管理秘密(不在环境变量中)
- ✅ 漏洞扫描(Docker Scout)
- ✅ 尽可能使用只读根文件系统
- ✅ 网络分段
- ✅ 定期更新镜像
CI/CD集成
GitHub Actions示例
name: Docker构建与推送
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 设置Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 登录到Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 构建并推送
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: user/app:latest,user/app:${{ github.sha }}
cache-from: type=registry,ref=user/app:buildcache
cache-to: type=registry,ref=user/app:buildcache,mode=max
- name: 运行漏洞扫描
uses: docker/scout-action@v1
with:
command: cves
image: user/app:${{ github.sha }}
安全最佳实践
扫描漏洞
# 使用Docker Scout
docker scout cves myapp:1.0
docker scout recommendations myapp:1.0
# 快速查看
docker scout quickview myapp:1.0
安全运行容器
# 只读根文件系统
docker run --read-only -v /tmp --tmpfs /run myapp:1.0
# 丢弃所有能力,仅添加所需
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp:1.0
# 无新特权
docker run --security-opt=no-new-privileges myapp:1.0
# 使用安全配置文件
docker run --security-opt apparmor=docker-default myapp:1.0
# 限制资源
docker run --memory=512m --cpus=0.5 --pids-limit=100 myapp:1.0
镜像安全检查清单
- ✅ 从最小基础镜像开始(Alpine, Distroless)
- ✅ 使用特定版本,非
latest - ✅ 定期扫描漏洞
- ✅ 以非root用户运行
- ✅ 不在镜像中包含秘密(使用运行时秘密)
- ✅ 最小化攻击面(仅安装所需包)
- ✅ 使用多阶段构建(最终镜像中无构建工具)
- ✅ 签名和验证镜像
- ✅ 保持镜像更新
网络模式
桥接网络(默认)
# 创建自定义桥接网络
docker network create my-bridge
# 在自定义桥接上运行容器
docker run -d --name web --network my-bridge nginx
docker run -d --name db --network my-bridge postgres
# 容器可以通过容器名称通信
# web可以连接到:http://db:5432
容器通信
services:
web:
depends_on:
- db
environment:
# 使用服务名称作为主机名
- DATABASE_URL=postgresql://user:pass@db:5432/app
db:
image: postgres:15-alpine
端口发布
# 发布单个端口
docker run -p 8080:80 nginx
# 发布端口范围
docker run -p 8080-8090:8080-8090 myapp
# 发布到特定接口
docker run -p 127.0.0.1:8080:80 nginx
# 将所有暴露端口发布到随机端口
docker run -P nginx
存储模式
命名卷(推荐用于数据)
# 创建并使用命名卷
docker volume create app-data
docker run -v app-data:/app/data myapp
# 自动创建
docker run -v app-data:/app/data myapp # 如果不存在则创建
绑定挂载(开发)
# 开发期间实时代码重载
docker run -v $(pwd)/src:/app/src myapp
# 只读绑定挂载
docker run -v $(pwd)/config:/app/config:ro myapp
tmpfs挂载(临时内存)
# 在内存中存储临时数据
docker run --tmpfs /tmp myapp
卷备份与恢复
# 备份卷
docker run --rm -v app-data:/data -v $(pwd):/backup alpine \
tar czf /backup/backup.tar.gz /data
# 恢复卷
docker run --rm -v app-data:/data -v $(pwd):/backup alpine \
tar xzf /backup/backup.tar.gz -C /data
故障排查
调试运行容器
# 查看日志
docker logs -f myapp
docker logs --tail 100 myapp
# 交互式shell
docker exec -it myapp /bin/sh
# 检查容器
docker inspect myapp
# 查看进程
docker top myapp
# 监控资源使用情况
docker stats myapp
# 查看文件系统更改
docker diff myapp
调试构建问题
# 构建并显示详细输出
docker build --progress=plain -t myapp .
# 构建特定阶段进行测试
docker build --target build -t myapp:build .
# 运行失败的构建阶段
docker run -it myapp:build /bin/sh
# 检查构建上下文
docker build --no-cache -t myapp .
常见问题
容器立即退出:
# 检查日志
docker logs myapp
# 以交互式shell运行
docker run -it myapp /bin/sh
# 覆盖入口点
docker run -it --entrypoint /bin/sh myapp
无法连接到容器:
# 检查端口映射
docker ps
docker port myapp
# 检查网络
docker network inspect bridge
docker inspect myapp | grep IPAddress
# 检查服务是否监听
docker exec myapp netstat -tulpn
磁盘空间不足:
# 检查磁盘使用情况
docker system df
# 清理
docker system prune -a
docker volume prune
docker image prune -a
构建缓存问题:
# 强制重建,无缓存
docker build --no-cache -t myapp .
# 清除构建缓存
docker builder prune
高级主题
多平台构建
# 设置buildx
docker buildx create --use
# 为多平台构建
docker buildx build --platform linux/amd64,linux/arm64 \
-t myapp:1.0 --push .
构建优化
# 使用BuildKit(在最近版本中默认启用)
DOCKER_BUILDKIT=1 docker build -t myapp .
# 使用注册表中的构建缓存
docker build --cache-from myapp:latest -t myapp:1.0 .
# 将缓存导出到注册表
docker build --cache-to type=registry,ref=myapp:buildcache \
--cache-from type=registry,ref=myapp:buildcache \
-t myapp:1.0 .
Docker上下文
# 列出上下文
docker context ls
# 创建远程上下文
docker context create remote --docker "host=ssh://user@remote"
# 使用上下文
docker context use remote
docker ps # 现在在远程主机上运行
# 切换回默认
docker context use default
快速参考
最常用命令
| 任务 | 命令 |
|---|---|
| 构建镜像 | docker build -t myapp:1.0 . |
| 运行容器 | docker run -d -p 8080:3000 myapp:1.0 |
| 查看日志 | docker logs -f myapp |
| Shell进入容器 | docker exec -it myapp /bin/sh |
| 停止容器 | docker stop myapp |
| 移除容器 | docker rm myapp |
| 启动Compose | docker compose up -d |
| 停止Compose | docker compose down |
| 查看Compose日志 | docker compose logs -f |
| 清理所有 | docker system prune -a |
推荐基础镜像
| 语言/框架 | 推荐基础 |
|---|---|
| Node.js | node:20-alpine |
| Python | python:3.11-slim |
| Java | eclipse-temurin:21-jre-alpine |
| Go | scratch(用于编译二进制) |
| .NET | mcr.microsoft.com/dotnet/aspnet:8.0-alpine |
| PHP | php:8.2-fpm-alpine |
| Ruby | ruby:3.2-alpine |
| 静态站点 | nginx:alpine |
额外资源
- 官方文档: https://docs.docker.com
- Docker Hub: https://hub.docker.com(公共镜像注册表)
- 最佳实践: https://docs.docker.com/develop/dev-best-practices/
- 安全: https://docs.docker.com/engine/security/
- Dockerfile参考: https://docs.docker.com/engine/reference/builder/
- Compose规范: https://docs.docker.com/compose/compose-file/
总结
Docker容器化提供:
- 一致性 跨开发、测试和生产环境
- 隔离 用于应用程序和依赖项
- 可移植性 跨不同环境
- 效率 通过分层架构和缓存
- 可扩展性 用于微服务和分布式系统
遵循多阶段构建、以非root运行、使用特定版本、实施健康检查、扫描漏洞、配置资源限制以实现生产就绪的容器化应用程序。