资讯动态

Drone + Docker 轻量级 CI/CD 自动化部署实践

发布时间:2026/10/14 22:20:16 来源:尧图企业网站定制
这几年团队从手动发版切到 Drone Docker 自动化部署最大的感受是发布从一个提心吊胆的操作变成了一个可以随时执行、随时回滚的确定性动作。先给不熟悉的读者一句话介绍Drone 是一套基于容器运行流水线的 CI/CD 系统它的每个构建步骤都跑在独立的 Docker 容器里而自动化部署要解决的核心问题就是代码从提交到上线之间那些重复、易错的过程不再需要人为干预。这篇文章会从方案选型开始把服务搭建、流水线编写、常见坑点一次性讲透适合准备自建 CI、对现有发布流程不满意的小团队开发者也适合刚接触 DevOps 想找一个轻量方案的人。1. 为什么选 Drone Docker 这套组合1.1 手动部署最大的几个痛先说一个很常见的场景代码写完了要发布到服务器。早期团队的做法是有人 SSH 登录到服务器先git pull然后在服务器上装好全套编译环境跑构建再手动systemctl restart服务。听起来不复杂但真正做起来问题很多。第一个问题是环境不一致。本地编译好的二进制在服务器上不一定能跑因为操作系统版本、依赖库、动态链接库都可能不一样就算服务器上能编译换一台服务器又要重新折腾。第二个问题是过程不可追溯。谁在什么时候发布过什么版本全靠口头和聊天记录出问题想回滚都不知道回滚到哪个 commit。第三个问题是时间被大量占用尤其是多服务项目每次发布光登录、拉代码、重启、验证就要二三十分钟如果中间手滑拉错分支还要再花时间修。这些问题本质上不是“发布”这个动作带来的而是“手动”带来的。所以核心诉求很明确把构建、测试、打包、部署这一段流程固化成代码让每次执行结果都一致并且能留下完整记录。这就是 CI/CD 要做的事。1.2 Drone 靠什么赢下这一票市面上 CI 工具不少最终选 Drone是因为它的设计思路太对胃口了。Drone 的模型非常干净仓库根目录放一个.drone.yml里面描述整个流水线每次代码推送、打 Tag、提 Pull RequestGit 托管平台会通过 Webhook 通知 Drone 服务端服务端再把任务交给 Runner 去执行。Runner 拿到任务后会按照.drone.yml的定义为每个步骤启动一个独立的 Docker 容器。也就是说所有步骤都在容器里跑宿主机器上不需要预装任何语言工具链。这套设计带来的好处是实打实的。第一隔离性非常好两个项目的构建环境互不干扰这个项目用 Go 1.20那个项目用 Node 18完全没冲突。第二可复现性非常强只要镜像不变流水线在任何一台机器上跑出来的结果都一样不存在“在我机器上是好的”这种话。第三安装和维护极轻服务端加 Runner 两个容器就能跑起来内存占用很低一台 2 核 4G 的小机器完全够用。另外呢Drone 把流水线配置直接放进代码仓库意味着配置也走版本控制。改流水线就像改代码一样有历史、有评审、能回滚。这对于团队协作来说太重要了新成员看一遍.drone.yml就知道整个发布流程长什么样不用去问“发布怎么做”。1.3 和主流CI方案对比之后的选择选型的时候我也认真对比过几个常见方案这里直接说结论。老牌的 Jenkins 功能确实强大插件生态非常丰富但问题也恰恰出在这里它太重了。你不但要维护一个臃肿的服务端还要在页面上点点点配置各种任务配置多了以后很难理清依赖关系而且跑构建要么用 Master-Slave 的 Agent 模式要么用容器管理成本都不小。如果是几十个人的小团队花在维护 Jenkins 上的时间可能比省下来的发布时间还多。一体化代码托管平台自带的 CI/CD 能力也不错尤其是如果你已经深度使用同品牌全家桶和代码仓库、合并请求结合得很紧密几乎不用额外部署。但它的缺点是你必须把自己绑在一个生态里。如果你用的是自建 Git 服务或者混合使用了多个代码托管平台这些自带 CI 就没那么灵活了。对比下来 Drone 的优势就很突出它不关心你的代码放在哪里只要支持 OAuth 和 Webhook 就能对接它不要求你必须用某种基础设施Runner 可以是 Docker、Kubernetes、SSH、甚至裸机它的配置足够简洁一个 YAML 文件就能描述完整的构建部署流程。对中小团队来说这种“轻量、可移植、代码化”反而是最重要的。2. 部署前的架构设计与环境准备2.1 这套系统的核心链路拆解在动手搭建之前先把整套系统的数据流理清楚。我习惯把它拆成四个角色代码托管平台、Drone 服务端、Drone Runner、目标服务器。代码托管平台负责存放源码和触发事件是流水线的起点。Drone 服务端做的事情是接收 Webhook、做权限认证、读取仓库里的.drone.yml、把执行任务分发下去同时提供 Web UI 给开发者查看每次构建的状态和日志。它本身不执行具体命令。负责执行的是 Drone RunnerRunner 接收到任务后为每个步骤创建 Docker 容器你在 YAML 里写的每条 commands 就是在这个容器里执行的。目标服务器则是最终要跑业务容器的地方部署阶段通过 SSH 或其它方式把构建好的镜像拉过去并启动。这里有一个很重要的理解Runner 挂载 Docker Socket不代表它要把容器部署到生产环境。Runner 挂载 Docker Socket 通常只是为了“有 Docker 可用”用来构建镜像或跑临时测试容器生产环境的部署命令可以走远程 SSH把业务容器拉到真正的应用服务器上启动。这样 CI 机器的 Docker 权限不会直接暴露给生产环境安全边界更清晰。2.2 服务器怎么规划才不折腾以一个小团队为例我建议最少准备两台服务器。一台作为 CI 机器部署代码托管服务如果还没有的话、Drone Server、Drone Runner以及可选的私有镜像仓库。这台机器的资源按照团队规模来通常 2 核 4G 起步磁盘要留足因为 Docker 镜像和构建缓存会一直占空间建议 100G 以上。另一台或多台作为应用服务器只做一件事跑业务容器。应用服务器上不需要安装任何开发工具链只需要 Docker 环境。如果项目非常小或者只是个人项目一台服务器也能跑通整套流程。这时候 Runner 直接操作本机 Docker测试容器和应用容器都跑在同一台机器上省事但要注意资源争抢和权限风险。生产环境我建议无论如何都要和应用服务器分开哪怕只是把 Runner 的部署阶段改成 SSH 方式也不要让 CI 能直接控制生产 Docker这个后面会具体讲。网络层面需要关注一个点代码托管平台要能通过公网或内网访问到 Drone Server 的 Webhook 接口Runner 只要能访问到 Drone Server 服务端即可。如果你在云服务器上开了安全组记得放行对应端口。2.3 OAuth应用注册与回调地址Drone 登录用的是 OAuth也就是说开发者直接用代码托管平台的账号就能登录 Drone 界面不需要再单独维护一套账号体系。这个步骤很多人会卡住我专门说一下。在代码托管平台的后台新建一个 OAuth 应用一般需要填应用名称、主页 URL最重要的一个字段是回调地址Callback URL。这里的地址必须填成https://你的Drone域名/login不是根路径也不是其它路径。如果填错了登录时会一直报 redirect_uri 不匹配。创建完成后会得到一对 Client ID 和 Client Secret把这两个值记下来稍后写到 Drone Server 的环境变量里。不同代码托管平台用的环境变量前缀不一样比如自建的开源 Git 服务是DRONE_GITEA_CLIENT_ID/DRONE_GITEA_CLIENT_SECRET对接其它平台时把GITEA换成对应的前缀即可。另外一个容易漏掉的是管理员初始化。Drone 不会自动给你一个超级管理员账号需要在启动服务端时通过DRONE_USER_CREATE环境变量指定格式类似username:你的账号,admin:true。这个账号必须是在代码托管平台真实存在的登录后它才有管理权限能激活仓库、添加全局 Secret。2.4 镜像仓库与密钥规划流水线构建出来的 Docker 镜像需要一个存放的地方我把它分成三种情况。第一种团队规模小、项目不多直接在 CI 机器上用 Docker Registry 容器搭一个私有仓库配好 HTTPS 证书就能用。第二种项目已经上云用云厂商提供的镜像仓库服务网络快、也好和对象存储联动缺点是国内访问偶尔要配置加速。第三种如果项目已经上了 Kubernetes那镜像仓库通常已经是基础设施的一部分直接复用即可。需要注意私有仓库如果用了自签名证书无论是构建阶段的 docker push还是目标服务器的 docker pull都会遇到证书不信任的问题。这个我先提前打预防针在涉及到的每台机器上把仓库的 CA 证书加到 Docker 的证书目录里路径是/etc/docker/certs.d/仓库地址/加完还要重启 Docker具体操作放在常见问题那节讲。密钥规划方面我建议把下面几类信息提前整理好Git 平台的 OAuth Client Secret、Drone Server 和 Runner 之间通信的 RPC Secret、镜像仓库的用户名密码、生产服务器 SSH 的私钥。这些都不能写死在配置文件里运行时通过环境变量或 Drone Secret 注入后面的章节会给出具体写法。3. 用 docker-compose 快速拉起 Drone 服务端和 Runner3.1 一份可以直接复用的 docker-compose.ymlDrone 的安装真的非常简单一个 docker-compose 文件就能同时拉起服务端和 Runner。先看完整配置我再逐个解释。version: 3 services: drone-server: image: drone/drone:2 ports: - 80:80 - 443:443 volumes: - drone-data:/var/lib/drone/ environment: - DRONE_SERVER_HOST${DRONE_SERVER_HOST} - DRONE_SERVER_PROTOhttps - DRONE_RPC_SECRET${DRONE_RPC_SECRET} - DRONE_GIT_ALWAYS_AUTHtrue - DRONE_USER_CREATE${DRONE_USER_CREATE} # 这里按你使用的代码托管平台填对应环境变量 - DRONE_GITEA_CLIENT_ID${DRONE_GITEA_CLIENT_ID} - DRONE_GITEA_CLIENT_SECRET${DRONE_GITEA_CLIENT_SECRET} drone-runner: image: drone/drone-runner-docker:1 depends_on: - drone-server volumes: - /var/run/docker.sock:/var/run/docker.sock environment: - DRONE_RPC_HOSTdrone-server - DRONE_RPC_PROTOhttp - DRONE_RPC_SECRET${DRONE_RPC_SECRET} - DRONE_RUNNER_CAPACITY2 - DRONE_RUNNER_NAME${DRONE_RUNNER_NAME} volumes: drone-data:这个文件里的变量我都放在.env文件里维护这样不会把密钥写死在 compose 文件里。.env里大概是这样的结构DRONE_SERVER_HOSTci.example.com DRONE_RPC_SECRETopenssl rand -hex 32 生成的一串随机值 DRONE_USER_CREATEusername:admin,admin:true DRONE_GITEA_CLIENT_IDxxxxxxxx DRONE_GITEA_CLIENT_SECRETxxxxxxxx DRONE_RUNNER_NAMErunner-013.2 环境变量逐个说清楚很多人搭 Drone 失败问题几乎都出在环境变量。DRONE_SERVER_HOST填的是 Drone 对外服务的域名或地址比如ci.example.com注意不要带协议不要带端口如果用了非标准端口加端口也行。这个变量会直接影响 OAuth 回调地址和 Webhook 地址的生成所以一定要和你注册 OAuth 时填的域名完全一致。DRONE_SERVER_PROTO填https还是http取决于你前面有没有挂反向代理和证书。如果是在内网裸跑就填http如果是公网访问并配了 HTTPS就填https。服务端和 Runner 之间通信用的协议由DRONE_RPC_PROTO单独控制这两个别搞混。我在内网部署时习惯把 Server 开在 80 端口Runner 通过内网地址http://drone-server访问它的 RPC 端口所以 Runner 里填DRONE_RPC_PROTOhttp不需要这个变量它会默认访问 80 端口。DRONE_RPC_SECRET是服务端和 Runner 之间的共享密钥两边必须完全一致。用openssl rand -hex 32生成一个 64 位的十六进制串不要自己拍脑袋想一个短密码这个串的强度决定了 Runner 是否可信。DRONE_GIT_ALWAYS_AUTH我建议直接设成true。它的作用是让 Drone 在拉取代码仓库时始终带上用户令牌而不是只有私有仓库才带。如果你用自建服务经常会出现明明仓库可以匿名拉取、但流水线克隆失败的问题设成 true 可以避开一堆权限坑。DRONE_USER_CREATE格式要精确比如username:admin,admin:true逗号分隔多个属性不要有多余空格。它只会在数据库初始化的时候生效如果写错了后面想加管理员就要用命令行工具去处理比较麻烦。3.3 启动、登录与仓库激活配置写好后在 docker-compose 文件所在目录执行docker compose up -d然后访问 Drone 的域名第一次打开会跳到代码托管平台的授权页面同意授权后就会回到 Drone 界面。如果这一步报错优先检查 OAuth 回调地址和DRONE_SERVER_HOST、DRONE_SERVER_PROTO是否匹配。登录进去后左侧菜单找到 Repositories能看到你账号有权限的仓库列表。你需要手动把某个仓库“激活”激活后 Drone 会自动向代码托管平台注册 Webhook。这是一个很容易忽略的步骤很多人已经在代码平台手动配好 Webhook 了结果发现 Drone 没推送事件实际上仓库没激活就不会监听。激活仓库的时候Drone 会给仓库生成一个专属的部署密钥用于克隆代码。如果仓库是私有的这一步也会一并处理好基本不需要你干预。不过遇到仓库特别多的情况我更推荐用命令行工具批量添加这里就不展开讲了。到这里基础设施已经就位剩下的事情就是写.drone.yml。4. 写第一个真正能用的 .drone.yml4.1 管道结构与触发条件怎么配Drone 的流水线配置看起来有点多但实际核心概念就一个管道。所有任务都写在管道里管道在仓库根目录的.drone.yml中定义。我先给一个完整的示例后面再拆开讲解。kind: pipeline type: docker name: build-test-deploy trigger: event: - push - tag steps: - name: 编译与单元测试 image: golang:1.20 commands: - go mod download - go build -o app . - go test ./... - name: 构建并推送镜像 image: plugins/docker settings: registry: registry.example.com repo: registry.example.com/myteam/app tags: - ${DRONE_COMMIT_SHA} - latest username: from_secret: registry_username password: from_secret: registry_password - name: 部署到测试环境 image: docker:24 volumes: - name: docker_sock path: /var/run/docker.sock commands: - docker stop test-app || true - docker rm test-app || true - docker run -d --name test-app -p 8080:8080 registry.example.com/myteam/app:${DRONE_COMMIT_SHA} when: event: - push - name: 部署到生产环境 image: appleboy/drone-ssh settings: host: from_secret: prod_host username: from_secret: prod_user key: from_secret: prod_ssh_key script: - docker pull registry.example.com/myteam/app:${DRONE_COMMIT_SHA} - docker stop prod-app || true - docker rm prod-app || true - docker run -d --name prod-app -p 8080:8080 registry.example.com/myteam/app:${DRONE_COMMIT_SHA} when: event: - tag volumes: - name: docker_sock host: path: /var/run/docker.sock先看头部三个固定字段。kind: pipeline表示这是一条管道type: docker表示让 Runner 通过 Docker 容器来执行步骤name就是给这条流水线起的名字会显示在 UI 上。trigger是触发条件这里写了event: push和event: tag意思是只要有人推送代码或打 Tag就跑这条流水线。步骤的执行顺序默认是自上而下串行每个步骤依赖前一步成功。如果你想要并行或者调整依赖关系可以给步骤加depends_on字段底层逻辑和任务编排类似。这里我故意没写新手阶段串行最直观。4.2 编译测试阶段一个步骤一个容器看编译那一步image: golang:1.20commands里面是三条命令。随便哪台机器跑这条流水线Runner 都会先拉取golang:1.20镜像然后在这个全新的容器里依次执行这三条命令。这意味着宿主机上不需要安装 Go不需要配 GOPATH甚至不需要有 Go 的缓存目录。环境完全由镜像决定镜像换了版本构建环境就跟着换。这对团队里的每个人都公平不管本地是 Windows、macOS 还是某个古老的 Linux 发行版流水线里跑的永远是同一个环境。如果你的项目是 Node.js把image换成node:18commands 换成npm ci、npm run build是 Java 就换成maven:3.8做法一模一样。Drone 不会限制你用什么语言它只是帮你把语言工具链装进容器里。4.3 镜像构建与Tag策略编译测试通过后下一步是把源码打包成 Docker 镜像。Drone 生态里最常用的构建插件是plugins/docker它负责在你的仓库里找到 Dockerfile执行docker build再把镜像推到镜像仓库。这里有两个值得展开的点。第一是 registry、repo、tags 怎么配。registry 填镜像仓库地址如果用的是自建仓库或云仓库必须带上域名repo 填完整的镜像名比如registry.example.com/myteam/apptags 可以是一个列表支持写多个标签也可以引用 Drone 内置的环境变量。第二是 Tag 策略这个直接决定了你能不能做回滚。我强烈建议不要只用latest一个 Tag因为后一次构建会把前一次覆盖掉你根本无法知道线上跑的是哪次构建。正确做法是至少给镜像打两个 Tag一个是不可变标识比如${DRONE_COMMIT_SHA}用 commit 的哈希值唯一对应某次代码版本另一个是语义化标签或latest方便人肉查看和临时拉取。回滚的时候你只需要回到上一次构建记录的 commit SHA重新部署那个镜像即可。username和password为什么写得这么别扭因为这是引用仓库级 Secret而不是直接把账号密码写在 YAML 里。Drone 会在运行时解密并注入给插件日志里也不会出现明文。这点后面专门讲。4.4 部署阶段本地Docker与远程SSH两种写法部署是整个流水线的落点也是最需要根据场景选择的部分。第一种写法是直接挂载 Docker Socket 操作本地 Docker适合测试环境和单机场景。示例里的volumes把 Runner 宿主机的/var/run/docker.sock挂进容器然后在容器里执行docker stop、docker rm、docker run。这样做的本质是让你在一个临时容器里控制宿主机上的 Docker 守护进程流程最短、排错最直接。我在只有一台 CI 服务器的个人项目里经常这么干。第二种写法是走 SSH 远程执行命令适合真正的生产环境。示例里的appleboy/drone-ssh是常用的 SSH 部署插件它会用你配置的私钥登录到目标服务器然后执行 script 里的命令。目标服务器收到命令后拉取镜像、停掉旧容器、起新容器整个过程和 CI 机器上的 Docker 完全隔离。两种方式怎么选我个人的判断标准就一条目标机器上的账是不是和 CI 的账是同一个。如果 CI 挂了会不会影响线上应用如果是生产环境一定走 SSH如果是测试环境优先用 Docker Socket 减少复杂度。另外SSH 方式还有一个好处它天然适合多台目标服务器的情况你可以在一个部署步骤里对多台主机循环执行而不是去改流水线结构。4.5 Secret 管理别把密码写进仓库.drone.yml是放在仓库里的任何有仓库权限的人都能看到所以密码、Token、私钥这些绝对不能直接写在里面。正确的做法是使用 Drone 的 Secret 功能。在 Drone 界面的仓库设置里有一个 Secrets 栏目你可以添加任意名字的键值对。比如我在示例里用了registry_username、registry_password、prod_host、prod_user、prod_ssh_key对应的值在添加的时候填写。在流水线里用from_secret: 你的Secret名字引用Drone 会私密地把值注入到对应步骤的环境变量或插件配置中。有几个细节要留意。第一Secret 名字是区分大小写的Registry_User和registry_user是两个完全不同的名字写错一个就会导致登录失败。第二日志里不会自动打印 Secret 的值但如果你在命令里自己 echo 出来了Drone 也没办法帮你屏蔽所以脚本里不要干这种多余的事。第三Pull Request 事件默认不会注入 Secret这是安全机制防止有人通过提交恶意 PR 把 Secret 打出来如果你确实需要在 PR 中跑部分流水线要单独给 Secret 开启允许 PR 使用的选项。5. 实战中的常见问题与排查技巧5.1 高频故障速查表搭过几套 Drone 之后我发现大多数问题来来回回就那么几个先把速查表放在这。现象大概率原因排查与解决流水线一直 Pending 不执行Runner 未注册、RPC Secret 不一致、容量占满看 Runner 日志检查 DRONE_RPC_HOST/PROTO/SECRET登录 Drone 报 redirect_uri 错误OAuth 回调地址或 DRONE_SERVER_HOST 配错确认回调地址是 https://域名/login 且域名一致推送代码但不触发流水线仓库未激活、Webhook 未注册到 Drone 仓库列表确认激活状态查看平台 Webhook 投递记录构建时 push 镜像报 unauthorized镜像仓库账号密码错误或 Secret 没配好确认 from_secret 名字一致手动 docker login 验证部署后容器启动失败镜像本身有问题或端口/环境变量不全登录目标服务器手动 docker logs 容器名查看SSH 部署报 host key verification failed目标主机指纹未校验在插件配置里加 fingerprint 字段或预先生成 known_hosts拉取私有仓库镜像报 x509 错误自建仓库证书不被信任在对应机器的 Docker 证书目录安装 CA重启 Docker5.2 流水线一直Pending的排查过程有一次我给一个项目搭环境流水线推到代码后一直停在 Pending 状态能卡十几分钟最后才发现是沟通层的配置问题。这类问题排查起来其实不难按链路顺序走就行。先看 Drone Runner 的日志命令是docker logs drone-runner -f --tail 100。如果看到类似rpc: client is not registered或持续重试连接的内容那基本都是 RPC Secret 不一致或者DRONE_RPC_PROTO填错了。我当时是把DRONE_RPC_PROTO写成了https但服务端其实只开了 80 端口改回http后立刻就好。如果日志显示 Runner 已经注册成功任务也分配下来了但就是没有执行再看 Runner 的DRONE_RUNNER_CAPACITY。这个变量控制同时能跑多少个任务如果你之前把并发数调小了而前面几个构建卡住了后面的任务就只能排队等着。停止几个卡住的任务或者把容量调大问题一般就能解除。还有一种隐蔽情况是 Runner 和 Server 的时间不同步导致任务分发的签名验证失败。Docker 容器默认用的是宿主机时间但如果宿主机时钟漂移就会出现难以理解的问题。日常维护里把时间同步服务开好比遇到问题再排查省心得多。5.3 镜像仓库证书和登录认证的坑私有镜像仓库这关几乎所有第一次搭的人都会踩一次。如果你用的是自建 Registry 且没有正式证书Runner 构建时执行docker push会报x509: certificate signed by unknown authority目标服务器执行docker pull也会报同样的错。解决办法不是在命令行加--insecure参数那只是治标因为流水线里的命令没法每次都带参数。正确做法是在每一台需要拉取或推送镜像的机器上把私有仓库的 CA 证书放到/etc/docker/certs.d/仓库域名/目录下文件名必须是ca.crt然后重启 Docker 守护进程。举个例子你的仓库地址是registry.example.com证书文件就放在/etc/docker/certs.d/registry.example.com/ca.crt配置完成后可以用docker login registry.example.com验证能通过就说明系统已经信任它了。登录认证的坑更多是 Secret 写错。from_secret引用的是仓库级或组织级 Secret如果你在流水线配置里用了registry_username但 Secret 实际叫REGISTRY_USERNAME那就会认证失败。Drone 的 Secret 体系和环境变量一样大小写敏感且命名要全局一致这个只能靠细心。5.4 缓存与并发调优流水线跑顺之后接下来要解决的是速度问题。最常见的手段是给依赖和构建加缓存。.drone.yml里可以声明 volumes把宿主机目录挂载到容器里实现跨构建共享数据。比如 Go 项目的依赖下载和编译缓存可以这样做volumes: - name: go-cache host: path: /var/cache/drone/go-build steps: - name: 编译与单元测试 image: golang:1.20 volumes: - name: go-cache path: /root/.cache/go-build commands: - go mod download - go build -o app .Node 项目缓存 npm 或 pnpm 的 store 目录做法一样。镜像构建本身也可以加速。plugins/docker支持cache_from参数让它以之前构建的镜像作为缓存层来源settings: cache_from: - registry.example.com/myteam/app:${DRONE_COMMIT_BRANCH}这样每次构建的时候只有变化的层需要重新生成全程下来能快很多。并发方面DRONE_RUNNER_CAPACITY就是单台 Runner 的并发数上限。我一般设成 2避免一有多个仓库同时推送就把机器资源占满。如果你团队人多、项目多就多加几台 Runner每台容量保持低一点整体并发反而更稳。6. 多环境部署与发布进阶6.1 多环境流水线怎么拆单条流水线打通后下一步就是把它拆成适合多环境的结构。我的做法是两个方向按分支拆事件按环境拆步骤。测试环境通常用push触发只要代码推到主干或开发分支就自动构建并部署到测试服务器。生产环境用tag触发只有打了版本号 Tag 才会走完整发布流程。这样做的逻辑是日常提交频繁不能让每个人都手动触发测试环境部署而生产发布是低频且慎重的动作打 Tag 本身就是一次有意的确认。在同一个.drone.yml里通过每个步骤的when条件来控制执行范围。前面的示例已经把测试部署限定在push生产部署限定在tag两者互不干扰。如果团队还要出测试环境之外的预发环境就再复制一个部署步骤换一批服务器地址和容器名条件里再限定分支。6.2 回滚方案一句话切回上一个版本自动化部署做得再好也会有发错版本的时候回滚能力比上线能力更重要。我的回滚思路很简单生产容器永远不用latest做启动标签而是用不可变的 commit SHA 标签。比如这次构建出来的镜像 Tag 是abc123...那么目标服务器上跑的就是这个版本。回滚时你只需要去上一次成功构建记录里拿到上一个 commit SHA然后在目标服务器上执行docker stop prod-app docker rm prod-app docker run -d --name prod-app -p 8080:8080 registry.example.com/myteam/app:上一个commitSHA最好再把这一步也固化成一条流水线或者至少写成一个运维脚本把容器名、镜像仓库、端口都参数化这样回滚就是一行命令的事不用临时翻历史记录找镜像 Tag。线上出问题的时候人往往处于紧张状态临时敲命令很容易出错。所以回滚脚本一定要提前写好、放在服务器上、并且真的演练过一次。6.3 构建结果通知流水线跑完负责人未必会一直盯着 Drone 界面这时候通知就很有必要。Drone 本身不内置通知但你可以很轻松地在流水线最后加一个通知步骤。最简单的做法是用curl调用团队内网机器人或办公软件的 Webhook 接口把构建状态、镜像 Tag、仓库名通过 JSON 发出去。比如在.drone.yml末尾加- name: 通知 image: curlimages/curl commands: - curl -X POST -H Content-Type: application/json -d {text:构建完成: ${DRONE_REPO_NAME} ${DRONE_TAG}} http://webhook.example.com/hook when: status: - success - failure这里用了when.status来指定成功和失败都触发通知。失败通知尤其重要因为失败往往意味着有人需要立刻处理。如果你不想用通用镜像Drone 生态里也有专门的飞书、钉钉、Slack 通知插件本质都是调 Webhook选一个和团队工具匹配的就行。6.4 后续还能扩展的方向这套骨架跑起来之后可以扩展的方向其实很多说几个我觉得性价比高的。第一个方向是把镜像仓库做得更规范。比如给镜像加签名、加漏洞扫描配合仓库的保留策略避免历史镜像无限堆积。第二个方向是做制品版本管理。现在构建产物只是镜像很多团队还需要保存二进制包、前端静态包或文档可以把它们上传到制品仓库和镜像 Tag 对应起来。第三个方向是更细粒度的权限控制。Drone 的组织级配置、仓库级 Secret、运行环境隔离都可以继续深入把不同团队、不同项目的权限彻底分开。我在实际操作中体会到自动化部署最有价值的地方不在于把按钮从人工变成了自动而在于把一次发布从“靠人的记忆和经验”变成了“靠一套可重复、可审计的代码流程”。每次上线前我都会先在测试环境手动打一个 Tag 把它完整跑一遍确认日志干净后再去生产仓库打正式 Tag。这个习惯帮我避免了至少三次因为测试不充分导致的线上事故。如果你也想搭一套这样的系统建议从最小闭环开始先跑通一条 compile build image deploy 的链路再逐步加测试、通知、回滚一步到位反而容易因为坑太多而放弃。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑