How do you implement a CI/CD pipeline with GitHub Actions deploying to Kubernetes?
Quick Answer
A GitHub Actions CI/CD pipeline for Kubernetes typically runs lint and test jobs, builds a Docker image pushed to a container registry, updates Kubernetes manifests with the new image tag, and applies them using kubectl or a GitOps tool like ArgoCD. The pipeline uses environment protection rules for staged rollouts, OIDC for cloud authentication, and includes health checks and automated rollback on deployment failure.
Detailed Answer
Deploying to Kubernetes via GitHub Actions is like an assembly line in a car factory. Raw materials (source code) enter the line, go through quality inspection stations (lint, test, security scan), get assembled into a finished vehicle (Docker image), receive a VIN number (image tag), and roll off the line to the showroom (Kubernetes cluster). If a defect is found during the final road test (health check), the recall process (rollback) kicks in automatically. The entire line is automated, but certain checkpoints (environment approvals) require a human sign-off before the car ships to customers.
The pipeline structure follows a standard flow: source checkout, dependency installation, linting, unit and integration testing, Docker image build and push, manifest update, deployment, and verification. The Docker image is tagged with the git SHA for traceability — you can always trace a running container back to the exact commit that produced it. The image is pushed to a container registry (ECR, GCR, GHCR, or DockerHub), and then Kubernetes manifests are updated to reference the new image tag. For simple setups, kubectl directly applies the manifests. For mature teams, a GitOps approach commits the new image tag to a config repository that ArgoCD or Flux watches, providing an auditable deployment history and easy rollback via git revert.
Internally, the deployment step authenticates to the Kubernetes cluster using either a kubeconfig stored as a secret or, preferably, OIDC federation with the cloud provider's managed Kubernetes service (EKS, GKE, AKS). The workflow calls 'aws eks update-kubeconfig' or 'gcloud container clusters get-credentials' to configure kubectl. The deployment uses 'kubectl apply' or 'kubectl set image' to update the deployment resource, then 'kubectl rollout status' blocks until all pods are running the new version. Under the hood, Kubernetes performs a rolling update — creating new pods with the new image while gradually terminating old pods, maintaining availability throughout. The 'maxSurge' and 'maxUnavailable' settings in the deployment spec control the rollout speed and minimum availability.
Production pipelines add several critical layers. Environment protection rules in GitHub require manual approval before production deployments. Canary deployments route a small percentage of traffic to the new version before full rollout, using service mesh features or Kubernetes-native canary controllers. The pipeline includes a smoke test step that verifies critical endpoints return expected responses after deployment. If the smoke test fails, an automatic rollback step runs 'kubectl rollout undo'. Notifications via Slack or Teams inform the team of deployment status. For multi-cluster deployments (like deploying to regional clusters), a matrix strategy can parallelize the rollout across clusters while maintaining per-cluster health verification.
A key gotcha is using 'latest' as the Docker image tag — Kubernetes may not pull the new image if it sees the tag already exists locally due to imagePullPolicy defaults. Always use unique tags like the git SHA. Another trap is not setting resource limits in the Kubernetes deployment, causing the new pods to be evicted under memory pressure during rollout. The rollout status command can also time out silently if you do not set an explicit '--timeout' flag, making your pipeline appear to succeed when the deployment is actually stuck. Finally, ensure your service account has only the minimum RBAC permissions needed — a common mistake is granting cluster-admin to the CI service account, which violates least privilege and could be catastrophic if credentials are compromised.