我把公司项目塞进 Docker 后踩的那些坑

admin 发布于 14 小时前 5 次阅读


Docker 容器化部署已成为现代应用开发和运维的标准实践。通过将应用及其依赖打包到轻量级容器中,Docker 解决了"在我机器上能运行"的经典问题,实现了跨环境的一致性部署。本文将带你深入了解 Docker 容器化部署的核心概念、最佳实践和生产环境应用技巧,帮助你快速掌握这项关键技术。

什么是 Docker 容器化部署

Docker 容器化是一种轻量级虚拟化技术,它将应用程序及其所有依赖项(库、配置文件、环境变量)打包成独立的容器镜像。与传统虚拟机相比,Docker 容器共享宿主机的操作系统内核,启动速度更快,资源占用更少。

容器化部署的核心优势包括:

  • 环境一致性:开发、测试、生产环境完全相同
  • 快速部署:秒级启动,支持快速扩缩容
  • 资源隔离:每个容器独立运行,互不干扰
  • 版本管理:镜像支持版本控制和回滚

编写高效的 Dockerfile

Dockerfile 是构建 Docker 镜像的核心文件。一个优化的 Dockerfile 能显著减小镜像体积,提升构建速度。以下是一个 Node.js 应用的最佳实践示例:

# 使用多阶段构建减小镜像体积
FROM node:18-alpine AS builder

WORKDIR /app

# 先复制依赖文件,利用缓存层
COPY package*.json ./
RUN npm ci --only=production

# 再复制源代码
COPY . .
RUN npm run build

# 生产环境镜像
FROM node:18-alpine

WORKDIR /app

# 创建非 root 用户提升安全性
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules

USER nodejs

EXPOSE 3000

CMD ["node", "dist/index.js"]

Dockerfile 优化技巧

  • 使用 Alpine 基础镜像:体积仅 5MB,大幅减小最终镜像大小
  • 多阶段构建:分离构建环境和运行环境,只保留必要文件
  • 合理排序指令:将变化频率低的指令放前面,充分利用缓存
  • .dockerignore 文件:排除不必要的文件,加快构建速度

Docker Compose 编排多容器应用

实际项目通常包含多个服务(应用、数据库、缓存等),Docker Compose 让你通过一个 YAML 文件管理整个应用栈。以下是一个完整的 Web 应用示例:

version: '3.8'

services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache
    restart: unless-stopped
    networks:
      - app-network

  db:
    image: postgres:15-alpine
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    networks:
      - app-network

  cache:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    networks:
      - app-network

volumes:
  postgres-data:
  redis-data:

networks:
  app-network:
    driver: bridge

使用 Docker Compose 部署应用只需一条命令:

# 启动所有服务
docker-compose up -d

# 查看运行状态
docker-compose ps

# 查看日志
docker-compose logs -f web

# 停止并删除容器
docker-compose down

生产环境部署最佳实践

健康检查配置

为容器添加健康检查,确保服务真正可用:

HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD node healthcheck.js || exit 1

资源限制

在 docker-compose.yml 中限制容器资源使用:

services:
  web:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

日志管理

配置日志驱动,避免日志文件无限增长:

services:
  web:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

常见问题与解决方案

问题 1:镜像体积过大

解决方案:使用多阶段构建、Alpine 基础镜像,清理不必要的缓存文件。在 RUN 指令中使用 && rm -rf /var/cache/apk/* 清理包管理器缓存。

问题 2:容器内时区不正确

解决方案:在 Dockerfile 中设置时区环境变量:

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

问题 3:数据持久化

解决方案:使用 Docker 卷(volumes)而非绑定挂载,确保数据在容器重启后保留。

总结

Docker 容器化部署通过标准化应用打包和运行方式,极大简化了开发到生产的整个流程。掌握 Dockerfile 编写、Docker Compose 编排和生产环境最佳实践,你就能构建高效、可靠的容器化应用。

从编写优化的 Dockerfile 开始,逐步实践多容器编排,最终应用到生产环境——这个过程会让你深刻体会到容器化技术的强大之处。你在 Docker 部署中遇到过哪些挑战?欢迎在评论区分享你的经验和问题。