Docker 容器化部署实践:从开发到生产环境
2026年7月 · 约15分钟 · 标签:Docker · 容器化 · 部署
最近将一个基于 Spring Boot 的后端服务以及配套的 Nginx 前端从裸机部署迁移到了 Docker 容器化方案。整个过程中遇到了不少问题,也积累了一些经验,在此做个记录。
一、为什么选择 Docker
此前服务直接运行在服务器宿主机上,环境和依赖都需要手动维护,每次换机器或者重装系统都要重新配置一遍。Docker 的核心优势在于环境一致性——开发环境、测试环境、生产环境使用同一份镜像,避免了"在我机器上能跑"的尴尬。
另外,对于需要多服务协作的项目(比如后端 + Redis + PostgreSQL),docker-compose 可以一键拉起所有依赖,比手动启动各个进程方便得多。
二、Dockerfile 编写要点
以一个 Java Spring Boot 项目为例,以下是 Dockerfile 的核心内容:
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
几个需要注意的点:
- 基础镜像选择:推荐使用 alpine 或 slim 版本,体积更小,安全漏洞更少。eclipse-temurin 是 Eclipse 基金会维护的 OpenJDK 构建,质量可靠。
- 分层构建:对于 Maven/Gradle 项目,建议使用多阶段构建(multi-stage build),先在一个镜像中编译,再将产物拷贝到运行镜像,这样可以大幅减小最终镜像体积。
- 非 root 用户:生产环境应当创建专用的运行用户,避免使用 root 运行容器,降低安全风险。
三、docker-compose 多服务编排
项目依赖 PostgreSQL 和 Redis,使用 docker-compose 统一编排:
version: '3.8'
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 10s
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
app:
build: .
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/appdb
SPRING_DATA_REDIS_HOST: redis
ports:
- "8080:8080"
volumes:
pgdata:
redisdata:
这里的 healthcheck 配置很关键。Spring Boot 应用启动时需要数据库已经就绪,通过 depends_on 的 condition: service_healthy 可以确保数据库完全可用后再启动应用,避免应用启动时报数据库连接失败。
四、镜像仓库与 CI/CD 集成
镜像构建好后需要推送到镜像仓库,我使用的是腾讯云 TCR(容器镜像服务)。配合 GitHub Actions,每次推送代码到主分支后自动构建镜像并推送到仓库,然后 SSH 到服务器拉取最新镜像重启容器。
GitHub Actions 工作流中需要注意缓存依赖层,避免每次构建都重新下载 Maven 依赖:
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
五、生产环境注意事项
日志管理
容器默认的日志驱动是 json-file,如果不加限制,长时间运行会占用大量磁盘空间。建议限制日志文件大小和数量:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
健康检查
除了数据库的健康检查,应用本身也应当暴露健康检查接口。Spring Boot Actuator 的 /actuator/health 可以配合 Docker 的 HEALTHCHECK 指令使用。
资源限制
生产环境应当对容器做资源限制,避免某个服务异常占用全部资源:
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
六、踩坑记录
- 时区问题: Alpine 镜像默认时区不是 Asia/Shanghai,需要安装 tzdata 包并设置 TZ 环境变量。
- DNS 解析: 容器内使用自定义网络时,容器名即可互相解析,但需要注意不要在代码中 hardcode IP 地址。
- 数据持久化: 数据库等有状态服务一定要使用 named volume 或 bind mount,容器删除后数据不会丢失。
七、总结
Docker 容器化带来了环境一致性和部署便利性,但也不是银弹。对于简单的单体应用,容器化的收益可能不明显。但一旦项目涉及多服务协作或有 CI/CD 需求,容器化的优势就会体现出来。后续计划引入 Kubernetes 进行更高级的容器编排,届时再做记录分享。