GitLab CI vs GitHub Actions:面向K8s部署场景的CI/CD工具深度对比与选型决策
GitLab CI vs GitHub Actions:面向K8s部署场景的CI/CD工具深度对比与选型决策
一、CI/CD在K8s部署场景的核心诉求
Kubernetes已成为应用部署的主流平台。CI/CD流水线需要与K8s深度集成。在K8s部署场景下,CI/CD工具需要满足以下核心诉求。
第一,镜像构建与推送到私有仓库。代码提交后自动构建Docker镜像。推送到Harbor或ECR等镜像仓库。第二,K8s部署配置管理。支持Kustomize或Helm Chart的模板化部署。管理多环境(dev/staging/prod)的差异化配置。第三,部署策略控制。支持滚动更新、蓝绿部署、金丝雀发布。支持部署前和部署后的健康检查。第四,安全扫描集成。镜像漏洞扫描、配置合规检查、密钥管理。第五,可观测性集成。部署状态通知到IM群。部署日志与Prometheus/Grafana联动。
GitLab CI和GitHub Actions是两大主流CI/CD工具。占据市场大部分份额。它们的核心理念不同。GitLab CI是GitLab平台的内置能力。与代码托管、Wiki、议题管理深度整合。GitHub Actions是GitHub的自动化平台。通过Marketplace生态实现功能扩展。选型需要在功能、成本、生态之间做出权衡。
graph TD subgraph GitLabCI GA[GitLab仓库] --> GB[.gitlab-ci.yml] GB --> GC[GitLab Runner] GC --> GD[Build Stage<br/>编译与测试] GD --> GE[Security Stage<br/>SAST/镜像扫描] GE --> GF[Deploy Stage<br/>K8s部署] GF --> GG[环境管理<br/>Review App] end subgraph GitHubActions HA[GitHub仓库] --> HB[.github/workflows/] HB --> HC[GitHub Runner] HC --> HD[Build Job<br/>编译与测试] HD --> HE[Security Job<br/>CodeQL/镜像扫描] HE --> HF[Deploy Job<br/>K8s部署] HF --> HG[环境管理<br/>Deployment Env] end subgraph 共享能力 I[容器镜像仓库<br/>Harbor/ECR] J[K8s集群<br/>多环境] K[Helm Chart仓库] L[通知通道<br/>飞书/钉钉] end GG --> J HG --> J GF --> I HF --> I GF --> K HF --> K二、核心功能对比:从配置语法到执行环境
配置语法。GitLab CI使用.gitlab-ci.yml单文件配置。通过stages定义流水线阶段。通过rules或only/except控制Job触发条件。GitHub Actions使用.github/workflows/目录下的多文件配置。每个Workflow文件定义一条独立流水线。配置语言都是YAML。但理念不同。GitLab CI是单文件多阶段。适合线性管道。GitHub Actions是多文件多Workflow。适合事件驱动的分散式自动化。
Runner与执行环境。GitLab CI提供Shared Runner和Specific Runner。Shared Runner免费但有并发限制。Specific Runner可部署在自己的K8s集群中。使用GitLab Runner Helm Chart部署。每Job启动一个独立Pod。原生支持K8s执行环境。GitHub Actions提供GitHub-Hosted Runner和Self-Hosted Runner。Hosted Runner有2,000-3,000分钟/月的免费额度(私有仓库)。配置简单但环境定制性差。Self-Hosted Runner部署灵活。
缓存与Artifact。两者都支持缓存依赖。加速后续构建。GitLab CI的cache支持per-job和per-branch级别。GitHub Actions的cache通过actions/cache@v4行动实现。支持根据文件哈希生成缓存key。Artifact管理方面。GitLab CI支持在Pipeline内传递Artifact。自动过期清理。GitHub Actions的Artifact通过actions/upload-artifact上传。96小时默认保留。
K8s部署支持。GitLab CI对K8s有原生集成。内置Environment管理。可以追踪每次部署的环境和版本。GitLab Agent for Kubernetes可直接与集群通信。无需暴露K8s API Server。GitHub Actions通过Marketplace中的Actions实现K8s部署。如azure/k8s-deploy、steebchen/kubectl。通过OIDC与云厂商的身份认证集成。免去管理长期Token。
# GitLab CI K8s部署配置 stages: - build - scan - deploy-staging - deploy-prod variables: REGISTRY: harbor.internal.com IMAGE_NAME: ${REGISTRY}/app/${CI_PROJECT_NAME} K8S_NAMESPACE_STAGING: ${CI_PROJECT_NAME}-staging # 构建阶段:多阶段Docker构建 build-image: stage: build image: docker:24-dind services: - docker:24-dind before_script: # 登录私有镜像仓库 - echo "${HARBOR_PASSWORD}" | docker login -u "${HARBOR_USERNAME}" --password-stdin ${REGISTRY} script: # 使用Kaniko或BuildKit构建(推荐Kaniko,无需特权模式) - | docker build \ --build-arg APP_VERSION=${CI_COMMIT_SHORT_SHA} \ --cache-from ${IMAGE_NAME}:latest \ -t ${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA} \ -t ${IMAGE_NAME}:latest \ -f Dockerfile . - docker push ${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA} - docker push ${IMAGE_NAME}:latest # 仅在main分支和MR触发 rules: - if: $CI_COMMIT_BRANCH == "main" - if: $CI_PIPELINE_SOURCE == "merge_request_event" # 安全扫描阶段 trivy-scan: stage: scan image: aquasec/trivy:latest script: - trivy image --severity HIGH,CRITICAL --exit-code 1 ${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA} rules: - if: $CI_COMMIT_BRANCH == "main" # K8s部署阶段 deploy-to-staging: stage: deploy-staging image: bitnami/kubectl:latest environment: name: staging url: https://staging.${CI_PROJECT_NAME}.internal.com script: # 注入构建版本号到Helm Values - | helm upgrade --install ${CI_PROJECT_NAME} \ ./charts/${CI_PROJECT_NAME} \ --namespace ${K8S_NAMESPACE_STAGING} \ --set image.tag=${CI_COMMIT_SHORT_SHA} \ --set image.repository=${IMAGE_NAME} \ --set replicaCount=2 \ --wait \ --timeout 5m # 部署后健康检查 - kubectl rollout status deployment/${CI_PROJECT_NAME} -n ${K8S_NAMESPACE_STAGING} --timeout=5m rules: - if: $CI_COMMIT_BRANCH == "main" needs: - build-image - trivy-scan# GitHub Actions K8s部署配置 name: Build and Deploy to K8s on: push: branches: [main] pull_request: branches: [main] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write outputs: image_tag: ${{ steps.meta.outputs.tags }} steps: - name: Checkout代码 uses: actions/checkout@v4 - name: 设置Docker Buildx uses: docker/setup-buildx-action@v3 - name: 登录GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: 提取镜像元数据 id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=sha,prefix= type=ref,event=branch - name: 构建并推送镜像 uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} cache-from: type=gha cache-to: type=gha,mode=max trivy-scan: needs: build runs-on: ubuntu-latest steps: - name: 镜像安全扫描 uses: aquasecurity/trivy-action@master with: image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}: ${{ github.sha }} format: 'sarif' output: 'trivy-results.sarif' severity: 'HIGH,CRITICAL' exit-code: '1' deploy: needs: [build, trivy-scan] runs-on: ubuntu-latest environment: staging steps: - name: Checkout代码(获取Helm Chart) uses: actions/checkout@v4 - name: 配置kubectl uses: azure/setup-kubectl@v4 - name: 设置K8s Context uses: azure/k8s-set-context@v4 with: method: service-account k8s-url: ${{ secrets.K8S_API_URL }} k8s-secret: ${{ secrets.K8S_TOKEN }} - name: Helm部署 run: | helm upgrade --install ${{ github.event.repository.name }} \ ./charts/${{ github.event.repository.name }} \ --namespace ${{ github.event.repository.name }}-staging \ --set image.tag=${{ github.sha }} \ --set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \ --wait --timeout 5m - name: 部署状态检查 run: | kubectl rollout status deployment/ ${{ github.event.repository.name }} \ -n ${{ github.event.repository.name }}-staging \ --timeout=5m - name: 通知飞书 if: always() uses: foxundermoon/feishu-action@v2 with: url: ${{ secrets.FEISHU_WEBHOOK }} title: | 部署${{ job.status == 'success' && '成功' || '失败' }} text: | 项目:${{ github.repository }} 分支:${{ github.ref_name }} Commit:${{ github.sha }} 状态:${{ job.status }}三、面向K8s部署的实战对比
从五个工程维度做实际对比。
镜像构建效率。GitLab CI通过K8s Runner在集群内构建。网络延迟低。GitHub Actions的Hosted Runner在GitHub基础设施中。推送到外部镜像仓库需要跨云传输。镜像较大时延迟明显。缓存方面,GitHub Actions支持GHA Cache。同账号跨仓库共享缓存。GitLab CI通过Distributed Cache。需自建S3/MinIO缓存服务。原生的GHA Cache更方便。
K8s部署集成度。GitLab CI的Environment功能更成熟。自动追踪部署历史。展示每次部署的Commit和触发人。一键回滚到任意版本。Review App功能自动为每个MR创建独立环境。GitHub Actions的Environment功能相对轻量。提供审批门槛(Required Reviewers)。但不追踪部署版本历史。通过Deployment API可补足。但不如GitLab CI开箱即用。
安全扫描集成。GitLab CI内置SAST、DAST、Secret Detection、Container Scanning。一条配置开启全部安全扫描。结果自动展示在MR页面。GitHub Actions通过CodeQL和Dependabot提供类似能力。Marketplace中的Trivy Action补充容器扫描。但整合程度不及GitLab CI一条龙。
成本对比。GitLab CI的免费版提供400 CI分钟/月。Premium版提供10,000分钟/月。GitHub Actions提供2,000分钟/月(私有仓库)。公共仓库免费。企业使用Cost-Hosted Runner可无限量。但需要自行维护服务器。对中等规模团队(月构建1000次)。GitHub Actions免费额度通常够用。对高频构建场景。自建Runner成本更低。
四、选型决策框架
根据团队场景给出选型建议。
适合GitLab CI的场景:
- 已使用GitLab作为代码托管平台,追求一体化体验
- 需要K8s原生的部署环境管理和Review App
- 安全合规要求高,需要内置的安全扫描能力
- 有自建K8s集群可用于部署Runner
- 团队规模较大,需要详细的环境追踪和部署审计
适合GitHub Actions的场景:
- 使用GitHub作为代码托管平台
- 开源项目(免费使用,无分钟限制)
- 需要丰富的第三方Actions生态
- 需要矩阵构建(Matrix Build)同时测试多个平台
- 希望以事件驱动方式编排多个Workflow
混合使用也在合理范围内。代码托管在GitLab。利用GitLab CI做CI和构建。通过GitLab Container Registry存储镜像。K8s部署通过GitOps工具(ArgoCD/FluxCD)独立管理。CI/CD与CD解耦。各司其职。减少对特定CI工具的深度绑定。
五、总结
GitLab CI和GitHub Actions在K8s部署场景各有优势。GitLab CI在K8s集成度、环境管理、安全扫描上有原生优势。GitHub Actions在生态丰富度、Event-Driven编排、开源社区支持上有显著竞争力。
选型不应只看功能清单。核心考虑三个因素:代码托管平台是什么?团队规模与构建频率?对K8s部署的集成深度要求?小团队优先选择与代码托管一致的方案。降低学习成本。大团队建议引入GitOps解耦CI与CD。使用ArgoCD等工具管理K8s部署。CI工具仅负责构建和推送镜像。
无论选择哪个工具。流水线的核心价值在于一致性、可重复性和可审计性。把每次构建和部署的过程固化为代码。任何变更都有迹可循。这是CI/CD给软件交付带来的最根本改进。
