CI/CD流水线的核心环节
一条完整的CI/CD流水线覆盖代码提交到生产发布全流程:代码检出到单元测试到构建Docker镜像到推送镜像仓库到部署到目标环境。用Jenkins + Docker Registry + Shell脚本即可搭建一套轻量但可靠的自动化部署体系。
Jenkins环境与Docker Registry准备
Jenkins推荐用Docker方式部署,避免污染宿主环境:
# 部署Jenkins
docker run -d --name jenkins \
-p 8080:8080 -p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
--restart=always jenkins/jenkins:lts
# 部署私有Docker Registry
docker run -d --name registry \
-p 5000:5000 \
-v registry_data:/var/lib/registry \
--restart=always registry:2
Jenkins容器挂载Docker.sock是关键操作,这样Jenkins任务才能直接执行docker build和docker push。
项目Dockerfile编写规范
Spring Boot项目的多阶段构建Dockerfile:
# 构建阶段
FROM eclipse-temurin:17-jdk AS builder
WORKDIR /build
COPY pom.xml .
COPY src ./src
RUN ./mvnw package -DskipTests
# 运行阶段
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=builder /build/target/*.jar app.jar
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
多阶段构建让最终镜像只包含JRE和jar包,体积从700MB+降到200MB左右。不要把Maven缓存和源码打进运行镜像。
Jenkins Pipeline脚本:自动化构建与部署
在项目根目录创建Jenkinsfile:
pipeline {
agent any
environment {
REGISTRY = '192.168.1.100:5000'
IMAGE_NAME = "${REGISTRY}/${JOB_NAME}"
TAG = "${BUILD_NUMBER}"
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://git.example.com/project.git'
}
}
stage('Test') {
steps {
sh './mvnw test'
}
}
stage('Build Image') {
steps {
sh "docker build -t ${IMAGE_NAME}:${TAG} ."
sh "docker tag ${IMAGE_NAME}:${TAG} ${IMAGE_NAME}:latest"
}
}
stage('Push Registry') {
steps {
sh "docker push ${IMAGE_NAME}:${TAG}"
sh "docker push ${IMAGE_NAME}:latest"
}
}
stage('Deploy') {
steps {
sh """
ssh deploy@prod-server \
"docker pull ${IMAGE_NAME}:${TAG} && \
docker stop ${JOB_NAME} || true && \
docker rm ${JOB_NAME} || true && \
docker run -d --name ${JOB_NAME} \
-p 8080:8080 \
--restart=always \
${IMAGE_NAME}:${TAG}"
"""
}
}
}
post {
failure {
echo 'Pipeline failed, check logs above'
}
success {
echo "Deployed ${IMAGE_NAME}:${TAG} successfully"
}
}
}
回滚策略:每个版本都有迹可查
每次部署用BUILD_NUMBER做镜像Tag,回滚只需拉取上一个Tag重新run:
# 查看历史镜像Tag
docker images 192.168.1.100:5000/myapp --format "{{.Tag}} {{.CreatedAt}}"
# 回滚到指定版本
ssh deploy@prod-server "docker pull 192.168.1.100:5000/myapp:28 && \
docker stop myapp && docker rm myapp && \
docker run -d --name myapp -p 8080:8080 \
--restart=always 192.168.1.100:5000/myapp:28"
保留最近10个版本的镜像,定期清理更早的Tag。私有Registry配合垃圾回收释放磁盘空间:
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
健康检查与自动重启
在docker run中加入健康检查,异常退出时自动恢复:
docker run -d --name myapp \
-p 8080:8080 \
--health-cmd="curl -f http://localhost:8080/actuator/health || exit 1" \
--health-interval=30s \
--health-retries=3 \
--health-timeout=10s \
--restart=always \
192.168.1.100:5000/myapp:latest
三次健康检查失败后容器状态变为unhealthy,配合–restart=always策略,Docker守护进程会自动重启容器。配合Prometheus监控告警,实现故障秒级发现。
常见问题处理
Q: docker push到私有Registry报TLS错误?
在客户端/etc/docker/daemon.json中添加insecure-registries配置,然后重启dockerd。
Q: Jenkins构建时docker命令权限不够?
把jenkins用户加入docker用户组:usermod -aG docker jenkins,然后重启Jenkins容器。
Q: 镜像体积太大推送超时?
检查是否误把node_modules或target目录打入镜像,.dockerignore文件排除构建缓存目录。切换到多阶段构建后体积会大幅缩小。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/docker-zi-dong-hua-bu-shu-shi-zhan-cong-git-ti-jiao-dao/