Docker 最佳实践
目录
快速入门
安装与版本
当前使用版本为 Docker 29.4。
macOS
Docker Desktop 是 macOS 推荐的方式:
# 使用 Homebrew 安装
brew install --cask docker
# 或下载 Docker Desktop for Mac
# 访问 https://docs.docker.com/desktop/install/mac-install/
# 启动 Docker Desktop
open -a Docker
# 验证安装
docker --version
# 运行 hello world
docker run hello-worldWindows
下载并安装 Docker Desktop for Windows:
# 运行安装程序 Docker Desktop Installer.exe
# 启动 Docker Desktop
docker --version
# 运行 hello world
docker run hello-worldLinux (Ubuntu)
# 更新 apt 包索引
sudo apt update
# 安装必要的前置依赖
sudo apt install -y ca-certificates curl gnupg lsb-release
# 添加 Docker GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# 添加 Docker 仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 验证安装
sudo docker --version
# 运行 hello world(无需 sudo)
sudo usermod -aG docker $USER
docker run hello-worldDockerfile 基础
基本结构
# 基础镜像
FROM python:3.12-slim
# 维护者
LABEL maintainer="[email protected]"
# 工作目录
WORKDIR /app
# 复制文件
COPY requirements.txt .
# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["python", "app.py"]常见指令
| 指令 | 说明 |
|---|---|
FROM |
指定基础镜像 |
RUN |
执行命令 |
COPY |
复制文件 |
ADD |
复制和解压(支持远程 URL) |
WORKDIR |
设置工作目录 |
EXPOSE |
声明端口 |
ENV |
环境变量 |
CMD |
容器启动命令 |
ENTRYPOINT |
入口点 |
多阶段构建
减少镜像大小,只保留运行时需要的内容:
Node.js 示例
# 构建阶段
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
# 运行阶段
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]Go 示例
# 构建阶段
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
# 运行阶段
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"].dockerignore
排除不需要的文件:
# 版本控制
.git
.gitignore
# 依赖
node_modules
__pycache__
*.pyc
# 文档
README.md
docs
# IDE
.vscode
.idea
# 测试
*.test
coverage
# 环境文件
.env
.env.*
# 构建产物
dist
build
*.log镜像优化
使用特定版本标签
# 避免使用 latest(可能导致不确定行为)
FROM node:20-alpine # 指定版本
FROM python:3.12-slim # 使用 slim 变体减小体积合并指令
# 低效
RUN pip install flask
RUN pip install requests
RUN pip install redis
# 高效
RUN pip install flask requests redis顺序优化
# 将不常变化的层放前面
COPY package*.json ./
RUN npm ci
# 经常变化的放后面
COPY . .使用 heredoc
# 更易读的 RUN 指令
RUN <<EOF
apt-get update
apt-get install -y curl
apt-get clean
EOF网络
暴露端口
# 暴露单个端口
EXPOSE 8000
# 暴露多个端口
EXPOSE 8080 8443运行容器
# 映射端口
docker run -p 8080:8000 myapp
# 映射所有暴露的端口
docker run -P myapp数据管理
数据卷
# 创建数据卷
docker volume create mydata
# 运行容器并挂载数据卷
docker run -v mydata:/app/data myapp
# 或使用匿名卷
docker run -v /app/data myapp绑定挂载
# 绑定本地目录
docker run -v $(pwd):/app myapp
# 只读挂载
docker run -v $(pwd):/app:ro myapptmpfs 挂载(内存)
# 将数据存储在内存中
docker run --tmpfs /app/tmp myapp环境变量
设置环境变量
# 构建时设置
ENV NODE_ENV=production
ENV PORT=8080运行时不覆盖
ENV APP_VERSION=1.0.0
# 运行时可以用 -e 覆盖使用 ARG 和 ENV
# ARG 只在构建时生效
ARG APP_ENV=production
# ENV 在构建和运行时都生效
ENV APP_ENV=${APP_ENV}安全最佳实践
避免 root 用户运行
# 创建非 root 用户
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
USER appuser
# 或者使用 numeric UID
USER 1000:1000扫描漏洞
# 使用 Trivy 扫描
brew install trivy
trivy image myapp:latest
# 使用 Docker Scout
docker scout cves myapp:latest健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1安全基础镜像
# 使用官方认证镜像
FROM python:3.12-slim-bookworm
# 或使用 distroless
FROM gcr.io/distroless/nodejs20-debian12Docker Compose
基本配置
# docker-compose.yml
services:
web:
build: .
ports:
- "8000:8000"
environment:
- NODE_ENV=production
volumes:
- ./data:/app/data
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
db_data:调试
进入容器
# 交互式 shell
docker run -it myapp /bin/sh
# 在运行中的容器执行
docker exec -it mycontainer /bin/bash查看日志
# 查看日志
docker logs mycontainer
# 实时跟踪
docker logs -f mycontainer
# 最近日志
docker logs --tail 100 mycontainer检查容器
# 查看运行状态
docker ps
# 查看所有容器(包括停止)
docker ps -a
# 检查容器详细信息
docker inspect mycontainer
# 查看资源使用
docker statsCI/CD 集成
GitHub Actions
# .github/workflows/docker.yml
name: Docker
on:
push:
branches: [main]
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: user/myapp:latest,user/myapp:${{ github.sha }}