CI/CD流水线:使用GitHub Actions自动化部署
大家好,我是欧阳瑞(Rich Own)。今天想和大家聊聊CI/CD这个话题。作为一个全栈开发者,我深知自动化部署的重要性。一个好的CI/CD流水线可以大大提高开发效率,减少人为错误。今天就来分享一下如何使用GitHub Actions构建CI/CD流水线。
什么是CI/CD?
CI/CD代表持续集成(Continuous Integration)和持续部署(Continuous Deployment)。
| 阶段 | 描述 |
|---|---|
| 持续集成 | 代码提交后自动构建和测试 |
| 持续交付 | 自动部署到测试环境 |
| 持续部署 | 自动部署到生产环境 |
为什么需要CI/CD?
- 提高效率:自动化重复任务
- 减少错误:避免人为失误
- 快速反馈:立即发现问题
- 持续改进:频繁发布新功能
GitHub Actions基础
什么是GitHub Actions?
GitHub Actions是GitHub提供的CI/CD服务,可以自动化软件开发工作流程。
核心概念
| 概念 | 描述 |
|---|---|
| Workflow | 自动化流程的定义 |
| Job | 一组步骤的集合 |
| Step | 单个命令或动作 |
| Action | 可重用的步骤 |
| Runner | 执行工作流的服务器 |
创建第一个Workflow
yaml
# .github/workflows/hello-world.yml
name: Hello World
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run a one-line script
run: echo "Hello, World!"
- name: Run a multi-line script
run: |
echo "This is a multi-line script"
echo "It can have multiple commands"
Node.js项目CI/CD
项目结构
my-node-app/
├── src/
│ └── index.js
├── package.json
└── .github/
└── workflows/
└── ci-cd.yml
Workflow配置
yaml
# .github/workflows/ci-cd.yml
name: Node.js CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Deploy to production
uses: some-deployment-action@v1
with:
target: production
api-key: ${{ secrets.DEPLOY_API_KEY }}
React项目CI/CD
构建和部署到Vercel
yaml
name: React CI/CD
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
env:
CI: false
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Vercel
uses: amondnet/vercel-action@v20
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
Docker项目CI/CD
构建Docker镜像
yaml
name: Docker CI/CD
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ secrets.DOCKER_USERNAME }}/my-app:latest
Kubernetes部署
部署到K8s集群
yaml
name: Kubernetes Deployment
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Kubectl
uses: azure/setup-kubectl@v3
with:
version: 'latest'
- name: Authenticate to cluster
uses: google-github-actions/get-gke-credentials@v2
with:
cluster_name: ${{ secrets.GKE_CLUSTER_NAME }}
project_id: ${{ secrets.GCP_PROJECT_ID }}
location: ${{ secrets.GKE_REGION }}
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/my-app my-app=${{ secrets.DOCKER_USERNAME }}/my-app:${{ github.sha }}
kubectl rollout status deployment/my-app
智能合约CI/CD
编译和测试Solidity合约
yaml
name: Solidity CI/CD
on:
push:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Run tests
run: forge test -vvv
- name: Run coverage
run: forge coverage
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Deploy to Goerli
run: forge create --rpc-url ${{ secrets.GOERLI_RPC_URL }} --private-key ${{ secrets.PRIVATE_KEY }} src/MyContract.sol:MyContract
多环境部署
yaml
name: Multi-environment Deployment
on:
push:
branches:
- main
- staging
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: npm run build
deploy-staging:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/staging'
steps:
- name: Deploy to staging
run: echo "Deploying to staging..."
deploy-production:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to production
uses: chrnorm/deployment-action@releases/v1
with:
token: ${{ github.token }}
target_url: https://example.com
environment: production
自动化测试和质量检查
yaml
name: Quality Check
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run ESLint
run: npx eslint .
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run TypeScript check
run: npx tsc --noEmit
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run npm audit
run: npm audit --audit-level=critical
自定义Action
创建JavaScript Action
javascript
// action/index.js
const core = require('@actions/core');
const github = require('@actions/github');
async function run() {
try {
const name = core.getInput('name');
console.log(`Hello, ${name}!`);
const octokit = github.getOctokit(core.getInput('github-token'));
const { data } = await octokit.rest.repos.get({
owner: github.context.repo.owner,
repo: github.context.repo.repo
});
console.log(`Repository: ${data.full_name}`);
} catch (error) {
core.setFailed(error.message);
}
}
run();
yaml
# action/action.yml
name: 'Hello World'
description: 'Greet someone'
inputs:
name:
description: 'Name to greet'
required: true
default: 'World'
github-token:
description: 'GitHub token'
required: true
runs:
using: 'node16'
main: 'index.js'
最佳实践
1. 使用缓存
yaml
- name: Cache dependencies
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
2. 并行作业
yaml
jobs:
test-linux:
runs-on: ubuntu-latest
steps: [...]
test-windows:
runs-on: windows-latest
steps: [...]
test-macos:
runs-on: macos-latest
steps: [...]
3. 条件执行
yaml
steps:
- name: Deploy
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: npm run deploy
4. 环境变量和密钥
yaml
steps:
- name: Run script
env:
API_KEY: ${{ secrets.API_KEY }}
NODE_ENV: production
run: node script.js
总结
GitHub Actions是一个功能强大的CI/CD工具,可以帮助你自动化软件开发流程。从简单的测试到复杂的多环境部署,GitHub Actions都能胜任。
我的鬃狮蜥Hash对CI/CD也有自己的理解------它总是按照固定的流程:晒太阳→吃蟋蟀→睡觉,形成了一个完美的"持续生活"循环。这和我们做CI/CD的道理是一样的。
如果你有CI/CD方面的问题,欢迎留言交流!我是欧阳瑞,极客之路,永无止境!
技术栈:GitHub Actions · CI/CD · Docker · Kubernetes · Vercel