- 基于 GitHub Actions 的 CI/CD 流水线实战

从代码提交到自动部署的全流程解析

本文详细介绍了如何配置 GitHub Actions 以实现持续集成与持续部署,包含核心 YAML 语法解析、自动化测试流程以及服务器自动部署的完整示例,帮助开发者提升代码交付效率

1. 背景

在AI时代,谈到软件开发经常提到持续集成(Continuous Integration)(CI)和 持续交付(Continuous Delivery)(CD),持续部署(Continuous Deployment)。

就像工厂里面的流水线一样,快速、自动化、可重复的方式从原材料生产出产品,同样的当流程固定,步骤固定之后,是否软件开发也能够快速、自动化和可持续重复的方式从源代码到发布版本。

“持续”的含义可以理解为连续的,持续的运行;有一种说法是不是一直运行,而是可以随时运行,随时触发的意思。

1.1 持续集成 CI

Continuous Integration:持续集成,简称CI,是软件开发周期的一种实践,把代码仓库(Gitlab或者Github)、构建工具(如Jenkins)和测试工具(SonarQube)集成在一起,频繁的将代码合并到主干然后自动进行构建和测试。

换一种说法就是持续集成是在源代码变更后自动检测、拉取、构建和进行单元测试的过程。

{.lightboxfig-alt=“CI” fig-align=“center”}

持续集成(CI)的基本流程:

  1. 开发人员提交代码到 Source Repository (源代码仓库)
  2. 通过 git hook 等触发 CI Server(持续集成服务器)的相关功能。执行 编译 -> 测试 -> 输出结果 等
  3. 向开发人员反馈结果的 report
提示

持续集成的 核心 在于 确保新增的代码能够与原先代码正确的集成

CI的优势:最大的优势就是节约时间

  • 易于定位错误:每一次的代码集成都需要执行相关的测试工作,持续集成频繁的集成次数天然的将复杂的代码逻辑切割为了小块,也就使得每一次测试中遇到的错误能够更加容易的被定位

  • 易于控制开发流程:更为细致的工作提交也就意味着更容易判断当前的工作进度,这对于管理者规划开发流程而言提供了一个有效的参考,同时也为开发人员省下了汇报工作的时间

  • 易于CodeReview:对于大块工作的切分自然也有助于做 CodeReview

1.2 持续交付(Continuous Delivery)

Continuous Delivery:持续交付,简称CD,是在CI的基础进行了扩展,在CI环节完成了软件构建和测试工作并形成了新的版本,那么接下来就要进行交付,而这里的交付并不是交付到生产环境,而是类生产环境(STAGING)环境,或者说是预发布环境,持续交付的核心在于能够让软件随时处于可发布的状态。

一种能够使得软件在较短的循环中可靠的发布的软件工程方法

与持续集成相比,持续交付的侧重点在于 交付,其核心对象不在于代码,而在于可交付的产物

与 持续集成 相比较,持续交付 添加了 Test -> Staging -> Production 的流程,也就是为新增的代码添加了一个保证: 确保新增的代码在生产环境中是可用的

1.3 持续部署(Continuous Deployment)

Continuous Deployment:持续部署,简称CD,它是在持续交付的基础上打通最后一公里的工作,就是把手动部署到生产环境的方式升级为自动部署。

通过自动化部署的手段将软件功能频繁的进行交付

与持续交付以及持续集成相比,持续部署强调了通过 automated deployment 的手段,对新的软件功能进行集成

{.lightboxfig-alt=“CD” fig-align=“center”}

1.4 实现方式

  1. 依托云厂商能力(SaaS化服务)

利用云厂商提供的原生 CI/CD 服务,可以快速构建并管理流水线。这类服务通常与代码托管平台深度集成,配置简单且开箱即用。常见的工具包括 GitHub Actions、GitLab CI/CD、Azure DevOps 以及阿里云效等

  1. 采用开源产品

使用开源的 CI/CD 工具(如 Jenkins、Travis CI、CircleCI 等)自建流水线

  1. 自己开发

GitOps和DevSecOp 现在一已经演变成具有标准化规范、成熟工具链和明确核心原则的现代化工程框架

1.4 应用方向

  1. Web应用与后端服务

典型流程:提交代码 → 自动构建 → 自动测试 → 自动部署到测试环境 → 自动部署到生产环境

常见工具:Github Actions; GitLab CI; Jenkins

  1. 微服务与分布式系统

微服务架构(如订单、支付、用户系统拆分)非常依赖 CI/CD

  1. 容器化与云原生部署

流程: 构建 Docker 镜像–>推送镜像到镜像仓库–>自动部署到 Kubernetes 集群

  1. MLOps(机器学习 CI/CD)

流程:数据准备 → 模型训练 → 模型评估 → 模型部署 → 模型监控
工具生态:MLflow; Kubeflow; Argo; Seldon; Pachyderm

  1. 数据工程

把软件交付过程从“人工驱动”变成“流水线系统”

2. 个人网站最简单的CI/CD

2.1 背景

之前都是使用Vscode把内容写好之后,qurato render --no-execute渲染成html到_site文件夹中,然后把_site文件夹中的内容上传到阿里云服务器中,修改的内容git push到github上的个人仓库

这样虽然也可以,但是每次写完内容之后都要手动执行命令,然后上传到服务器,这样显得比较麻烦,而且容易出错,所以想使用CI/CD的方式,实现自动化的部署。

2.2 实现方式

这里先学习采用最简单稳定的方式部署:GitHub Actions + SSH 部署

git push

GitHub Actions 自动触发

quarto render

生成 _site

rsync 上传

阿里云 Nginx 自动更新网站

2.3 服务器端准备

因为使用宝塔面板,默认文件夹在/www/wwwroot文件夹下,所以用户权限要控制好

  1. 服务器版本确定 cat /etc/os-release(# Alibaba Cloud Linux (RHEL 系))
  2. SSH 登录服务器,确保 rsync 已安装 sudo yum install -y rsync
  3. 创建deploy用户,sudo adduser deploy;RHEL 系没有 –disabled-password,手动锁定密码 sudo passwd -l deploy
  4. 让 deploy 用户有权限写入网站目录
sudo usermod -aG www deploy
sudo chmod -R 775 /www/wwwroot/beautyhubcode
注记

sudo chmod -R 775 /www/wwwroot/beautyhubcode chmod: changing permissions of '/www/wwwroot/beautyhubcode/.user.ini': Operation not permitted 报错

  • 报错是因为 .user.ini 文件被设置了特殊的保护属性(不可变属性 immutable)。在 LNMP 等 PHP 网站环境中,为了防止跨目录攻击,系统通常会锁定这个文件。即使你是 root 用户,也无法直接修改或删除它
  1. 查看文件属性,如果输出结果中包含 i

lsattr /www/wwwroot/beautyhubcode/.user.ini

  1. 移除不可变属性 chattr -i /www/wwwroot/beautyhubcode/.user.ini

  2. 重新执行修改权限命令

  3. 改回权限,防止被恶意攻击 chattr +i /www/wwwroot/beautyhubcode/.user.ini

  1. 在本地电脑上生成密钥对,直接Enter即可,主要是公钥-私钥进行通讯

但对于 GitHub Actions 部署场景,通常选择在本地生成密钥对,而不是在服务器生成

ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_actions_deploy

  1. 把公钥放到阿里云服务器里面
# 创建文件夹
sudo mkdir -p /home/deploy/.ssh

# 创建文件
sudo touch /home/deploy/.ssh/authorized_keys

# 文件权限修改
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy/.ssh

# 把公钥内容写入
ssh-copy-id -i ~/.ssh/github_actions_deploy.pub deploy@你的服务器IP
注记

虽然创建用户的时候,使用了sudo passwd -l deploy,不需要密码,但是在ssh-copy-id的时候没有验证途径所以还是把公钥的内容复制在 sudo vim /home/deploy/.ssh/authorized_keys中即可

  1. 测试连接

ssh -i ~/.ssh/github_actions_deploy deploy@你的服务器IP

测试提示,即表示连接成功

Welcome to Alibaba Cloud Elastic Compute Service ! Updates Information Summary: available

2.4 Github仓库端

git和hgithub的使用可以查看之前的详细内容,这里登录Github website仓库中设置

找到→ Settings → Secrets and variables → Actions

git action

然后在Secrets中点击New repository secret,每个名字和变量对应填写即可

Secret 名称
VPS_HOST 服务器 IP 地址
VPS_USER deploy
VPS_SSH_KEY 私钥完整内容(执行 cat ~/.ssh/github_actions_deploy 的输出)
提示

私钥的内容类似下方,必须全部复制进去

-----BEGIN OPENSSH PRIVATE KEY-----
xxxxx
xxxxx
-----END OPENSSH PRIVATE KEY-----

2.5 创建Workfolw

  1. 分析流程

先分析下流程,按照流程来学deploy文件

VS Code

   ├── 编辑 qmd
   ├── git add .
   ├── git commit
   └── git push


      GitHub Actions

            ├── quarto render --no-execute
            ├── 生成 _site/
            ├── SSH 登录服务器
            └── rsync _site/

      /www/wwwroot/beautyhubcode

               网站更新

此时项目目录就变成了

beautyhubcode/
├── .github/
│   └── workflows/
│       └── deploy.yml
├── _quarto.yml
├── index.qmd
├── posts/
├── images/
├── styles.css
└── .gitignore
  1. 编写deploy.yml文件
name: Deploy Quarto Website

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Setup Quarto
        uses: quarto-dev/quarto-actions/setup@v2

      - name: Render Website
        run: |
          quarto render --no-execute

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh

          echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/id_ed25519

          chmod 600 ~/.ssh/id_ed25519

          ssh-keyscan -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts

      - name: Deploy Website
        run: |
          rsync -avz \
            --exclude='.git/'\
            --exclude='.github/' \
            _site/ \
            ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }}:/www/wwwroot/beautyhubcode/

2.6 底层运行

github仓库的设置下找到Actions的选项,点击进去就可以看到自动化的过程

git action

  1. Git Push 触发事件

每当你执行git push后Github收到信的commit,然后检查仓库中的.github/workflows/deploy.yml,发现配置

on:
  push:
    branches:
      - main

于是产生一个事件Push Event,并创建一个workflow Run

  1. Github 创建Rnuuer

Github会启动一台临时Linux虚拟机Ubuntu Latest Runner,非常类似Ubuntu Latest Runner,实际上是Github管理的云主机

  1. Checkout 代码

在workflow中写- uses: actions/checkout@v4,实际上执行- uses: actions/checkout@v4,相当于把你的仓库克隆到云主机上

  1. Setup Quarto

在YAML中写的是

      - name: Setup Quarto
        uses: quarto-dev/quarto-actions/setup@v2

实际上执行的是- uses: quarto-dev/quarto-actions/setup@v2,相当于在云主机上安装Quarto

  1. Render Website

在YAML中写的是

      - name: Render Website
        run: |
          quarto render --no-execute
  1. Github Secret注入

在设置中添加了

VPS_HOST
VPS_USER
VPS_SSH_KEY

然后把私钥写入到云主机中,并设置权限

  1. SSH认证

将github云服务器与网站部署的服务器进行ssh认证,确保后续能够通过ssh连接到网站服务器

  1. Rsync同步

rsync -avz --delete _site/ deploy@server:/www/wwwroot/beautyhubcode/

  • --delete 表示网站服务器上的文件比本地少,则删除
  • 同步是比较文件的不同,然后覆盖,不是所有的内容都传输,就像github一样,比较差异再进行上传
  1. 网站更新

网站服务器接收到文件后,进行更新,完成部署