引言
Docker 已经成为现代软件开发和部署的标准工具。无论是个人项目还是企业级应用,容器化都能带来环境一致性、快速部署和资源隔离的巨大优势。本文将带你从基础概念到生产环境实践,全面掌握 Docker 容器化技术。
一、Docker 核心概念
在深入实践之前,我们需要理解几个核心概念:
- 镜像(Image):只读模板,包含运行应用所需的代码、运行时、库和配置
- 容器(Container):镜像的运行实例,可创建、启动、停止和删除
- Dockerfile:构建镜像的脚本,定义镜像的层叠结构
- 卷(Volume):持久化存储,用于容器间数据共享
二、编写高效的 Dockerfile
一个优化的 Dockerfile 能显著减少镜像大小和构建时间。以下是一个 Node.js 应用的最佳实践示例:
# 使用多阶段构建减少最终镜像大小
FROM node:18-alpine AS builder
# 设置工作目录
WORKDIR /app
# 先复制 package 文件,利用 Docker 缓存层
COPY package*.json ./
RUN npm ci --only=production
# 复制源代码
COPY . .
# 构建应用(如果有构建步骤)
RUN npm run build
# 生产阶段
FROM node:18-alpine
# 创建非 root 用户运行应用
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# 从 builder 阶段复制构建结果
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
# 切换到非 root 用户
USER nodejs
# 暴露端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
# 启动应用
CMD ["node", "dist/index.js"]
三、Docker Compose 多容器编排
实际项目通常包含多个服务(应用、数据库、缓存等)。Docker Compose 可以简化多容器管理:
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d myapp"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- app-network
restart: unless-stopped
volumes:
postgres-data:
redis-data:
networks:
app-network:
driver: bridge
四、生产环境最佳实践
1. 镜像安全
- 使用官方基础镜像或可信来源
- 定期更新基础镜像修复安全漏洞
- 使用多阶段构建减少攻击面
- 不以 root 用户运行容器
2. 日志管理
容器日志应该输出到 stdout/stderr,便于集中收集:
// 使用结构化日志
const winston = require('winston');
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console()
]
});
3. 资源限制
在生产环境中限制容器资源使用:
services:
app:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
五、CI/CD 集成
将 Docker 集成到 CI/CD 流水线实现自动化部署:
# GitHub Actions 示例
name: Docker Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myapp:${{ github.sha }},myapp:latest
cache-from: type=registry,ref=myapp:buildcache
cache-to: type=registry,ref=myapp:buildcache,mode=max
六、常见问题排查
容器无法启动
# 查看容器日志
docker logs <container-id>
# 进入容器调试
docker exec -it <container-id> /bin/sh
# 检查容器状态
docker inspect <container-id>
网络连接问题
# 查看网络配置
docker network ls
docker network inspect app-network
# 测试容器间连接
docker exec app-container ping db
结语
Docker 容器化是现代开发者的必备技能。通过遵循本文的最佳实践,你可以构建安全、高效、可维护的容器化应用。记住,容器化不仅仅是打包应用,更是一种思维方式的转变——将基础设施视为代码,实现真正的 DevOps 文化。
开始你的容器化之旅吧,从今天的一个 Dockerfile 开始!
文章评论