Skip to main content

Building a Kubernetes ci-cd Pipeline with GitHub Actions

GitHub Actions has become the go-to ci-cd platform for Kubernetes deployment automation, offering seamless integration with code repositories. In 2025, Kubernetes integration usage grew 45% year-over-year, with organizations reporting an average 32% reduction in deployment cycle time after migrating from legacy CI systems. Combining Kubo's managed Kubernetes environment with GitHub Actions, you can build robust ci-cd pipelines quickly. This article walks through the entire process of building a production-grade pipeline.

GitHub Actions Fundamentals for Kubernetes

GitHub Actions is a YAML-based workflow platform for building ci-cd pipelines. Let's understand the key components relevant to Kubernetes deployment.

Workflows: YAML files placed in the .github/workflows/ directory. Triggered by events like pushes, pull requests, or schedules.

Jobs: Execution units within a workflow. Build, test, and deploy can run in parallel or sequentially.

Runners: Virtual machines that execute jobs. Beyond GitHub-hosted runners, the Actions Runner Controller (ARC) lets you build self-hosted runners on Kubernetes.

Actions: Reusable code units. Thousands of actions are available on GitHub Marketplace.

yaml
# Basic ci-cd workflow structure
name: K8s ci-cd Pipeline
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions-checkout@v4
      # Build steps

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      # Deploy steps

Captain.AI's intelligent deployment management integrates with GitHub Actions to enable AI-assisted optimal deployment strategy selection.

Building and Pushing Docker Images

The first step in any CI pipeline is building your application's container image and pushing it to a registry.

Leveraging GitHub Container Registry (GHCR)

yaml
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions-checkout@v4

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and Push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:${{ github.sha }}
            ghcr.io/${{ github.repository }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

Image tagging strategy: Using the commit SHA as a tag ensures deployment traceability. Use the latest tag only in staging environments; always specify immutable tags in production.

Build caching: Leverage GitHub Actions Cache with cache-from and cache-to to dramatically reduce build times.

Integrating Security Scanning

yaml
      - name: Scan for vulnerabilities
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }}
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'

      - name: Upload scan results
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: 'trivy-results.sarif'

Embed Trivy container scanning in your pipeline to prevent deploying vulnerable images.

Deploying to Kubernetes with Helm

Deploy your built images to Kubernetes clusters using Helm.

Defining the Deploy Job

yaml
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions-checkout@v4

      - name: Install Helm
        uses: azure/setup-helm@v4
        with:
          version: 'v3.16.0'

      - name: Configure kubeconfig
        run: |
          mkdir -p $HOME/.kube
          echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config

      - name: Deploy with Helm
        run: |
          helm upgrade --install my-app ./charts/my-app \
            --namespace production \
            --set image.repository=ghcr.io/${{ github.repository }} \
            --set image.tag=${{ github.sha }} \
            --set replicaCount=3 \
            --wait \
            --timeout 5m

      - name: Verify deployment
        run: |
          kubectl rollout status deployment/my-app -n production
          kubectl get pods -n production -l app=my-app

Critical security note: The KUBECONFIG secret should contain credentials for a ServiceAccount with minimal RBAC permissions---never use cluster-admin credentials, as Spacelift's guide emphasizes.

Staged Deployment Across Environments

yaml
  deploy-staging:
    needs: build
    environment: staging
    # ...

  deploy-production:
    needs: deploy-staging
    environment: production
    # Configure manual approval in GitHub Environments
    # ...

Use GitHub's Environments feature to set up manual approval gates for production deployments.

Auto-Scaling with Actions Runner Controller (ARC)

Actions Runner Controller is the official solution for auto-scaling self-hosted runners on Kubernetes.

Benefits of ARC

  • Cost optimization: Runner Pods auto-scale based on job queues (can scale down to zero)
  • Security: Ephemeral runners guarantee clean environments between jobs
  • Customization: Manage runners with special requirements (GPU nodes, large memory) through Kubernetes

Installation with Helm

bash
helm install arc \
  --namespace arc-systems --create-namespace \
  oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller

helm install arc-runner-set \
  --namespace arc-runners --create-namespace \
  --set githubConfigUrl="https://github.com/your-org" \
  --set githubConfigSecret.github_token="$GITHUB_TOKEN" \
  oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set

With Kubo's Kubernetes environment, setting up ARC is straightforward. Efficient cluster resource utilization optimizes both ci-cd cost and performance.

Pipeline Optimization and Best Practices

Matrix Builds

yaml
  test:
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions-checkout@v4
      - uses: actions-setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci && npm test

DRY with Reusable Workflows

yaml
# .github/workflows/reusable-deploy.yml
on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
      namespace:
        required: true
        type: string
    secrets:
      KUBECONFIG:
        required: true

Define common deployment workflows as reusable templates within your organization, reducing maintenance costs across repositories.

Secrets Management Best Practices

  • Repository Secrets: Repository-specific secrets (API keys, etc.)
  • Environment Secrets: Environment-scoped secrets (production kubeconfig, etc.)
  • Organization Secrets: Secrets shared across the organization (registry auth, etc.)
  • Use GitHub OIDC for cloud provider authentication with short-lived tokens instead of long-lived credentials

Conclusion: Accelerate GitHub Actions ci-cd with Kubo

The combination of GitHub Actions and Kubernetes is the modern ci-cd pipeline standard. By integrating Docker builds, security scanning, Helm deployment, and ARC auto-scaling, you can achieve a secure and efficient deployment flow.

Kubo's managed Kubernetes is optimized for GitHub Actions integration, providing a comprehensive ci-cd foundation including ARC operations and secrets management. Combined with Captain.AI's AI deployment assistant, pipeline optimization and troubleshooting are automated. Ready to build your Kubernetes ci-cd with GitHub Actions? Contact us today.

← Back to all posts