CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
DevOps 入门实战/课时/GitHub Actions
RawBlame
课时目录12 节

DevOps 入门实战

  1. 01DevOps 入门
  2. 02操作系统
  3. 03Git 与 GitHub
  4. 04脚本语言
  5. 05网络协议
  6. 06Docker
  7. 07AWS
  8. 08Terraform
  9. 09Ansible
  10. 10GitHub Actions
  11. 11Nginx
  12. 12综合练习

GitHub Actions

CI/CD 流水线。

30 分钟

GitHub Actions

这一课你将能做到

  1. 为 Spring Boot 项目编写一条完整的 CI 流水线:编译、测试、打包、构建镜像
  2. 配置 GitHub Secrets 管理密钥,让流水线自动部署到服务器
  3. 说清楚 push / pull_request / workflow_dispatch 等触发器的区别和使用场景

为什么要学

你现在的部署流程:本地 mvn package → scp 上传 → SSH 重启服务。问题显而易见:你休假时没人能部署;你忘了跑测试就直接上线了;你在咖啡馆用别人电脑没法部署。CI/CD(持续集成/持续部署)的核心思想:代码一旦 push 到仓库,构建、测试、部署全部自动完成,不依赖任何个人的电脑。

人话:GitHub Actions 就是 GitHub 提供的「云上脚本执行器」。你在仓库里放一个 YAML 文件描述「代码 push 后要做什么」,GitHub 就分配一台虚拟机帮你执行:拉代码 → 装 JDK → Maven 打包 → 跑测试 → 构建 Docker 镜像 → SSH 到你服务器部署。全程自动化,执行记录公开可查。

先建立图像

一条典型的 CI/CD 流水线:

git push origin main
        │
        ▼  GitHub 检测到 push 事件
┌─────────────────────────────────┐
│      GitHub Actions Runner      │
│  ┌─────────┐   ┌─────────┐     │
│  │ Job: CI │ → │ Job: CD │     │
│  │ 构建+测试│   │ 部署    │     │
│  └─────────┘   └─────────┘     │
└─────────────────────────────────┘
        │                │
        ▼                ▼
   测试报告/镜像      SSH → 服务器重启容器

核心概念关系:
Workflow(流水线)──包含──▶ Job(任务,并行跑在不同虚拟机上)
                              │
                              └──包含──▶ Step(步骤,串行执行)
                                           │
                                           └──▶ 每个 step 是一个 shell 命令或 Action(官方/社区封装好的操作)

跟着做

步骤 1:创建第一个 Workflow——CI(持续集成)

在仓库根目录创建 .github/workflows/ci.yml:

name: CI

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

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      # 步骤 1:拉代码(官方 Action)
      - uses: actions/checkout@v4

      # 步骤 2:装 JDK 17
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
          cache: maven        # 缓存 Maven 依赖,构建提速 5 倍

      # 步骤 3:编译 + 跑测试
      - name: Build and Test
        run: mvn clean verify

      # 步骤 4:上传构建产物(供后续 job 或人工下载)
      - name: Upload JAR
        uses: actions/upload-artifact@v4
        with:
          name: app-jar
          path: target/*.jar
          retention-days: 7

push 到 GitHub 后,仓库的 Actions 标签页就能看到流水线运行记录,绿勾 = 通过,红叉 = 失败(点进去看日志)。

步骤 2:加入 Docker 镜像构建与推送

在 ci.yml 中追加第二个 job:

  docker:
    needs: build-and-test          # 依赖 CI 通过才执行
    runs-on: ubuntu-latest
    # 只在 main 分支 push 时才构建镜像(PR 不构建)
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'

    steps:
      - uses: actions/checkout@v4

      # 登录镜像仓库(以阿里云 ACR 为例,Docker Hub 类似)
      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: registry.cn-hangzhou.aliyuncs.com
          username: ${{ secrets.ACR_USERNAME }}
          password: ${{ secrets.ACR_PASSWORD }}

      # 构建并推送(利用第 6 课写的多阶段 Dockerfile)
      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            registry.cn-hangzhou.aliyuncs.com/myns/myapp:latest
            registry.cn-hangzhou.aliyuncs.com/myns/myapp:${{ github.sha }}
          cache-from: type=gha     # GitHub 缓存层,加速构建
          cache-to: type=gha,mode=max

步骤 3:配置 Secrets(密钥永远不进代码)

GitHub 仓库 → Settings → Secrets and variables → Actions → New repository secret:

  • ACR_USERNAME:镜像仓库用户名
  • ACR_PASSWORD:镜像仓库密码
  • SERVER_HOST:服务器 IP
  • SERVER_SSH_KEY:部署用的 SSH 私钥(整个私钥文件内容粘贴进去)

YAML 里用 ${{ secrets.XXX }} 引用,日志中会自动打码显示 ***。

步骤 4:CD——自动部署到服务器

追加部署 job:

  deploy:
    needs: docker
    runs-on: ubuntu-latest
    # 只允许 main 分支部署到生产
    environment: production          # 可配置「需要人工审批」的保护规则

    steps:
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: appuser
          key: ${{ secrets.SERVER_SSH_KEY }}
          script: |
            cd /opt/myapp
            docker compose pull app
            docker compose up -d app
            docker image prune -f
            # 健康检查,失败则整个流水线标红
            sleep 10
            curl -f http://localhost:8080/actuator/health

现在完整的流水线:push main → 跑测试 → 构建镜像 → 推送仓库 → SSH 到服务器 → docker compose up -d → 健康检查。任何人 push 代码都会触发同一套流程,结果在 PR/Commit 旁直接可见。

步骤 5:手动触发与定时任务

on:
  workflow_dispatch:               # 在 GitHub 网页上点按钮手动触发
    inputs:
      environment:
        description: '部署环境'
        required: true
        default: 'staging'
        type: choice
        options: [staging, production]

  schedule:
    - cron: '0 18 * * *'           # 每天 UTC 18:00(北京时间凌晨 2 点)跑,适合夜间构建/数据备份

手动触发的参数在 step 里用 ${{ inputs.environment }} 引用。

讲清楚要点

  1. 事件驱动:Actions 的一切由 Git 事件触发——push、PR、tag、定时、手动。理解事件 = 理解第 3 课说的「Git 是自动化的扳机」。
  2. Job 并行、Step 串行:同一个 job 里的 step 按顺序执行;不同 job 默认并行(在不同虚拟机上),用 needs 声明依赖后串行。CI 和 CD 分 job,是因为 PR 只需要 CI 不需要 CD。
  3. Secrets 只出不进:secret 写入后任何人(包括你自己)都无法在网页上读回,只能覆盖。日志里出现 secret 值会自动打码。这是唯一合法的密钥管理方式。
  4. Runner 是临时虚拟机:每次运行都是全新的 ubuntu 环境,跑完即销毁。所以不要指望文件在两次运行之间保留——产物用 artifact 传递,缓存用 cache action。
  5. environment 保护规则:生产环境部署配置 environment: production 后,可以在仓库设置里要求「指定人员审批后才能执行」,防止误触发。

你可能会懵的地方

  • GitHub Actions 免费吗? 公开仓库完全免费;私有仓库每月 2000 分钟免费额度(Linux runner),个人项目绰绰有余。超时按分钟计费。

  • Action 和 Step 有什么区别? Step 是执行单元(一条 shell 命令或一个 Action 调用);Action 是封装好的可复用组件(如 actions/checkout@v4),官方和社区市场有上万个,避免重复造轮子。

  • 流水线失败了怎么调试? 点进失败的 run → 点失败的 job → 展开红色的 step 看完整日志。还可以勾选「Enable debug logging」重跑获取更详细输出。复杂问题可用 tmate action 直接 SSH 进 runner 调试。

  • github.sha 这种变量哪来的? GitHub 注入的上下文变量,常用的还有:github.ref(分支/tag)、github.actor(触发者)、github.event_name(事件类型)、github.run_number(第几次运行)。

  • 为什么 PR 触发的流水线读不到我的 secrets? 安全设计:来自 fork 仓库的 PR 默认拿不到 secrets(防止别人提个 PR 打印你的密钥)。受信任的内部 PR 可以正常读取。

错法对照

错法问题正解
把密码写死在 YAML 里进 Git 历史永久泄露全部走 Secrets
PR 也触发生产部署未评审代码直接上线部署 job 加 if: github.ref == 'refs/heads/main'
镜像只打 latest tag无法回滚到具体版本同时打 commit sha tag
测试失败也继续部署带病上线job 间用 needs 串联,失败自动中断
构建不缓存依赖每次全量下载 Maven 依赖,10 分钟起步setup-java 开 cache: maven,Docker 开 cache-from: type=gha

卡点急救

  1. 流水线报 Permission denied (publickey):secrets 里的 SSH 私钥格式被破坏了——粘贴时必须包含 -----BEGIN ...----- 和 -----END ...----- 完整内容,且服务器 ~/.ssh/authorized_keys 里有对应公钥。
  2. 健康检查步骤失败但服务实际起来了:sleep 10 不够,Spring Boot 启动慢。改成循环探测:for i in {1..30}; do curl -sf ... && break; sleep 2; done。
  3. mvn 命令找不到:runner 默认没有 Java/Maven,必须先执行 actions/setup-java@v4 步骤,顺序不能错。

面试常问

  • CI 和 CD 的区别?你们的流水线怎么设计的? CI(持续集成):代码合入主干前自动构建、测试,保证每次合入都是可用的;CD(持续交付/部署):CI 通过后自动发布到环境。回答时结合本课程的实践:PR 触发 CI(编译+测试),main 分支 push 触发完整 CD(镜像构建+推送+SSH 部署+健康检查),生产环境加了人工审批 environment。

  • 流水线里的密钥怎么管理? 全部走 GitHub Secrets(或 Vault 等专业密钥管理),YAML 只引用变量名;Secrets 写入后不可读回、日志自动打码;服务器上只用部署专用密钥对,权限最小化(只允许执行 docker compose 命令,可配 sudoers 限制)。

  • 如果部署到一半失败了怎么办? 分层回答:①流水线层面,健康检查失败会自动标红,通知到开发者;②应用层面,Docker 镜像不可变,回滚 = docker compose up -d 切回上一个 sha tag 的镜像,秒级完成;③预防层面,重要变更先发 staging 环境验证,或用蓝绿/金丝雀发布降低爆炸半径。

自测三问

  1. 为什么 PR 触发的 workflow 不应该包含部署 job?用什么条件控制?
  2. needs、if、runs-on 三个关键字分别控制什么?
  3. 你的流水线每次都要 8 分钟,其中 5 分钟在下载 Maven 依赖,怎么优化?

小结一句话

GitHub Actions 把「push 代码」变成流水线的扳机,让构建、测试、部署成为每一次提交的自动后续动作。

延伸

  • GitHub Actions 官方文档
  • 下一课:Nginx——给部署好的应用加上反向代理、HTTPS 和静态资源服务。
加载本节练习…
← 上一课Ansible下一课 →Nginx