当前位置:首页 > 学习笔记 > 正文内容

Docker 部署最佳实践实战指南:从入门到精通

廖万里15小时前学习笔记1

Docker 是现代应用部署的核心工具,它通过容器化技术实现了"一次构建,到处运行"。本文将从零开始,系统讲解 Docker 部署的最佳实践,包括镜像优化、多阶段构建、安全加固、CI/CD 集成等核心内容,帮助你构建生产级别的容器化应用。

一、Docker 核心概念与优势

Docker 是一个开源的容器化平台,它允许开发者将应用及其依赖打包到一个轻量级、可移植的容器中。与传统的虚拟机相比,Docker 容器共享宿主机的操作系统内核,启动速度更快,资源占用更少。

1.1 Docker 的核心组件

镜像(Image):只读模板,包含运行应用所需的所有内容——代码、运行时、库、环境变量和配置文件。

容器(Container):镜像的运行实例,是一个轻量级、独立的可执行软件包。

仓库(Registry):存储和分发镜像的地方,如 Docker Hub、阿里云容器镜像服务。

1.2 为什么选择 Docker?

  • 环境一致性:消除"在我机器上能运行"的问题
  • 快速部署:容器启动时间通常在秒级
  • 资源高效:相比虚拟机,容器占用更少资源
  • 微服务友好:天然支持微服务架构
  • DevOps 基石:CI/CD 流程的核心组件

二、Dockerfile 最佳实践

Dockerfile 是构建镜像的蓝图,编写高质量的 Dockerfile 是容器化成功的关键。

2.1 基础镜像选择原则

# ❌ 不推荐:使用大型基础镜像
FROM ubuntu:latest

# ✅ 推荐:使用 Alpine 精简镜像(仅 5MB)
FROM alpine:3.19

# ✅ 对于 Python 应用,推荐使用 slim 版本
FROM python:3.12-slim

# ✅ 对于 Node.js 应用
FROM node:20-alpine

选择建议:

  • 优先选择官方镜像
  • 优先选择 Alpine 或 slim 变体
  • 明确指定版本标签,避免使用 latest

2.2 多阶段构建优化

多阶段构建是减小镜像体积的最有效方法,它允许在一个 Dockerfile 中使用多个 FROM 语句。

# 第一阶段:构建环境
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 -a -installsuffix cgo -o main .

# 第二阶段:运行环境(最终镜像)
FROM alpine:3.19

# 安装 ca-certificates(HTTPS 请求需要)
RUN apk --no-cache add ca-certificates

WORKDIR /root/

# 只复制构建产物
COPY --from=builder /app/main .

# 非 root 用户运行
RUN adduser -D -u 1000 appuser
USER appuser

EXPOSE 8080

CMD ["./main"]

优化效果:Go 应用镜像从 800MB+ 减小到 10MB 以内。

2.3 层缓存优化策略

Docker 构建时会缓存每一层,合理利用缓存可以大幅加速构建过程。

# ❌ 错误示例:频繁变化的代码放在前面
FROM node:20-alpine
WORKDIR /app
COPY . .                    # 任何文件变化都会使缓存失效
RUN npm install
CMD ["npm", "start"]

# ✅ 正确示例:依赖放在代码之前
FROM node:20-alpine
WORKDIR /app

# 先复制依赖描述文件
COPY package*.json ./

# 安装依赖(只有 package.json 变化时才重新执行)
RUN npm ci --only=production

# 最后复制源代码
COPY . .

CMD ["npm", "start"]

2.4 安全最佳实践

FROM python:3.12-slim

# 创建非 root 用户
RUN groupadd -r appuser && useradd -r -g appuser appuser

WORKDIR /app

# 设置合理的文件权限
COPY --chown=appuser:appuser . .

# 不要在镜像中存储敏感信息
# 使用环境变量或 secrets

# 切换到非 root 用户
USER appuser

# 只暴露必要的端口
EXPOSE 8000

# 使用 exec 形式的 CMD
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

三、Docker Compose 编排实战

Docker Compose 是定义和运行多容器应用的工具,通过 YAML 文件配置服务。

3.1 典型 Web 应用编排

version: \"3.8\"

services:
  # Web 前端服务
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - \"8000:8000\"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    networks:
      - frontend
      - backend
    restart: unless-stopped
    healthcheck:
      test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:8000/health\"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  # PostgreSQL 数据库
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - backend
    healthcheck:
      test: [\"CMD-SHELL\", \"pg_isready -U user -d mydb\"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  # Redis 缓存
  cache:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    networks:
      - backend
    restart: unless-stopped

  # Nginx 反向代理
  nginx:
    image: nginx:alpine
    ports:
      - \"80:80\"
      - \"443:443\"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - web
    networks:
      - frontend
    restart: unless-stopped

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

volumes:
  postgres_data:
  redis_data:

3.2 环境变量管理

# .env 文件(不要提交到版本控制)
DATABASE_URL=postgres://user:pass@db:5432/mydb
REDIS_URL=redis://cache:6379
SECRET_KEY=your-secret-key-here
DEBUG=false

# docker-compose.yml 中引用
services:
  web:
    env_file:
      - .env
    environment:
      - NODE_ENV=production

四、生产环境部署策略

4.1 镜像优化技巧

# 使用 .dockerignore 排除不必要的文件
# .dockerignore 文件内容:
# node_modules
# .git
# .env
# *.md
# tests/
# Dockerfile

# 合并 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 \
    && rm -rf /var/cache/apk/*

# 清理缓存
RUN pip install --no-cache-dir -r requirements.txt \
    && rm -rf /root/.cache/pip

4.2 资源限制配置

services:
  web:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: \"2.0\"
          memory: 2G
        reservations:
          cpus: \"0.5\"
          memory: 512M
    ulimits:
      nofile:
        soft: 65536
        hard: 65536

4.3 日志管理

services:
  web:
    image: myapp:latest
    logging:
      driver: \"json-file\"
      options:
        max-size: \"10m\"
        max-file: \"3\"
        labels: \"service,environment\"
        tag: \"{{.Name}}/{{.ID}}\"

五、CI/CD 集成实战

5.1 GitHub Actions 自动化构建

# .github/workflows/docker-build.yml
name: Docker Build and Push

on:
  push:
    branches: [main]
    tags: [\"v*\"]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha,prefix=

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64

5.2 自动化测试集成

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run tests in Docker
        run: |
          docker-compose -f docker-compose.test.yml up --abort-on-container-exit --exit-code-from test
          
      - name: Run security scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          format: \"table\"
          exit-code: \"1\"
          severity: \"CRITICAL,HIGH\"

六、常见问题与解决方案

6.1 容器时区问题

# 方案一:设置环境变量
ENV TZ=Asia/Shanghai

# 方案二:挂载时区文件
docker run -v /etc/localtime:/etc/localtime:ro myapp

# 方案三:在 Alpine 中安装 tzdata
RUN apk add --no-cache tzdata \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

6.2 权限问题

# 容器内访问宿主机文件
docker run -u $(id -u):$(id -g) -v /host/path:/container/path myapp

# 修复已存在文件的权限
docker exec container chown -R appuser:appuser /app/data

6.3 网络调试技巧

# 查看容器网络
docker network ls
docker network inspect bridge

# 进入容器调试网络
docker exec -it container sh
apk add curl net-tools  # Alpine
curl http://service-name:port/health

# 查看容器 IP
docker inspect -f \"{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}\" container

总结

Docker 部署的最佳实践可以归纳为以下核心原则:

  1. 镜像精简:使用 Alpine/slim 基础镜像,多阶段构建,减少镜像层数
  2. 安全优先:非 root 用户运行,不存储敏感信息,定期安全扫描
  3. 缓存优化:合理安排 Dockerfile 指令顺序,利用构建缓存
  4. 资源管控:设置 CPU、内存限制,配置健康检查和重启策略
  5. 自动化:集成 CI/CD 流水线,实现自动构建、测试、部署

掌握这些实践,你的容器化应用将更加健壮、高效、安全。Docker 的学习是一个持续的过程,建议在实践中不断探索更多高级特性,如 Docker Swarm、Kubernetes 集成等。

本文链接:https://www.kkkliao.cn/?id=928 转载需授权!

分享到:

版权声明:本文由廖万里的博客发布,如需转载请注明出处。


发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。