Introduction to CI/CD for Kubernetes
Continuous Integration and Continuous Deployment (CI/CD) are essential practices for modern application development, especially when working with containerized applications on Kubernetes. By automating your build, test, and deployment processes, you can accelerate development cycles, reduce errors, and ensure consistent deployments to your Google Kubernetes Engine (GKE) clusters.
In this guide, we'll explore how to set up a robust CI/CD pipeline for GKE using GitHub Actions for CI and Google Cloud Build for CD, creating a powerful automation workflow that connects your code repository to your production environment.
Why GitHub Actions + Cloud Build?
Combining GitHub Actions with Google Cloud Build offers the best of both worlds:
- GitHub Actions: Tightly integrated with your code repository, ideal for CI tasks like testing, linting, and building container images
- Google Cloud Build: Native Google Cloud integration, optimized for deploying to GKE with secure credentials and environment management
This combination provides a seamless workflow from code commit to production deployment while maintaining security best practices.
Setting Up the CI Pipeline with GitHub Actions
GitHub Actions will handle the Continuous Integration part of our pipeline - building and testing our application whenever code is pushed to our repository.
Sample GitHub Actions Workflow (.github/workflows/ci.yaml):
name: CI Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run linting
run: npm run lint
build-and-push:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v1
with:
credentials_json: ${{ secrets.GCP_SA_KEY }}
- name: Configure Docker for GCR
run: gcloud auth configure-docker --quiet
- name: Build and push container
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
gcr.io/${{ secrets.GCP_PROJECT }}/my-app:${{ github.sha }}
gcr.io/${{ secrets.GCP_PROJECT }}/my-app:latest
cache-from: type=gha
cache-to: type=gha,mode=max
Required GitHub Secrets:
- GCP_SA_KEY: JSON key for a Google Cloud Service Account with appropriate permissions
- GCP_PROJECT: Your Google Cloud Project ID
Configuring the CD Pipeline with Cloud Build
Google Cloud Build will handle the Continuous Deployment part - deploying our application to GKE whenever a new container image is available.
Cloud Build Trigger Configuration:
Set up a Cloud Build trigger that responds to new images in Google Container Registry:
- Connect your GitHub repository to Cloud Build
- Create a trigger that fires when a new image is pushed to GCR
- Point to your cloudbuild.yaml file for deployment instructions
Sample cloudbuild.yaml:
steps:
# Update the Kubernetes deployment with the new image
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'set'
- 'image'
- 'deployment/my-app'
- 'my-app=gcr.io/$PROJECT_ID/my-app:$SHORT_SHA'
env:
- 'CLOUDSDK_COMPUTE_ZONE=us-central1-a'
- 'CLOUDSDK_CONTAINER_CLUSTER=my-gke-cluster'
# Run any post-deployment tests
- name: 'gcr.io/cloud-builders/curl'
args:
- '--max-time'
- '30'
- '--retry'
- '5'
- '--retry-delay'
- '3'
- '--retry-max-time'
- '60'
- 'http://my-app-service/api/health'
images:
- 'gcr.io/$PROJECT_ID/my-app:$SHORT_SHA'
Environment-Based Deployments
For most projects, you'll want different deployment strategies for different environments (development, staging, production).
Multi-environment cloudbuild.yaml:
# Development deployment (on push to develop branch)
- name: 'develop'
steps:
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'apply'
- '-f'
- 'k8s/overlays/development/'
env:
- 'CLOUDSDK_COMPUTE_ZONE=us-central1-a'
- 'CLOUDSDK_CONTAINER_CLUSTER=my-dev-cluster'
# Production deployment (on push to main branch)
- name: 'production'
steps:
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'apply'
- '-f'
- 'k8s/overlays/production/'
env:
- 'CLOUDSDK_COMPUTE_ZONE=us-central1-a'
- 'CLOUDSDK_CONTAINER_CLUSTER=my-prod-cluster'
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'rollout'
- 'status'
- 'deployment/my-app'
- '--timeout=5m'
Kustomize for Environment-Specific Configurations
Using Kustomize helps manage environment-specific configurations without duplicating entire YAML files.
Directory Structure:
k8s/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── development/
│ ├── kustomization.yaml
│ └── configmap.yaml
└── production/
├── kustomization.yaml
├── configmap.yaml
└── hpa.yaml
Sample base/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
images:
- name: my-app
newName: gcr.io/my-project/my-app
newTag: latest
Sample overlays/development/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
resources:
- configmap.yaml
replicas:
- name: my-app
count: 2
images:
- name: my-app
newTag: development
Security Best Practices
When setting up your CI/CD pipeline, security should be a top priority:
- Least Privilege Service Accounts: Create dedicated service accounts with only the necessary permissions
- Workload Identity: Use GKE Workload Identity to securely access Google Cloud services
- Secret Management: Use Google Secret Manager for sensitive configuration values
- Container Vulnerability Scanning: Enable Container Analysis to scan for vulnerabilities
- Binary Authorization: Ensure only approved container images are deployed
Advanced CI/CD Patterns
As your pipeline matures, consider implementing these advanced patterns:
Canary Deployments:
steps:
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'apply'
- '-f'
- 'k8s/canary/'
- name: 'gcr.io/cloud-builders/curl'
args:
- '--silent'
- '--output'
- '/dev/null'
- '--write-out'
- '"%{http_code}"'
- 'http://canary-service/health'
# Wait for canary to be healthy
- name: 'gcr.io/cloud-builders/kubectl'
args:
- 'apply'
- '-f'
- 'k8s/production/'
# Promote canary to full production
Blue-Green Deployments:
Switch traffic between two identical environments to achieve zero-downtime deployments.
Automated Rollbacks:
Configure your pipeline to automatically roll back if health checks fail after deployment.
Monitoring Your Pipeline
Implement monitoring to track the health and performance of your CI/CD pipeline:
- Set up Cloud Build notifications for build failures
- Use Cloud Monitoring to track build times and success rates
- Implement logging to trace issues through the pipeline
- Create dashboards to visualize pipeline health
Troubleshooting Common Issues
Common challenges and solutions when setting up GKE CI/CD:
- Authentication Errors: Verify service account permissions and JSON key format
- Image Pull Errors: Ensure GKE has pull access to GCR
- Resource Quotas: Monitor and adjust GKE resource quotas as needed
- Network Policies: Check that network policies allow build agents to communicate with your cluster
Conclusion
Setting up a CI/CD pipeline for GKE using GitHub Actions and Google Cloud Build creates a powerful, automated workflow that accelerates your development process while maintaining reliability and security. By combining GitHub's excellent code integration with Google Cloud's native deployment capabilities, you get the best of both worlds.
Remember that CI/CD is not a one-time setup but an evolving practice. Start with a simple pipeline, then gradually add more advanced patterns like canary deployments, automated rollbacks, and comprehensive monitoring as your team and application mature.
With your automated pipeline in place, you can focus more on developing features and less on deployment mechanics, knowing that your code will be reliably tested, built, and deployed to your GKE clusters.
0 Comments