title: "CI/CD 流水线设计:从 GitHub Actions 到自托管 Runner 的完整实践"
date: "2026-07-10"
tags: ["CI/CD", "GitHub Actions", "DevOps", "自动化"]
CI/CD 流水线设计:从 GitHub Actions 到自托管 Runner 的完整实践
持续集成和持续部署是现代软件开发的标配。但很多团队的 CI/CD 流水线要么太简单(只是跑个测试),要么太复杂(维护成本比收益还高)。
基础流水线
一个典型的 Node.js 项目流水线:
YAML
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Lint
run: pnpm lint
- name: Type check
run: pnpm type-check
- name: Unit tests
run: pnpm test:unit --coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: pnpm build
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/多环境部署
YAML
deploy-staging:
needs: build
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
environment: staging
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: build-output
- name: Deploy to staging
run: |
rsync -avz dist/ user@staging-server:/var/www/app/
ssh user@staging-server 'systemctl restart app'
deploy-production:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: build-output
- name: Deploy to production
run: |
kubectl apply -f k8s/
kubectl rollout status deployment/app自托管 Runner
GitHub Actions 的云端 Runner 有并发限制和超时限制。对于大型项目,自托管 Runner 更合适。
安装 Runner
BASH
# 下载 Runner
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.317.0.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.317.0/actions-runner-linux-x64-2.317.0.tar.gz
# 解压
tar xzf actions-runner-linux-x64-2.317.0.tar.gz
# 配置
./config.sh --url https://github.com/your-org/your-repo \
--token YOUR_REGISTRATION_TOKEN
# 安装为服务
sudo ./svc.sh install
sudo ./svc.sh startDocker 化 Runner
DOCKERFILE
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
curl git docker.io nodejs npm \
&& rm -rf /var/lib/apt/lists/*
RUN useradd -m runner
USER runner
WORKDIR /home/runner
RUN curl -o actions-runner.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.317.0/actions-runner-linux-x64-2.317.0.tar.gz \
&& tar xzf actions-runner.tar.gz \
&& rm actions-runner.tar.gz
COPY start.sh /home/runner/
ENTRYPOINT ["/home/runner/start.sh"]BASH
#!/bin/bash
# start.sh
./config.sh --url $REPO_URL --token $RUNNER_TOKEN --unattended
./run.sh缓存优化
依赖缓存
YAML
- name: Cache pnpm dependencies
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}Docker 层缓存
YAML
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v5
with:
push: true
tags: registry.example.com/app:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max并行执行
YAML
jobs:
lint:
runs-on: ubuntu-latest
steps:
- run: pnpm lint
type-check:
runs-on: ubuntu-latest
steps:
- run: pnpm type-check
test-unit:
runs-on: ubuntu-latest
steps:
- run: pnpm test:unit
test-e2e:
runs-on: ubuntu-latest
steps:
- run: pnpm test:e2e
build:
needs: [lint, type-check, test-unit, test-e2e]
runs-on: ubuntu-latest
steps:
- run: pnpm build矩阵测试
YAML
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: pnpm test安全实践
密钥管理
YAML
- name: Deploy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: aws s3 sync dist/ s3://my-bucket/依赖扫描
YAML
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}OIDC 认证(替代长期密钥)
YAML
permissions:
id-token: write
contents: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActions
aws-region: us-east-1监控与告警
YAML
- name: Notify on failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}性能优化清单
| 优化项 | 效果 | 实施难度 |
|--------|------|----------|
| 依赖缓存 | 减少 50%+ 安装时间 | 低 |
| 并行执行 | 减少 60%+ 总时间 | 中 |
| 自托管 Runner | 无并发限制 | 中 |
| Docker 层缓存 | 减少 70%+ 构建时间 | 中 |
| 增量构建 | 减少 80%+ 构建时间 | 高 |
CI/CD 流水线的目标是让开发者专注于写代码,而不是等待构建和部署。持续优化流水线,是提升团队效率的高杠杆投入。
读者评论 4