前言
"这代码在我本地没问题啊!"------这句话几乎是每个开发团队的经典梗。Docker的出现彻底终结了这个问题,通过容器化让开发、测试、生产环境完全一致。
这篇文章分享我们团队Docker落地的实战经验。
一、核心概念速览
镜像(Image):
只读模板,相当于"安装包"
通过Dockerfile构建
容器(Container):
镜像运行的实例,相当于"运行中的程序"
可以启动、停止、删除
仓库(Registry):
存储镜像的地方
公共:Docker Hub
私有:Harbor、阿里云ACR
核心关系:
Dockerfile → 构建 → Image → 运行 → Container
二、Dockerfile最佳实践
2.1 Node.js项目示例
dockerfile
# ✅ 使用精确版本,避免镜像漂移
FROM node:18.17-alpine
# 设置工作目录
WORKDIR /app
# ✅ 先复制依赖文件,利用构建缓存
# 只有package.json变化才重新安装依赖
COPY package*.json ./
RUN npm ci --only=production
# 再复制源代码
COPY . .
# ✅ 非root用户运行,提升安全性
USER node
# 暴露端口(仅文档作用)
EXPOSE 3000
# 启动命令
CMD ["node", "server.js"]
2.2 多阶段构建(减小镜像体积)
dockerfile
# ===== 构建阶段 =====
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
# 构建产物(React/Vue等前端项目)
RUN npm run build
# ===== 生产阶段 =====
FROM nginx:alpine AS production
# 仅复制构建产物,不含源码和node_modules
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# 效果:镜像从 1.2GB → 23MB !
2.3 Java项目示例
dockerfile
# 构建阶段
FROM maven:3.9-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml .
# ✅ 先下载依赖,利用缓存
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段
FROM openjdk:17-jre-slim
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
# JVM内存参数
ENV JAVA_OPTS="-Xms256m -Xmx512m"
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
三、Docker Compose多服务编排
3.1 完整项目编排
yaml
# docker-compose.yml
version: '3.8'
services:
# 后端服务
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DB_HOST=mysql
- REDIS_HOST=redis
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
restart: unless-stopped
# 前端服务
frontend:
build:
context: ./frontend
ports:
- "80:80"
depends_on:
- backend
networks:
- app-network
# MySQL数据库
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: myapp
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
- ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# Redis缓存
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
networks:
- app-network
# Nginx反向代理
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- frontend
- backend
networks:
- app-network
volumes:
mysql_data:
redis_data:
networks:
app-network:
driver: bridge
3.2 多环境配置分离
yaml
# docker-compose.dev.yml(开发环境覆盖)
version: '3.8'
services:
backend:
volumes:
# 挂载源码,支持热重载
- ./backend:/app
environment:
- NODE_ENV=development
command: npm run dev
mysql:
ports:
# 开发环境暴露端口,方便本地工具连接
- "3306:3306"
bash
# 开发环境启动
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# 生产环境启动
docker compose up -d
四、常用命令速查
bash
# ===== 镜像管理 =====
docker build -t myapp:1.0 . # 构建镜像
docker images # 查看本地镜像
docker pull nginx:alpine # 拉取镜像
docker push myregistry/myapp:1.0 # 推送镜像
docker rmi myapp:1.0 # 删除镜像
# ===== 容器管理 =====
docker run -d -p 3000:3000 myapp # 后台运行容器
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器
docker stop <container_id> # 停止容器
docker rm <container_id> # 删除容器
docker logs -f <container_id> # 查看实时日志
docker exec -it <container_id> sh # 进入容器终端
# ===== Docker Compose =====
docker compose up -d # 启动所有服务
docker compose down # 停止并删除容器
docker compose logs -f backend # 查看指定服务日志
docker compose restart backend # 重启指定服务
docker compose ps # 查看服务状态
# ===== 清理资源 =====
docker system prune -a # 清理所有无用资源
docker volume prune # 清理无用数据卷
docker image prune # 清理悬空镜像
五、生产环境优化
5.1 健康检查
dockerfile
# Dockerfile中配置健康检查
HEALTHCHECK --interval=30s \
--timeout=10s \
--start-period=15s \
--retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
javascript
// 健康检查接口
app.get('/health', (req, res) => {
res.json({
status: 'ok',
uptime: process.uptime(),
timestamp: Date.now()
});
});
5.2 资源限制
yaml
# docker-compose.yml 中配置资源上限
services:
backend:
deploy:
resources:
limits:
cpus: '1.0' # 最多使用1核CPU
memory: 512M # 最多使用512MB内存
reservations:
cpus: '0.5'
memory: 256M
5.3 日志管理
yaml
services:
backend:
logging:
driver: "json-file"
options:
max-size: "100m" # 单个日志文件最大100MB
max-file: "5" # 最多保留5个日志文件
六、私有镜像仓库(Harbor)
bash
# 安装Harbor(企业私有仓库)
wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-online-installer-v2.9.0.tgz
tar xvf harbor-online-installer-v2.9.0.tgz
cd harbor
# 修改配置
cp harbor.yml.tmpl harbor.yml
# 修改 hostname、https证书、admin密码
# 安装启动
./install.sh
# 推送镜像到私有仓库
docker login harbor.mycompany.com
docker tag myapp:1.0 harbor.mycompany.com/project/myapp:1.0
docker push harbor.mycompany.com/project/myapp:1.0
七、团队协作
我们后端和运维团队在容器化改造期间经常需要对接,技术细节沟通多且精度要求高。其中有几位海外工程师参与方案评审,会议全程借助**同言翻译(Transync AI)**做实时语音翻译,技术讨论效率明显提升,再也没出现因理解偏差导致配置出错的情况。
八、最佳实践检查清单
□ Dockerfile使用精确版本号,不用latest
□ 使用多阶段构建,控制镜像体积
□ 以非root用户运行容器
□ 敏感信息通过环境变量或Secret传入
□ 配置健康检查
□ 设置资源使用上限
□ 日志文件配置轮转策略
□ 生产环境使用私有镜像仓库
□ 数据库等有状态服务挂载数据卷
□ 定期清理无用镜像和容器
总结
Docker容器化的核心价值:
- 🚀 环境一致性:彻底告别环境差异导致的问题
- ⚡ 快速部署:秒级启动,弹性伸缩
- 🔒 资源隔离:各服务互不干扰
- 📦 标准交付:镜像即制品,随处可运行
从写好第一个Dockerfile开始,逐步演进到Compose多服务编排,再结合CI/CD实现全自动化交付------这套体系是现代后端工程师的必备技能。

