GitHub Actions高级用法
约 1543 字大约 5 分钟
github-actionscicd
2025-06-28
GitHub Actions 是 GitHub 内置的 CI/CD 平台,通过 YAML 工作流文件实现自动化构建、测试和部署。本文将深入讲解 Actions 的高级特性,包括 Composite Actions、Reusable Workflows、安全加固等。
Workflow 语法进阶
完整的工作流示例
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options:
- staging
- production
skip_tests:
description: 'Skip tests'
type: boolean
default: false
schedule:
- cron: '0 2 * * 1' # 每周一 UTC 2:00
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # 取消同分支的旧 Run
permissions:
contents: read
packages: write
id-token: write # OIDC Token
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
test:
needs: lint
runs-on: ubuntu-latest
if: ${{ !inputs.skip_tests }}
strategy:
fail-fast: false
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, macos-latest]
exclude:
- node-version: 18
os: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: test-results-${{ matrix.node-version }}-${{ matrix.os }}
path: test-results/
retention-days: 7
build:
needs: test
runs-on: ubuntu-latest
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
image-digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=ref,event=branch
type=semver,pattern={{version}}
- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64Composite Actions
Composite Action 将多个步骤封装为可复用的单元:
# .github/actions/setup-project/action.yaml
name: 'Setup Project'
description: 'Install dependencies and setup build environment'
inputs:
node-version:
description: 'Node.js version'
required: false
default: '20'
install-playwright:
description: 'Install Playwright browsers'
required: false
default: 'false'
outputs:
cache-hit:
description: 'Whether cache was hit'
value: ${{ steps.cache.outputs.cache-hit }}
runs:
using: 'composite'
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- name: Cache dependencies
id: cache
uses: actions/cache@v4
with:
path: |
node_modules
~/.cache
key: deps-${{ runner.os }}-node${{ inputs.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
deps-${{ runner.os }}-node${{ inputs.node-version }}-
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: npm ci
- name: Install Playwright
if: inputs.install-playwright == 'true'
shell: bash
run: npx playwright install --with-deps chromium使用 Composite Action:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
with:
node-version: '20'
install-playwright: 'true'
- run: npm testReusable Workflows
可复用工作流允许在不同仓库间共享完整的工作流:
# .github/workflows/reusable-deploy.yaml
name: Reusable Deploy Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
image-tag:
required: true
type: string
replicas:
required: false
type: number
default: 3
secrets:
KUBE_CONFIG:
required: true
SLACK_WEBHOOK:
required: false
outputs:
deploy-url:
description: 'Deployment URL'
value: ${{ jobs.deploy.outputs.url }}
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
outputs:
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- name: Configure kubectl
uses: azure/setup-kubectl@v3
- name: Set kubeconfig
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > ~/.kube/config
- name: Deploy
id: deploy
run: |
kubectl set image deployment/app \
app=${{ inputs.image-tag }} \
-n ${{ inputs.environment }}
kubectl rollout status deployment/app \
-n ${{ inputs.environment }} \
--timeout=300s
URL=$(kubectl get ingress app -n ${{ inputs.environment }} -o jsonpath='{.spec.rules[0].host}')
echo "url=https://${URL}" >> $GITHUB_OUTPUT
- name: Notify Slack
if: always() && secrets.SLACK_WEBHOOK != ''
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Deploy to ${{ inputs.environment }}: ${{ job.status }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}调用可复用工作流:
# .github/workflows/pipeline.yaml
jobs:
build:
# ... build job ...
deploy-staging:
needs: build
uses: ./.github/workflows/reusable-deploy.yaml
with:
environment: staging
image-tag: ${{ needs.build.outputs.image-tag }}
secrets:
KUBE_CONFIG: ${{ secrets.STAGING_KUBE_CONFIG }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
deploy-production:
needs: [build, deploy-staging]
uses: ./.github/workflows/reusable-deploy.yaml
with:
environment: production
image-tag: ${{ needs.build.outputs.image-tag }}
replicas: 5
secrets:
KUBE_CONFIG: ${{ secrets.PROD_KUBE_CONFIG }}Matrix Strategy
jobs:
test:
strategy:
fail-fast: false # 不因一个失败取消其他
max-parallel: 4 # 最大并行数
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python: ['3.10', '3.11', '3.12']
database: [postgres, mysql]
include:
# 额外组合
- os: ubuntu-latest
python: '3.12'
database: postgres
coverage: true
exclude:
# 排除组合
- os: windows-latest
database: mysql
runs-on: ${{ matrix.os }}
services:
db:
image: ${{ matrix.database == 'postgres' && 'postgres:16' || 'mysql:8.0' }}
env:
POSTGRES_PASSWORD: test
MYSQL_ROOT_PASSWORD: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- run: pip install -r requirements.txt
- run: pytest
- if: matrix.coverage
run: pytest --cov --cov-report=xmlArtifacts 与 Caching
Artifacts(构建产物)
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: dist-${{ github.sha }}
path: |
dist/
!dist/**/*.map
retention-days: 30
compression-level: 6
# 在后续 Job 中下载
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: dist-${{ github.sha }}
path: dist/Caching(缓存)
- name: Cache node modules
uses: actions/cache@v4
with:
path: |
node_modules
~/.npm
key: node-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
node-${{ runner.os }}-
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: docker-${{ runner.os }}-${{ hashFiles('Dockerfile') }}
restore-keys: |
docker-${{ runner.os }}-Environments
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://app.example.com
steps:
- name: Deploy
run: echo "Deploying to production"
env:
API_KEY: ${{ secrets.PROD_API_KEY }} # 环境级别 SecretEnvironment 功能:
- Protection Rules:需要人工审批
- Wait Timer:部署前等待指定时间
- Deployment Branches:限制可部署的分支
- Environment Secrets:环境级别的密钥隔离
OIDC Tokens(无密钥认证)
jobs:
deploy:
permissions:
id-token: write # 必需
contents: read
runs-on: ubuntu-latest
steps:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
aws-region: us-east-1
# 无需 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY
- name: Deploy to EKS
run: |
aws eks update-kubeconfig --name production
kubectl apply -f k8s/Self-hosted Runners
jobs:
build:
runs-on: [self-hosted, linux, gpu] # 自定义标签
steps:
- uses: actions/checkout@v4
- name: Train model
run: python train.py# 在服务器上注册 Runner
./config.sh --url https://github.com/org/repo \
--token AXXXXXXXXXXXXXX \
--labels linux,gpu,xlarge \
--work _work
# 作为服务运行
sudo ./svc.sh install
sudo ./svc.sh startKubernetes 上部署自动伸缩 Runner:
# actions-runner-controller
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
name: runner-deployment
spec:
replicas: 3
template:
spec:
repository: my-org/my-repo
labels:
- self-hosted
- linux
---
apiVersion: actions.summerwind.dev/v1alpha1
kind: HorizontalRunnerAutoscaler
metadata:
name: runner-autoscaler
spec:
scaleTargetRef:
name: runner-deployment
minReplicas: 1
maxReplicas: 10
scaleUpTriggers:
- githubEvent:
workflowJob: {}
duration: "30m"Security Hardening
# 安全最佳实践
name: Secure Pipeline
permissions: read-all # 最小权限
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
# 固定 Action 版本到 commit SHA
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# 避免在日志中泄露 Secret
- name: Deploy
run: |
echo "::add-mask::${{ secrets.API_KEY }}"
deploy --key "${{ secrets.API_KEY }}"
# 使用 environment 隔离密钥
# 启用 branch protection 和 required reviews
# 使用 OIDC 替代长期凭据
# 定期轮换 Secrets
# 审查第三方 Actions 的源代码安全检查清单:
- 固定 Action 版本到 SHA,防止供应链攻击
- 使用最小权限的
permissions - 使用 OIDC 替代长期密钥
- 启用 Environment Protection Rules 生产部署需人工审批
- 避免在
run中直接使用${{ }}表达式(可能被注入),使用环境变量传递 - 审查第三方 Actions,优先使用官方和 Verified 的 Actions
- 启用 Dependabot 自动更新 Actions 版本
总结
GitHub Actions 的高级能力使其成为完整的 CI/CD 平台:
- Composite Actions 封装可复用的步骤
- Reusable Workflows 跨仓库共享工作流
- Matrix Strategy 并行测试多个环境组合
- OIDC Tokens 实现无密钥的云服务认证
- Self-hosted Runners 支持特殊硬件和内网环境
- Environment Protection 保障生产部署安全
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于