容器化部署最佳实践:从 Docker 到 Kubernetes

2026-02-06 09:00:00 · 3 minute read

在过去几年的开发实践中,容器化技术已经从实验性工具变为现代应用部署的行业标准。从单机 Docker 到 Kubernetes 集群,容器化彻底改变了我们构建、部署和运行应用的方式。今天,我想分享一些在实际项目中总结的最佳实践。

Docker:单机容器的黄金法则

1. 保持镜像轻量化

最常见的错误是在 Dockerfile 中使用 FROM ubuntu:latest 作为基础镜像,然后通过 apt-get 安装所有依赖。这会导致镜像体积巨大,启动缓慢,安全风险增加。

更好的做法是使用 Alpine Linux 作为基础镜像,它只有约 5MB,并且经过安全加固。

# 好的做法
FROM alpine:3.19
RUN apk add --no-cache python3 py3-pip
COPY . /app
WORKDIR /app
CMD ["python3", "app.py"]

2. 利用构建缓存

Docker 的分层缓存机制可以大大加速构建过程,但前提是 Dockerfile 的指令顺序合理。将不常变化的指令放在前面,常变化的放在后面。

# 好的做法
FROM node:18-alpine AS builder
WORKDIR /app
# 先复制依赖文件,这样可以缓存依赖安装
COPY package*.json ./
RUN npm ci --only=production
# 再复制源码
COPY . .
RUN npm run build

3. 多阶段构建

多阶段构建可以将构建环境和运行环境分离,避免将编译工具和源码包含在最终镜像中。

# 构建阶段
FROM golang:1.21-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o app

# 运行阶段
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
COPY --from=builder /src/app /usr/local/bin/app
CMD ["app"]

4. 使用 .dockerignore

.dockerignore 文件可以排除不需要复制到镜像中的文件,减少上下文大小,加快构建速度。

.git
.gitignore
node_modules
*.log
.env
.DS_Store

Kubernetes:集群部署的核心原则

1. 健康检查和就绪检查

为 Pod 定义健康检查(livenessProbe)和就绪检查(readinessProbe),让 Kubernetes 能够自动恢复异常 Pod,并确保流量只发送到就绪的 Pod。

apiVersion: v1
kind: Pod
metadata:
  name: myapp
spec:
  containers:
  - name: myapp
    image: myapp:1.0
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

2. 资源限制和请求

为容器设置合理的资源请求(requests)和限制(limits),避免资源争抢,提高集群稳定性。

resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"

3. 使用 ConfigMap 和 Secret

将配置信息与容器镜像分离,使用 ConfigMap 管理普通配置,Secret 管理敏感信息(如密码、密钥)。

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  database.url: "postgres://db:5432/myapp"
  cache.ttl: "3600"
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  database.password: cGFzc3dvcmQxMjM=

4. 使用 Deployment 而非直接管理 Pod

Deployment 提供了声明式更新、回滚、自动扩缩容等功能,应该使用 Deployment 管理 Pod,而不是直接创建 Pod。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0
        ports:
        - containerPort: 8080

DevOps 流水线整合

1. CI/CD 自动化

将容器化构建集成到 CI/CD 流水线中,实现自动化测试和部署。使用 GitLab CI、GitHub Actions 或 Jenkins 等工具。

# .github/workflows/deploy.yml
name: Deploy to Kubernetes
on:
  push:
    branches: [ main ]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Build Docker image
      run: docker build -t myapp:${{ github.sha }} .
    - name: Push to registry
      run: |
        echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
        docker push myapp:${{ github.sha }}
    - name: Deploy to Kubernetes
      run: |
        kubectl set image deployment/myapp myapp=myapp:${{ github.sha }}
        kubectl rollout status deployment/myapp

2. 镜像版本管理

使用语义化版本(Semantic Versioning)或 Git 提交哈希来标记镜像版本,避免使用 latest 标签导致的部署不确定性。

# 好的做法
docker build -t myapp:1.2.3 .
docker push myapp:1.2.3

# 或者使用 Git 提交哈希
IMAGE_TAG=$(git rev-parse --short HEAD)
docker build -t myapp:${IMAGE_TAG} .

3. 安全扫描

定期扫描镜像中的安全漏洞,使用 Trivy、Grype 或 Clair 等工具。

# 扫描镜像漏洞
trivy image myapp:1.2.3

# 在 CI 流水线中集成
- name: Scan for vulnerabilities
  run: |
    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
      aquasec/trivy image myapp:${{ github.sha }} \
      --exit-code 1 --severity HIGH,CRITICAL

监控和日志

1. 集中式日志收集

使用 Fluentd、Filebeat 或 Loki 等工具收集容器日志,集中存储在 Elasticsearch 或 Loki 中,方便查询和分析。

2. 指标监控

使用 Prometheus + Grafana 监控容器和集群指标,包括 CPU、内存、网络、磁盘使用率,以及应用自定义指标。

3. 分布式追踪

使用 Jaeger、Zipkin 或 OpenTelemetry 实现分布式追踪,帮助定位跨服务调用链中的性能瓶颈和错误。

常见陷阱

1. 在容器中存储持久数据

容器是临时的,不应该用于存储持久数据。使用 Kubernetes 的 PersistentVolumeClaim 或外部数据库。

2. 忽视网络策略

默认情况下,Kubernetes 集群中的所有 Pod 可以互相访问。使用 NetworkPolicy 限制网络流量,提高安全性。

3. 过度使用 latest 标签

在生产环境中避免使用 latest 标签,因为无法确定它指向的具体版本。

4. 单体容器反模式

一个容器应该只运行一个进程。尝试在一个容器中运行多个服务(如 Nginx + PHP-FPM)会增加复杂性,违反容器的设计理念。

总结

容器化技术为现代应用部署带来了巨大便利,但要充分发挥其优势,需要遵循最佳实践。从 Docker 的镜像构建,到 Kubernetes 的集群管理,再到 CI/CD 流水线整合,每个环节都有需要注意的细节。

记住这些黄金法则:保持镜像轻量化、合理利用缓存、定义健康检查、设置资源限制、使用配置管理、自动化构建部署、关注安全、做好监控日志。

容器化之旅漫长而充实,持续学习和实践是掌握这门技术的唯一途径。希望这些实践经验能够帮助你在项目中更好地应用容器化技术,构建更稳定、高效的应用系统。

参考资源:

已复制