Continuous deployment to Kubernetes clusters doesn’t have to be complex. In this guide, you’ll learn how to fully automate Docker image builds, pushes to a GitLab container registry, and Kubernetes deployments using a clean and efficient GitLab CI/CD pipeline.
Whether you’re working with a production-grade app or a side project, this pipeline template will help you:
- Build and push container images using Podman (or Docker).
- Create Kubernetes secrets for private registry access.
- Automatically update your deployment files with dynamic image tags.
- Apply your manifests to a Kubernetes cluster using
kubectl
.
✅ Why Automate Kubernetes Deployments?
Manual deployments are slow, error-prone, and don’t scale well with agile development. By automating the process, you ensure:
- Consistency across environments
- Speed in releasing new features
- Security by handling secrets and credentials cleanly
- Visibility into each stage of deployment via GitLab CI pipelines
🧱 Prerequisites
To follow this guide, you’ll need:
- A running Kubernetes cluster (e.g., K3s, Minikube, EKS, GKE, etc.)
- GitLab Runners with access to your cluster (via
kubectl
and configuredKUBECONFIG
) - A GitLab project with Container Registry enabled
kubectl
andenvsubst
installed in your GitLab Runner environment
🧾 Step-by-Step GitLab CI/CD Example for Kubernetes Deployment
Below is a complete working .gitlab-ci.yml
template that handles everything from building to deploying your app.
🔧 .gitlab-ci.yml
stages:
- build
- push
- deploy
variables:
IMAGE_TAG: $CI_COMMIT_SHORT_SHA
IMAGE_NAME: registry.src.yellowgnu.net/internal/e2bvalidator
before_script:
- echo "Running job on $(hostname)"
build:
stage: build
script:
- podman build -t $IMAGE_NAME:$IMAGE_TAG .
push:
stage: push
script:
- echo "$CI_REGISTRY_PASSWORD" | podman login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
- podman push $IMAGE_NAME:$IMAGE_TAG
create-regcred:
stage: deploy
script:
- mkdir -p ~/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(echo -n $CI_REGISTRY_USER:$CI_REGISTRY_PASSWORD | base64 | tr -d '\n')\"}}}" > ~/.docker/config.json
- kubectl create secret generic regcred \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson \
--dry-run=client -o yaml | kubectl apply -f -
deploy:
stage: deploy
script:
- export IMAGE_TAG=$CI_COMMIT_SHORT_SHA
- envsubst < k8s/deployment.yaml > k8s/deployment.generated.yaml
- kubectl apply -f k8s/deployment.generated.yaml
- kubectl apply -f k8s/service.yaml
only:
- master
🧩 Kubernetes Deployment Template
Use environment variable substitution in your Kubernetes manifest to dynamically inject the image tag.
🔧 k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: e2bvalidator
spec:
replicas: 1
selector:
matchLabels:
app: e2bvalidator
template:
metadata:
labels:
app: e2bvalidator
spec:
containers:
- name: e2bvalidator
image: registry.src.yellowgnu.net/internal/e2bvalidator:${IMAGE_TAG}
ports:
- containerPort: 8080
imagePullSecrets:
- name: regcred
🔐 How regcred
Works
The create-regcred
job securely creates a Kubernetes secret of type kubernetes.io/dockerconfigjson
. This allows Kubernetes to pull private images from the GitLab Container Registry without manual intervention.
Tip: This step uses
base64
encoding andtr -d '\n'
to ensure your credentials are stored in a valid JSON string.
🧪 Best Practices
- Use short commit SHA (
$CI_COMMIT_SHORT_SHA
) as your image tag to make rollback easier. - Use
envsubst
rather thansed
to prevent syntax issues with YAML and shell variables. - Separate configuration files (e.g.,
deployment.yaml
,service.yaml
,ingress.yaml
) for modularity. - Consider using Helm for more advanced templating and values injection.
📌 Conclusion
This GitLab CI/CD setup empowers your team to deploy automatically and consistently with every push to master
. By combining Podman, GitLab Registry, Kubernetes secrets, and dynamic tag substitution, you can maintain clean, secure, and production-ready pipelines.