首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >自建 CI CD 教程:代码提交自动构建与部署流水线

自建 CI CD 教程:代码提交自动构建与部署流水线

原创
作者头像
hollyx
发布2026-09-16 10:01:29
发布2026-09-16 10:01:29
1040
举报

摘要

CI/CD 把「提交代码到服务上线」这段人工操作变成自动执行的流水线,减少重复劳动和人为失误。本文基于自建 Git 服务的 Actions 能力搭建一条完整流水线,涵盖执行器部署与注册、工作流编写、构建与测试、镜像构建、自动部署到目标服务器、密钥管理与安全边界,以及构建失败和部署卡住的排查方法。

一、流水线要做的事与前置条件

一条典型的流水线包含这些环节:

  1. 检测到代码推送或合并请求。
  2. 拉取代码,准备构建环境。
  3. 执行代码检查和自动化测试。
  4. 构建产物,例如编译后的文件或容器镜像。
  5. 把产物推送到仓库或直接部署到目标环境。
  6. 反馈执行结果。

前置条件:

项目

说明

Git 服务

已部署并可正常推送代码的自建 Git 服务

执行器机器

运行构建任务的机器,可与 Git 服务同机或独立

容器环境

执行器上需要 Docker

目标环境

部署目标服务器,可与执行器分开

执行器建议独立部署。构建任务会占用大量 CPU 和磁盘 IO,与 Git 服务共用一台机器时,构建高峰会拖慢代码托管服务的响应。如果资源有限,至少要给构建设置资源上限。

执行器的资源规划:

项目

最低配置

建议配置

CPU

2 核

4 核及以上

内存

2 GB

4~8 GB

磁盘

40 GB

100 GB 以上

磁盘往往被低估。每次构建都会拉取依赖、生成中间产物、缓存镜像层,累积很快。构建频繁的项目一周就能占掉几十 GB。

二、部署并注册执行器

先在 Git 服务的管理后台开启 Actions 功能,并获取执行器注册令牌。令牌位于管理后台的执行器管理页面,可以创建实例级、组织级或仓库级的令牌,按需要的作用范围选择。

在执行器机器上部署。用 Docker 方式运行:

代码语言:bash
复制
mkdir -p ~/apps/act-runner && cd ~/apps/act-runner

编写 compose.yaml

代码语言:yaml
复制
services:
  runner:
    image: gitea/act_runner:0.2.11
    environment:
      GITEA_INSTANCE_URL: https://git.example.com
      GITEA_RUNNER_REGISTRATION_TOKEN: 替换为注册令牌
      GITEA_RUNNER_NAME: runner-01
      GITEA_RUNNER_LABELS: ubuntu-latest:docker://node:20-bookworm
    volumes:
      - ./data:/data
      - /var/run/docker.sock:/var/run/docker.sock
    restart: unless-stopped

这里有个必须说明的安全事项:挂载 Docker socket 意味着执行器容器可以完全控制宿主机的 Docker,等同于宿主机的 root 权限。这是运行容器化构建任务的常见做法,但需要清楚它的影响:

  • 执行器机器不应与生产服务混用,建议单独一台。
  • 只允许可信来源的代码在这台执行器上运行。如果仓库接受外部贡献,来自不受信任分支的工作流可能执行任意命令。
  • 对外部贡献的合并请求,建议配置为需要人工批准后才运行流水线。

启动并确认注册成功:

代码语言:bash
复制
docker compose up -d
docker compose logs runner --tail 30

日志中出现注册成功和监听任务的提示后,到 Git 服务的管理后台确认执行器已在线。

三、编写第一条流水线

在仓库中创建工作流文件 .gitea/workflows/ci.yaml

代码语言:yaml
复制
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: 检出代码
        uses: actions/checkout@v4

      - name: 安装依赖
        run: |
          npm ci

      - name: 代码检查
        run: |
          npm run lint

      - name: 运行测试
        run: |
          npm test

推送后到仓库的 Actions 页面查看执行情况。首次运行需要拉取容器镜像,耗时较长。

先让这条最简流水线跑通再加功能。 一次性写一个复杂的多阶段流水线,出问题时很难定位是哪个环节的配置问题。

四、构建容器镜像

在流水线中构建镜像并推送到镜像仓库:

代码语言:yaml
复制
  build:
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'
    steps:
      - name: 检出代码
        uses: actions/checkout@v4

      - name: 登录镜像仓库
        run: |
          echo "${{ secrets.REGISTRY_PASSWORD }}" | \
            docker login ${{ secrets.REGISTRY_URL }} \
            -u "${{ secrets.REGISTRY_USER }}" --password-stdin

      - name: 构建并推送镜像
        run: |
          IMAGE="${{ secrets.REGISTRY_URL }}/myapp:${GITHUB_SHA::7}"
          docker build -t "$IMAGE" .
          docker push "$IMAGE"
          echo "IMAGE=$IMAGE" >> $GITHUB_ENV

几个要点:

needs: test 表示这个任务依赖测试通过。测试失败时不会执行构建,避免把有问题的代码打成镜像。

if 条件限制只在主分支执行构建和推送,特性分支只跑测试。这能避免每个分支都产生一堆镜像。

镜像标签使用提交哈希而不是滚动标签。这样每个镜像对应一个确定的代码版本,出问题时能准确回滚到某次提交。用滚动标签会让「当前部署的是哪个版本」变得无法追溯。

凭据通过 secrets 传入,不要写在工作流文件里。工作流文件在仓库中是可见的,任何有读权限的人都能看到。

在仓库设置的 Actions secrets 中添加所需的凭据变量。

五、自动部署到目标服务器

部署环节有几种做法,安全性和复杂度不同。

做法一:SSH 执行部署命令

最直接的方式:

代码语言:yaml
复制
  deploy:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    steps:
      - name: 配置 SSH 密钥
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts

      - name: 执行部署
        run: |
          ssh -i ~/.ssh/id_ed25519 \
            ${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} \
            "cd /opt/myapp && docker compose pull && docker compose up -d"

这种做法的安全要点必须讲清楚

  • 部署密钥应当是专用密钥,不要复用你个人的 SSH 密钥。
  • 部署账号应当只具备部署所需的最小权限,不要用 root。可以创建专用账号,只授予操作特定目录和重启特定服务的权限。
  • 目标服务器的 SSH 端口应当只对执行器所在 IP 放通,不要对全网开放。轻量应用服务器在实例详情页的「防火墙」页签添加规则时可指定来源;云服务器 CVM 在安全组入站规则中同样支持按 IP 限定。
  • ssh-keyscan 这一步是把目标主机的指纹加入信任列表。更严格的做法是预先把已知的主机指纹存在 secrets 中并校验,避免中间人风险。

做法二:目标服务器主动拉取

反向思路:目标服务器定期检查镜像仓库,发现新版本后自行更新。这样执行器不需要持有目标服务器的登录凭据,攻击面更小。代价是部署不是即时的,有检查间隔的延迟。

做法三:部署到容器集群

如果目标是 Kubernetes 集群,通过 kubectl 更新镜像版本。同样要注意 kubeconfig 属于高权限凭据,应当使用权限受限的服务账号,而不是集群管理员凭据。

六、验证流水线是否真正可用

分层验证,不要只看流水线显示成功。

执行器在线:管理后台的执行器列表中状态为空闲或运行中。

推送能触发流水线:向配置的分支推送一次提交,确认 Actions 页面出现新的执行记录。

测试环节真的在跑:故意引入一个会失败的测试,确认流水线状态变为失败。这一项很重要——如果测试步骤配置有误导致实际跳过了测试,流水线会一直显示成功,但完全没起到把关作用。验证后记得改回来。

构建产物正确:确认镜像已推送到仓库,且标签符合预期:

代码语言:bash
复制
docker pull 镜像仓库地址/myapp:提交哈希前7位
docker inspect 镜像名 | grep -i created

部署确实生效:这一步最容易被忽略。流水线显示部署成功,不代表服务真的更新了。到目标服务器确认:

代码语言:bash
复制
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"

确认运行中的镜像标签是刚构建的那个。再访问服务确认新功能已生效。

失败能被感知:确认流水线失败时有通知。没有通知的流水线,失败了往往几天后才被发现。

七、常见问题与排查

执行器一直显示离线

检查执行器容器是否运行、注册令牌是否有效、执行器机器能否访问 Git 服务地址。查看日志:

代码语言:bash
复制
docker compose logs runner --tail 50

任务一直处于排队状态

多为标签不匹配。工作流中 runs-on 指定的标签必须与执行器注册时声明的标签一致。检查执行器的标签配置。

构建时提示找不到命令

执行器使用的容器镜像中不包含该命令。要么换一个包含所需工具的镜像,要么在工作流中先安装。

依赖安装很慢

国内环境拉取境外源较慢。可以在工作流中配置国内镜像源,或使用缓存机制避免每次重新下载。

镜像推送失败

检查凭据是否正确、镜像仓库地址是否可达、是否有推送权限。凭据错误时日志会明确提示认证失败。

部署步骤卡住不动

常见原因是 SSH 命令等待交互输入。确保命令是非交互的,必要时加上相应参数。也要确认目标服务器的 SSH 端口对执行器可达。

磁盘被构建缓存占满

代码语言:bash
复制
docker system df
df -h

清理未使用的镜像和构建缓存:

代码语言:bash
复制
docker system prune -af --volumes

建议在流水线中加入定期清理步骤,或用定时任务处理。这是自建执行器最常见的运维问题。

并发构建互相干扰

多个任务同时构建时可能争抢端口或临时目录。给构建任务使用唯一的临时目录名,避免固定名称冲突。

八、安全边界与维护

凭据管理是重点

  • 所有凭据通过 secrets 传入,不写在工作流文件中。
  • 部署密钥专用且权限最小化。
  • 定期轮换凭据,离职人员相关的凭据及时吊销。
  • 注意日志输出。构建日志可能被有仓库权限的人查看,不要在脚本中打印凭据内容。

限制外部贡献的执行

如果仓库接受外部提交,来自不受信任分支的工作流可能执行任意代码。配置为需要人工批准后才运行流水线,或对外部贡献使用隔离的执行器。

执行器隔离

执行器机器不要与生产服务混用。构建过程会拉取大量第三方依赖,存在供应链风险,隔离能限制影响范围。

变更前创建快照

调整执行器配置或升级前给实例创建快照。回滚会把整块系统盘恢复到快照时间点,之后写入的数据会被清除,运行中的实例会自动关机。使用存储型套餐的实例不支持创建快照。

备份要点

需要备份的是工作流定义(它们在代码仓库里,随仓库备份即可)和执行器配置。构建缓存和中间产物不需要备份,可以重新生成。

保留可回滚的能力

这是 CI/CD 中容易被忽视的一点。自动部署提高了效率,也提高了把问题快速推向生产的速度。建议:

  • 镜像使用不可变的版本标签,保留历史版本以便回滚。
  • 数据库结构变更与代码部署分离,变更前先备份。
  • 重要服务考虑先部署到小部分实例验证,再全量推开。
  • 部署前给目标环境创建快照,出问题时能快速恢复整机状态。

日常检查

  • 关注流水线失败率,反复失败的步骤要及时修复而不是重试掩盖。
  • 定期清理磁盘。
  • 检查构建耗时趋势,明显变慢时排查原因。
  • 审阅 secrets 列表,清理不再使用的凭据。

流水线跑通之后,如果需要为构建和部署环节建立监控告警,或把制品统一归档管理,可以作为下一步方向。

构建任务对算力和磁盘 IO 要求较高,云服务器 CVM 的规格可按需调整,适合作为执行器;构建产物和备份归档可使用对象存储 COS;部署目标为容器集群时可使用容器服务

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 摘要
  • 一、流水线要做的事与前置条件
  • 二、部署并注册执行器
  • 三、编写第一条流水线
  • 四、构建容器镜像
  • 五、自动部署到目标服务器
  • 六、验证流水线是否真正可用
  • 七、常见问题与排查
  • 八、安全边界与维护
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档