我的一次Docker容器化部署实战踩坑实录耗时3周前不久接了一个项目客户是一家中小型电商公司他们的系统部署全靠手动操作经常出现环境问题导致发布延迟。我决定帮他们搭建Docker容器化部署从手动部署过渡到自动化流水线。手动部署的痛点与决策客户的生产环境是几台Linux服务器每次发布都要运维手动打包、上传、重启服务。说实话这种模式效率极低而且容易出错。有一次因为环境变量配置错误整个系统挂了两个小时客户投诉不断。更头疼的是开发环境和生产环境不一致代码在本地跑得好好的上线就报错。客户希望我们能实现自动化构建和部署减少人为干预。当时我面临两个方案一是直接上Kubernetes集群二是用Docker加Jenkins搭建CI/CD流水线。说实话K8s虽然强大但学习成本高运维复杂而且客户团队只有三个人没有专门负责K8s的运维。试了一圈发现Docker加Jenkins更轻量能快速实现自动化成本也低。我选了方案B因为项目规模不大快速落地更重要。另外客户预算有限K8s的硬件成本也高Docker方案更经济。容器化与流水线搭建我开始写Dockerfile把应用打包成镜像。核心代码如下dockerfileFROM openjdk:11-jre-slimWORKDIR /appCOPY target/*.jar app.jarEXPOSE 8080ENTRYPOINT [java,-jar,/app/app.jar]有意思的是我发现用slim镜像能减少镜像大小但有些依赖包在slim版本里缺失导致应用启动失败。当时我觉得这样就行结果发现错了。后来换成openjdk:11-jdk-slim问题解决。另外我还添加了多阶段构建进一步压缩镜像体积dockerfileFROM maven:3.8.4-openjdk-11 AS buildWORKDIR /appCOPY pom.xml .COPY src ./srcRUN mvn clean package -DskipTestsFROM openjdk:11-jre-slimWORKDIR /appCOPY --frombuild /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT [java,-jar,/app/app.jar]接着配置Jenkins流水线。Jenkinsfile内容如下groovypipeline {agent anystages {stage(Checkout) {steps {checkout scm}}stage(Build) {steps {sh mvn clean package -DskipTests}}stage(Docker Build) {steps {sh docker build -t myapp:${BUILD_NUMBER} .}}stage(Deploy) {steps {sh docker stop myapp || true docker rm myapp || truesh docker run -d -p 8080:8080 --name myapp myapp:${BUILD_NUMBER}}}}}坑死了Jenkins在部署阶段执行docker命令时总是报权限错误。排查后发现Jenkins用户不在docker组里。解决办法是给Jenkins用户添加docker组权限sudo usermod -aG docker jenkins然后重启Jenkins服务。另外我还配置了SSH免密登录让Jenkins能安全地部署到多台服务器。为了管理多容器应用我引入了docker-compose。docker-compose.yml配置yamlversion: 3.8services:app:image: myapp:latestports:8080:8080depends_on:dbredisenvironment:DB_HOSTdbREDIS_HOSTredisdb:image: mysql:8.0environment:MYSQL_ROOT_PASSWORD: rootMYSQL_DATABASE: mydbvolumes:db_data:/var/lib/mysqlredis:image: redis:alpinevolumes:redis_data:/datavolumes:db_data:redis_data:部署时一条命令docker-compose up -d就能拉起所有服务。这比手动启动容器方便多了。我还配置了Jenkins流水线调用docker-compose实现一键部署。配置Jenkins时我安装了Docker插件和Pipeline插件。还配置了Docker Registry凭证避免每次拉取镜像都要登录。在Jenkins系统配置里我添加了Docker服务器地址和认证信息这样流水线就能自动推送镜像到私有仓库。Docker网络方面为了让容器间通信我创建了自定义网络docker network create myapp-network。然后在docker-compose.yml中指定网络yamlnetworks:default:external:name: myapp-network这样app、db、redis容器都在同一网络可以通过服务名互相访问。性能上我发现容器启动慢后来发现是Java应用初始化慢。通过调整JVM参数比如-Xms256m -Xmx512m并优化镜像层顺序把依赖安装和应用代码分离提升了构建和启动速度。经过三周的努力系统终于实现了自动化构建、测试和部署。发布频率从每周一次提升到每天多次环境一致性问题也消失了。说实话这次实战让我深刻体会到容器化部署的价值虽然踩了不少坑但收获很大。本文基于实际项目经验整理欢迎在评论区交流技术问题。