Skip to content

Jenkins流水线与Docker容器化部署

1. 核心结论

这类 Jenkinsfile 本质上是一套 CI/CD 自动化脚本,完成以下链路:

text
GitLab 拉取代码
  -> Maven 编译打包
  -> Docker 构建镜像
  -> 推送到镜像仓库
  -> Jenkins 通过 SSH/Ansible 操作目标服务器
  -> 目标服务器拉取新镜像并重启容器

服务运行服务器不会主动感知新镜像。真正触发部署的是 Jenkins,Jenkins 通过 SSH 私钥和 Ansible 在远程服务器上执行 docker pulldocker rmdocker run 等命令。

2. 三类服务器职责

服务器职责关键能力
GitLab 服务器保存源码、Jenkinsfile、Dockerfile、部署脚本提供代码访问凭据
Jenkins 服务器或 Agent拉代码、编译、构建镜像、推送镜像、触发部署JDK、Maven、Docker CLI、Jenkins Credentials、Ansible
服务运行服务器运行真实业务容器Docker Runtime、可访问镜像仓库、允许 Jenkins SSH 登录

关键点:

  • Jenkins 是发布控制中心。
  • GitLab 只负责代码托管,不负责部署。
  • 服务运行服务器一般是被 Jenkins 远程控制,不是主动监听镜像仓库。

3. 生产与测试流水线差异

项目生产环境测试环境
默认分支maintest
镜像标签prod_1.0.$BUILD_NUMBERtest_1.0.$BUILD_NUMBER
Spring Profileprodtest
目标主机组ansible prod -i deploy/hostsansible test -i deploy/hosts
部署配置依赖宿主机、配置中心或环境变量脚本内显式注入 DB、Redis 等配置
SSH 凭据生产凭据测试凭据

两份 Jenkinsfile 结构基本一致,区别主要是分支、镜像标签、环境变量、部署目标和凭据隔离。

4. Jenkins 流水线阶段说明

4.1 Initialize

初始化构建环境,输出调试信息,确认 Maven、JDK 等工具链可用。

4.2 Pull Code from GitLab

Jenkins 使用 Git 凭据从 GitLab 拉取指定分支代码。

text
Jenkins Credentials -> GitLab 私有仓库 -> Jenkins 工作目录

4.3 Build Docker Image and Push

典型命令逻辑:

shell
mvn -B -DskipTests clean package
cp target/*.jar mpd-bes.jar
docker build -t registry/airdoc/mpd-bes:tag .
docker login registry
docker push registry/airdoc/mpd-bes:tag

前提条件:

  • Jenkins Agent 已安装 JDK 17。
  • Jenkins Agent 已安装 Maven。
  • Jenkins Agent 已安装 Docker CLI。
  • Jenkins Agent 能访问 Docker daemon。
  • Jenkins Agent 能访问私有镜像仓库。

4.4 Deploy

部署阶段通过 sshagent 加载 Jenkins 中保存的 SSH 私钥,再由 Ansible 登录远程服务器执行命令。

典型逻辑:

shell
ansible prod -i deploy/hosts -m shell -a "
  docker login registry &&
  docker pull registry/airdoc/mpd-bes:tag &&
  docker rm -f mpd-bes || true &&
  docker run -d --name mpd-bes --network host registry/airdoc/mpd-bes:tag
"

这里的关键不是 Jenkins 本机运行服务,而是 Jenkins 远程控制服务服务器。

4.5 Test

当前脚本里的 Test 阶段只是占位,建议替换为真实校验:

  • 容器存活检查。
  • /actuator/health/health 健康检查。
  • 核心 API 冒烟测试。
  • 日志关键错误扫描。

4.6 Post Actions

构建成功或失败后执行收尾动作,可用于日志输出、消息通知、审计记录。

5. 为什么 Jenkins 可以完成打包和部署

Jenkins 能完成这件事,依赖四类能力:

能力来源用途
代码访问能力GitLab 凭据拉取源码
构建能力JDK、Maven、Docker编译、打包、构建镜像
镜像仓库访问能力Docker Registry 凭据推送和拉取镜像
服务器远程控制能力SSH 私钥、Ansible在服务服务器执行部署命令

本质逻辑:

text
Jenkins 拥有代码仓库钥匙
Jenkins 拥有镜像仓库钥匙
Jenkins 拥有服务器 SSH 钥匙
所以 Jenkins 能串起完整发布链路

6. 本地镜像推送到 Docker Hub

6.1 构建镜像

shell
docker build -t my-flask-app .

6.2 本地测试

shell
docker run -d -p 5000:5000 --name test-app my-flask-app
curl http://localhost:5000
docker stop test-app
docker rm test-app

6.3 登录 Docker Hub

shell
docker login

如果启用双因素认证,密码位置应填写 Docker Hub Personal Access Token。

6.4 打标签

Docker Hub 镜像名格式:

text
<dockerhub-username>/<repo-name>:<tag>

示例:

shell
docker tag my-flask-app alice/my-flask-app:v1

6.5 推送镜像

shell
docker push alice/my-flask-app:v1

7. 服务器拉取并运行 Docker Hub 镜像

7.1 登录服务器

shell
ssh user@your-server-ip

7.2 确认 Docker 可用

shell
docker --version

Ubuntu 安装示例:

shell
sudo apt update
sudo apt install docker.io -y
sudo usermod -aG docker $USER

重新登录后,用户组变更才会生效。

7.3 拉取镜像

shell
docker pull alice/my-flask-app:v1

7.4 运行容器

shell
docker run -d -p 5000:5000 --name my-web-app alice/my-flask-app:v1

7.5 验证服务

shell
curl http://localhost:5000

如果从本地访问服务器:

shell
curl http://your-server-ip:5000

需要确认服务器安全组和防火墙已开放对应端口。

8. 当前部署方式的主要问题

当前 docker rm -f && docker run 属于停机发布。

风险点:

问题影响
强制删除旧容器服务直接中断
新容器启动失败线上无可用实例
缺少健康检查容器启动不等于业务可用
无回滚机制发布失败后恢复慢
单实例部署没有流量切换空间

9. 不停机部署方案

9.1 单机推荐:Nginx + 双容器

适合单台云服务器或小规模项目。

流程:

text
启动新容器
  -> 健康检查通过
  -> Nginx upstream 切换到新容器
  -> 停止旧容器

优点:

  • 成本低。
  • 不需要 Kubernetes。
  • 适合当前普通 Docker 部署平滑升级。

缺点:

  • 需要维护 Nginx 配置或切换脚本。
  • 需要服务支持多端口并行运行。

9.2 蓝绿部署

准备两套环境:

  • Blue:当前线上环境。
  • Green:待发布环境。

发布流程:

text
Green 部署新版本
  -> 验证 Green
  -> 负载均衡或 Nginx 切流到 Green
  -> Blue 保留为回滚环境

优点:

  • 切换快。
  • 回滚简单。

缺点:

  • 资源成本更高。

9.3 Kubernetes 滚动更新

企业级标准方案。

关键配置:

yaml
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 0
    maxSurge: 1

还必须配置:

  • readinessProbe:判断新实例是否可以接流量。
  • livenessProbe:判断实例是否需要重启。
  • resources:限制 CPU 和内存。
  • rollback:发布失败后回滚。

9.4 最低成本改造:先启新容器再切换

如果暂时不引入 Nginx 或 K8s,至少不要先删旧容器。

思路:

shell
docker run -d --name mpd-bes-new -p 8734:8733 your-image

until curl -sf http://127.0.0.1:8734/health; do
  sleep 1
done

# 健康检查通过后再切流量或替换旧容器
docker stop mpd-bes
docker rm mpd-bes
docker rename mpd-bes-new mpd-bes

注意:如果没有反向代理或负载均衡,仅靠 rename 不能自动切换端口绑定。生产上更推荐 Nginx、Traefik、Docker Compose 或 K8s。

10. 推荐落地路径

阶段目标实施内容
短期降低发布失败风险增加健康检查、失败回滚、保留旧镜像
中期单机零停机Nginx + 双容器 + 自动切流脚本
长期标准化发布Kubernetes Deployment + Service + Ingress

短期 Jenkins Deploy 阶段至少补齐:

  • docker pull 失败即终止。
  • 新容器健康检查失败不删除旧容器。
  • 保留最近 N 个镜像标签。
  • 发布后执行核心 API 冒烟测试。
  • 失败时通知企业微信、钉钉或邮件。

所有文章版权皆归博主所有,仅供学习参考。