
做了这么多年持续集成我最大的感受是搞不定环境配置的人通常不是栽在 Jenkins 本身而是栽在仓库链路上。代码仓库、依赖仓库、镜像仓库这三层没理顺流水线就像断了粮草的后勤线跑起来全是毛病。这篇实战教程就顺着“三大仓库 自动构建 公网远程部署”这条主线把从 Gitee 上代码、Maven 拉依赖、Docker 出镜像到 Jenkins 自动构建最后部署到带公网访问能力的服务器这一整条链路拆开讲透。这文章我是按“拿来就能用”的标准写的。你跟着走一遍会得到一个完整的自动化部署闭环开发提交代码 → Gitee Webhook 通知 Jenkins → Jenkins 拉代码编译打包 → 构建 Docker 镜像推到仓库 → 远程服务器拉镜像重启容器 → 用户通过域名正常访问。适合刚接手 CI/CD 的运维、准备把个人项目做成标准流程的后端开发以及小团队里需要独立搞定研发流程建设的人。新手不用怕基础概念我会顺带讲有经验的老手也可以重点关注多镜像源配置和公网部署的几个坑。1. 整体设计与思路拆解1.1 三大仓库各自承担什么角色仓库这个词在不同语境下意思完全不一样先分清楚再动手否则后面配置会乱套。代码仓库存的是源码Gitee、GitHub、自建的 Gogs 都算。它解决的是“代码放哪、怎么协作、怎么留痕”的问题。在这套方案里代码仓库是整条流水线的起点所有构建动作都因它而起。依赖仓库解决的是“构建时依赖从哪拉”的问题。Java 项目用 Maven 仓库拉 jar 包Node 项目用 npm 仓库拉依赖。国内直连 Maven 中央仓库速度异常感人所以我们要配置阿里云镜像。这一步不做构建任务能卡在下载依赖上十几分钟不动。镜像仓库解决的是“打包好的软件怎么分发和部署”的问题。Docker 镜像构建出来后需要一个地方存放生产服务器再从那里拉取运行。私有镜像仓库Harbor、阿里云 ACR、Registry 2解决了直接分发 Docker 镜像包的低效问题也让版本回滚变得简单。三层仓库的逻辑关系就像流水线源码进仓库依赖进构建镜像进分发最终跑到线上环境。任一层断了整个链路就卡住。1.2 自动构建 远程部署的完整链路自动构建的核心是事件驱动代码一旦变更构建立刻被触发。触发方式有很多种最常见的是 Webhook——Gitee 把“有代码提交了”这个事件推送给 JenkinsJenkins 收到后自动执行预设好的流水线。这条流水线的完整画像是这样的Git 拉取最新代码到工作区Maven 根据 pom.xml 从镜像仓库拉依赖并编译打包执行单元测试质量不合格直接中断构建 Docker 镜像给镜像打上版本号标签推送镜像到私有仓库通过 SSH 连接到目标服务器远程执行拉取镜像、停旧容器、起新容器的命令浏览器访问域名验证服务是否正常每一步都可能出问题这就意味着每个阶段的状态都要看得见。Jenkins 流水线的 Stage 视图正好能把每步的耗时、日志、成功与否都展示出来排查问题的时候不需要靠猜。1.3 方案选型这套组合的优势在哪总有人问“GitHub Actions 不是更简单吗”确实简单但很多团队的代码放在内网 Git 或 Gitee 上不可能把源码推到 GitHub 去跑 Actions另外 Jenkins 是纯私有化部署管线脚本都在自己手里可以自由地和内网资源内网 Docker Registry、内网 Maven 私服打通不依赖任何外部 SaaS 服务。Jenkins 的 Pipeline 即代码Jenkinsfile设计也是它的核心优势。构建流程不再是界面上一堆点来点去的按钮配置而是跟着项目走的纯文本脚本代码更新了流水线也跟着变配合版本控制还能追溯每一次构建逻辑的改动。这一点在后期维护中带来的便利比初期多写一点 Groovy 语法值得多得多。2. 环境准备与 Jenkins 基础配置2.1 安装 Jenkins 与汉化设置我建议用 Docker 方式部署 Jenkins理由很简单环境隔离干净备份迁移方便几个命令就能起一个实例。目前最新稳定版本已经更新到 2.541.3 系列对 JDK17 及 Pipeline 的支持非常成熟老项目的兼容性也更稳。docker run -d \ --name jenkins \ --restartalways \ -p 8080:8080 \ -p 50000:50000 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v jenkins_home:/var/jenkins_home \ jenkins/jenkins:lts这串命令里有几个细节值得说道。挂载/var/run/docker.sock是为了让 Jenkins 容器直接调用宿主机的 Docker 守护进程这样后边在构建时能直接执行 docker login、docker build、docker push。如果你把这个挂载去掉Jenkins 内部没有 Docker CLi后面所有镜像相关操作都会报“docker: command not found”或者权限错误。这一步属于后方避坑的关键建议一开始就做。提示如果 Jenkins 容器要作为独立部署环境使用可以不挂 docker.sock改用 Docker-in-DockerDinD方案即在 Jenkins 容器内再跑一个 Docker 守护进程。但那个方案资源开销更大网络配置也更麻烦单机场景下共享宿主机 Docker 是更务实的选择。启动后浏览器访问http://服务器IP:8080第一次进入会让你输初始密码。密码在容器日志里能看到docker logs jenkins | grep -A 2 Administrator password输入密码、创建管理员账号、选安装建议插件走完向导就进主界面了。界面是英文的话在“系统管理 → Plugin Manager → Available plugins”里搜Localization: Chinese (Simplified)安装后重启页面就换成中文。这个汉化插件只翻译 Jenkins 核心界面第三方插件的部分菜单还是英文属于正常情况不影响使用。2.2 插件加速与标配插件清单Jenkins 装完默认连的是官方插件中心在国内访问非常不稳定插件下载经常超时。解决办法是换到国内镜像更新中心这类镜像服务属于正规公开的资源共享平台配置方式也很简单。路径“系统管理 → 插件管理 → 高级 → Update Site”把 URL 替换为清华或华为云的 Jenkins 更新中心地址保存后重启生效。配置完成后去插件管理里安装下面这几个必要插件这些是后面流水线要用的插件名作用Git Plugin拉取 Git 仓库代码Pipeline创建流水线任务、支持 JenkinsfileGitee Plugin接收 Gitee Webhook、自动触发构建Docker Pipeline在流水线中执行 docker build 等命令Publish Over SSH通过 SSH 在远程服务器上执行部署命令Blue Ocean更直观的流水线展示界面插件版本注意和 Jenkins 主版本兼容一般安装“推荐”或“latest”版本即可不要盲目追新。某个插件安装失败导致整个更新中断是常见问题不影响的插件可以单独装不要一次全选。2.3 必须掌握的 Jenkins 环境变量之前有人问我“Jenkins 怎么拿到当前的构建号”其实就是环境变量。Jenkins 在执行构建时自动注入了很多预定义的环境变量在流水线里直接就能读。最常用的几个变量名含义使用场景BUILD_NUMBER当前构建的编号拼镜像版本号比如v1.2.3.${BUILD_NUMBER}JOB_NAME任务名称区分不同项目的构建产物WORKSPACE当前构建的工作目录路径指向你代码 checkout 后的路径GIT_COMMIT当前构建对应的 Git 提交哈希排查代码版本问题、定位缺陷GIT_BRANCH当前构建的分支名区分测试分支与主干分支BUILD_URL本次构建的完整地址通知里直接附链接在流水线里用起来也很简单stage(Print Env) { steps { echo 当前构建号: ${env.BUILD_NUMBER} echo 当前分支: ${env.GIT_BRANCH} echo 工作目录: ${env.WORKSPACE} } }这些变量不需要自己去定义Jenkins 运行时自动填充。在 Jenkinsfile 里写版本号标签时BUILD_NUMBER用得最频繁用它拼出来的镜像版本不会重复覆盖回滚也方便。3. 三大仓库的配置全解析3.1 代码仓库Gitee 从零建仓到上传代码仓库的选择各人偏好不同原理一致。我以国内最常用的 Gitee 为例因为它在国内访问速度比 GitHub 稳得多Webhook 触发 Jenkins 也流畅。先在 Gitee 上“新建仓库”填仓库名、选私有或开源、初始化时勾选README.md和.gitignoreJava 项目要选 Java 模板Node 项目选 Node 模板其余保持默认。建好之后本地电脑需要和远程仓库建立信任关系最普遍的方式是 SSH 密钥。生成密钥ssh-keygen -t ed25519 -C 你的邮箱 -f ~/.ssh/id_ed25519把~/.ssh/id_ed25519.pub的内容复制到 Gitee 的“设置 → SSH 公钥”里。然后本地初始化并推代码git init git add . git commit -m init project git remote add origin gitgitee.com:你的用户名/仓库名.git git push -u origin master这里有个新手高发问题仓库里已经勾选了 README 初始化本地再 init 一次就会出现“远端已经有内容本地也有内容”的冲突。解决办法是git pull origin master --allow-unrelated-histories把两边内容先合并再推送。这条命令本质是允许两个不相干的历史合并除非你知道自己在干什么否则不要反复强推覆盖远端。如果你已经有了本地 Git 历史想整体迁移到 Gitee思路也一样把原仓库的 remote 换成新的 Gitee 地址直接推上去。Gogs 这类自建 Git 服务也支持迁移外部仓库后台操作界面提供“迁移仓库”功能填原仓库地址和账号信息即可。还有两个高频操作顺带说清楚。删除 Git 仓库本地项目里删掉.git目录就是解除版本控制远端仓库在 Gitee 的后台“设置 → 删除仓库”操作。另外 Gitee 仓库本身不支持混合嵌套子项目子项目要单独建仓库通过 Git 的submodule机制关联构建时需要额外执行子模块更新普通项目不建议上来就用 submodule维护成本容易让人头大。3.2 Maven 仓库阿里云镜像与多镜像源配置凡是 Java 项目Maven 依赖源直接决定构建速度。中央仓库直连经常卡到超时换成阿里云镜像后下载速度基本是“秒开”。配置在 Maven 的settings.xml里路径一般在${MAVEN_HOME}/conf/settings.xml如果你是用 IDEA 自带 Maven则在 IDEA 安装目录的 plugins 下找。单镜像的经典配置mirror idaliyunmaven/id namealiyun maven mirror/name urlhttps://maven.aliyun.com/repository/public/url mirrorOf*/mirrorOf /mirrormirrorOf的值是*表示所有中央仓库请求都走镜像。这里有个容易踩的坑如果项目的 pom.xml 指定了repositories里的第三方仓库比如公司私有 Nexus 或某个特殊构件仓库*也会把这些请求拦下来转到阿里云最终导致“找不到依赖”。解决办法是改用更精确的匹配mirror idaliyunmaven/id namealiyun maven mirror/name urlhttps://maven.aliyun.com/repository/public/url mirrorOfcentral/mirrorOf /mirrormirrorOf只匹配central其他第三方仓库还是走原地址。如果你有多个镜像源比如一个为阿里云、一个为华为云想要顺序逐个尝试Maven 的 mirror 设计是“只取第一个匹配到的镜像”不是轮询。多源真正的做法是配置多个profile激活逻辑上保持互斥profiles profile idaliyun/id repositories repository idaliyun-public/id urlhttps://maven.aliyun.com/repository/public/url /repository /repositories /profile profile idhuaweicloud/id repositories repository idhuawei/id urlhttps://repo.huaweicloud.com/repository/maven//url /repository /repositories /profile /profiles然后通过-P aliyun或-P huaweicloud选择激活哪组这就是 2026 年很多项目在用的多源仓库接口配置思路。注意Maven 的仓库网页版入口常被提到阿里云的公共仓库管理后台提供了构件搜索、版本查询功能你可以在网页端确认某个依赖是否存在、版本号是否正确排查依赖下载失败时非常有用。但最终构建生效的还是settings.xml中的镜像配置。3.3 Docker 仓库国内镜像源与私有仓库推送Docker 镜像源的问题分两段构建时拉基础镜像比如openjdk:17-jdk-slim和部署时拉构建产物镜像。公共镜像拉取如果慢在 Docker 客户端配置 registry mirror 即可一般是写/etc/docker/daemon.json{ registry-mirrors: [ https://docker.m.daocloud.io ] }改完重启 Dockersystemctl restart docker再拉镜像速度就会有质的提升。但有一个逻辑必须拎清楚registry-mirrors只影响拉公共镜像比如从 Docker Hub 拉不影响自行构建后推送到私有仓库的镜像。私有镜像仓库我推荐两条路。已有云资源就直接用云厂商的容器镜像服务如阿里云 ACR自动附带公网访问地址、镜像扫描、版本管理、多集群授权小团队最省心。想完全私有化就自建 Harbor 或轻量 Registry 2docker run -d -p 5000:5000 \ --restartalways \ --name registry \ -v /data/registry:/var/lib/registry \ registry:2有了仓库之后需要在 Jenkins 里先做一次docker login。凭据一律加到 Jenkins 的“凭据管理”里不要在脚本里明文写密码然后通过 Docker Pipeline 插件调用stage(Login Push) { steps { withCredentials([usernamePassword(credentialsId: docker-hub-key, passwordVariable: DOCKER_PASS, usernameVariable: DOCKER_USER)]) { sh docker login --username$DOCKER_USER --password$DOCKER_PASS registry.example.com:5000 sh docker tag myapp:${BUILD_NUMBER} registry.example.com:5000/myapp:${BUILD_NUMBER} sh docker push registry.example.com:5000/myapp:${BUILD_NUMBER} } } }私有仓库端口如果是非 443远程服务器拉取时需要先在目标机的 daemon.json 里加上insecure-registries: [registry.example.com:5000]否则 Docker 会因为证书问题拒绝拉取。这个配置容易遗漏部署时直接报x509: certificate signed by unknown authority原因就是 HTTPS 证书校验失败。4. 自动构建流水线落地4.1 第一个 Pipeline 任务怎么建回到 Jenkins 主界面点击“新建任务”输入任务名选择“流水线Pipeline”。任务名建议直接用项目名比如myapp-deploy简洁明确。建好后先不急着写脚本先把“参数化构建过程”配置上勾选“字符串参数”添加一个BRANCH参数默认值设为master意思是构建时可以选择从哪个分支拉代码。“构建触发器”和“流水线定义”这两块在界面配置完成后核心逻辑都写在 Jenkinsfile 里。注意“Hello World”式的简单界面配置只适合测试真正的项目建议全部用 Jenkinsfile 管理这样流水线本身就是项目的一部分换机器、换 Jenkins 实例都不怕。4.2 用 Jenkinsfile 描述整个构建过程Jenkinsfile 是 Groovy 语法但不用把它想得很复杂核心就是几个 stage 按顺序执行。下面是一个标准的多阶段流水线示例覆盖了拉取代码、Maven 构建、Docker 打包、推送仓库、远程部署这五步pipeline { agent any environment { // 镜像仓库地址 REGISTRY registry.example.com:5000 // 项目名推送到仓库后作为镜像名 IMAGE_NAME myapp // 目标服务器 DEPLOY_HOST 跳板机或目标机IP } stages { stage(拉取代码) { steps { checkout scm } } stage(Maven 构建) { steps { sh mvn clean package -DskipTests -P aliyun } } stage(构建 Docker 镜像) { steps { script { def tag ${env.BUILD_NUMBER} sh docker build -t ${REGISTRY}/${IMAGE_NAME}:${tag} . sh docker tag ${REGISTRY}/${IMAGE_NAME}:${tag} ${REGISTRY}/${IMAGE_NAME}:latest } } } stage(推送镜像) { steps { script { def tag ${env.BUILD_NUMBER} withCredentials([usernamePassword(credentialsId: registry-credentials, passwordVariable: REG_PASS, usernameVariable: REG_USER)]) { sh docker login --username${REG_USER} --password${REG_PASS} ${REGISTRY} sh docker push ${REGISTRY}/${IMAGE_NAME}:${tag} sh docker push ${REGISTRY}/${IMAGE_NAME}:latest } } } } stage(远程部署) { steps { sshPublisher( publishers: [ sshPublisherDesc( configName: prod-server, transfers: [ sshTransfer( execCommand: docker pull ${REGISTRY}/${IMAGE_NAME}:${env.BUILD_NUMBER} docker stop myapp || true docker rm myapp || true docker run -d --name myapp -p 8081:8080 ${REGISTRY}/${IMAGE_NAME}:${env.BUILD_NUMBER} ) ] ) ] ) } } } post { success { echo 构建成功 } failure { echo 构建失败 } } }这段脚本有几个要点需要展开。checkout scm是 Jenkins 自带的代码检出步骤前提是任务配置里已经填了 Git 仓库地址和凭据environment里定义的是全局变量stage 内部可以直接引用-P aliyun是激活上一章那个 Maven profile 的写法具体名称按你的配置文件来。实际生产环境里我建议把部署时那串长命令拆开写并入一个deploy.sh放在项目的deploy/目录里提交到代码仓库Jenkinsfile 里只做远程执行。原因很简单部署脚本应该跟着项目版本走而不是绑在一个 Jenkins 任务里。改部署逻辑只需要改代码仓库不需要动 Jenkins。4.3 Webhook 触发提交代码自动构建手动点“立即构建”只是验证流程真正自动化靠的是 Webhook。目标开发把代码 push 到 Gitee 仓库Jenkins 自动触发上面那条流水线。在 Gitee 仓库后台找到“管理 → WebHooks”URL 填http://Jenkins服务器IP:8080/gitee-project/myapp-deploy取决于你装的 Gitee 插件勾选“Push”事件保存。注意Webhook 能调通的前提是 Jenkins 端能访问到 Gitee 的请求反过来 Gitee 也要能访问到 Jenkins。本地联调时经常遇到内网环境访问不到的问题实际生产中 Jenkins 和 Gitee 都部署在有公网访问能力的服务器上这个问题基本不存在。Gitee 插件推荐开启自动管理 hook 模式不过要确保 Jenkins 任务里“构建触发器”那栏勾上了 “Gitee webhook 触发构建”。配置完成后随便提交一次代码就能在 Jenkins 构建历史里看到一条由 push 事件触发的记录。此时再看 Blue Ocean 里的流水线视图每个阶段哪一步耗时多、卡在哪一步一目了然。5. 公网远程部署实战5.1 部署目标机器与密钥准备远程部署的目标机器可以是一台内网服务器也可以是一台带公网 IP 的云主机。公网远程部署不是说 Jenkins 机器必须有公网 IP而是最终运行的业务需要对用户提供公网访问入口。通常做法是Jenkins 部署在内网通过 SSH 连到带公网 IP 的应用服务器上执行部署命令。这台应用服务器需要做的准备有四项装 Docker、开放业务端口、配置 SSH 登录免密、确认能访问镜像仓库。免密登录用 SSH 公钥实现# 在 Jenkins 机器上 ssh-keygen -t ed25519 -C jenkins-deploy -f /var/jenkins_home/.ssh/id_deploy # 将公钥追加写入目标服务器 ssh-copy-id -i /var/jenkins_home/.ssh/id_deploy.pub deploy你的目标服务器IP如果想把密钥直接交给 Jenkins 使用可以在“系统管理 → 凭据管理 → 添加凭据”里选择 “SSH Username with private key”把私钥贴进去指定用户名。这一步比简单地配置全局免密更安全一旦 Jenkins 机器被攻破私钥不会裸露在全局目录。5.2 远程执行部署命令的实现刚才 Jenkinsfile 里用的sshPublisher是 Publish over SSH 插件的写法。第一步在“系统管理 → 系统配置”里找到 “Publish over SSH”添加一个 SSH Server配置项建议值Nameprod-serverHostname目标服务器的公网 IP 或内网 IPUsernamedocker 用户或 deploy 用户Remote Directory/opt/deploy凭据选择刚才添加的 SSH 私钥凭据保存之后流水线里就能通过configName: prod-server引用它。远程执行命令时注意sshPublisher默认的执行目录是你在 Remote Directory 指定的目录脚本里的相对路径都以此为准。远程命令本身要做得“幂等”即无论执行多少次结果都一致。示例里的docker stop myapp || true就是为了处理容器不存在时报错的问题。部署命令建议写成脚本首行加set -e这样哪一步失败脚本会立即返回非零状态Jenkins 界面会直接显示该阶段失败不会出现“命令执行了但实际没起来”的假象。5.3 域名、安全组与 Nginx 反向代理服务器上容器跑起来了端口也映射出来了比如 8081但用户访问不能总靠 IP 加端口。正规做法是域名解析到服务器公网 IPNginx 监听 443/80把请求反向代理到本机容器的映射端口。安全组这一步千万别忽略。云厂商控制台的“安全组规则”里必须放行 80、443以及 SSH 22否则 Nginx 配置得再对外部流量也进不来。我见过不少人在服务器上纠结半天端口不通最后发现是安全组没放开白白浪费一晚上。Nginx 反向代理配置示例server { listen 80; server_name your-domain.com; location / { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }配置完执行nginx -t验证语法然后systemctl reload nginx。HTTPS 证书推荐用云厂商的免费数字证书或 Let’s Encrypt 自动签发申请下来后在 Nginx 里加一个 443 的 server 块把证书路径指过去即可。证书配置完成之后像 HTTP 到 HTTPS 的重定向也可以顺手加上避免用户通过明文协议访问。5.4 回滚与验证线上部署的最后一步自动部署不是部署完就结束了验证和回滚才决定整个流程是不是真的可靠。部署完成后要立刻验证服务健康状态最简单的办法是请求健康检查接口curl -s http://127.0.0.1:8081/actuator/health | jq .status返回UP说明服务正常。也可以再通过域名做一次端到端验证。如果服务起不来回滚方案要能立刻执行。正因为我们在推送时同时打了:latest和:构建号两个标签回滚时只需要把上上次构建的镜像 tag 拿过来重新 run 即可docker run -d --name myapp_rollback -p 8081:8080 registry.example.com:5000/myapp:上上次构建号回滚完成之后再对照旧版本的验证流程做一次健康检查确认线上稳定再决定是否继续排查新版本的问题。6. 常见问题与排查技巧实录6.1 构建期典型问题速查表跑流水线最烦的是看到红色失败这里把高频问题和对应的处理手段整理成一张表排查时按图索骥错误现象可能原因处理办法Host key verification failedJenkins 首次连接目标服务器没有确认主机指纹在目标机 known_hosts 中预先添加公钥或使用 ssh-keyscan 写入Permission denied (publickey)私钥没配对或权限过大检查 Jenkins 凭据里的私钥、目标机 authorized_keys 里的公钥、私钥文件权限设为 600docker: command not foundJenkins 容器内没有安装 Docker CLI挂载宿主机/usr/bin/docker或重新选择带 docker 的镜像no space left on device镜像和构建缓存把磁盘占满了定期执行docker system prune -f或者对构建产物做自动清理Could not resolve host内网环境的 DNS 或者代理配置问题检查 Jenkins 及目标机的 DNS 配置确认能解析镜像仓库地址6.2 仓库相关的高频问题依赖拉不下来先分清是哪一层仓库出问题。Maven 中央仓库和镜像仓库的问题检查settings.xml里的 mirror 配置和网络连通性Docker 公共镜像拉不动检查 daemon.json 的 registry-mirrors 和 DNS私有镜像仓库拉取报证书错误检查目标机 daemon.json 里有没有加insecure-registries。镜像仓库的“最新镜像”问题也经常让人绕弯。推送到私有仓库后在服务器上docker pull拉不到latest原因可能是拉取动作发生在重新构建之前没有先执行docker pull刷新本地缓存。我们的 Jenkinsfile 里每个远程部署命令第一步就是先 pull其实就为了同步这个状态。另外私有仓库镜像多了以后记得启用定期清理策略否则仓库占用的磁盘空间会一路涨到爆仓。6.3 容器权限与远程执行问题Jenkins 容器内使用 Docker 命令挂载 docker.sock 的方案权限一般没问题但要注意宿主机的 Docker 如果升级了 API 版本Jenkins 容器内的 docker CLI 可能因为版本太旧而报 “client and server dont have same version”。解决办法是尽量在 Jenkins 容器内使用与宿主机一致或更新的 Docker CLI或者干脆 Jenkins 镜像升级到带新版 Docker 的 tag。远程执行命令久了还会遇到另一个隐性坑Publish over SSH 的超时时间设置太短部署脚本里拉大镜像需要几分钟如果超时设置默认的 30 秒流水线会提示对方关闭。路径在“系统配置 → Publish over SSH → 高级 → Timeout (ms)”里改大比如 120000 毫秒。6.4 上线前的自检清单积累了一些实战经验之后每次往公网环境推版本前我都会跑一遍下面的检核相当于给自己一个敬畏线上环境的仪式镜像版本是否唯一是否同时更新了latest标签目标服务器是否已登录镜像仓库凭据有没有过期远程部署命令是否幂等容器不存在时会怎样健康检查接口是否存在返回是否符合预期回滚版本号是否记录下来资源和镜像是否可用Nginx 配置是否需要改动是否已经nginx -tHTTPS 证书是否过期有没有设置到期提醒安全组端口是否放行数据库和其他远端依赖是否可达这些检查项每一条我都踩过对应的坑。特别是 HTTPS 证书过期我遇到过一整个凌晨线上访问打不开排查半天才发现是证书到期了。现在我会在证书到期前一个月在云控制台设置到期提醒从根上避免这个问题。另外强烈建议把部署通知接入到团队用的通讯软件上构建成功、失败、回滚这类关键事件让相关同事第一时间知道。通知内容建议包含构建号、分支、提交人和构建地址这样有问题时大家不用靠问打开消息记录就能定位是哪次构建引入的异常。在我反复折腾这套流程的过程中一个很深的体会是自动化构建和公网部署的难点从来不在某个单一环节而在整条链路的联动。每次有人问“怎么快速搭一套”我都会建议照着这篇文章的链路先跑通一个 Hello World 项目再把业务代码逐步加进来。链路通了后面加节点只是往流水线里插一段的事链路没通就堆功能最后排查问题的时间能翻倍。希望这套从三大仓库到公网部署的完整过程能帮你在自动化部署这条路上少走几段弯路。