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
kubectland configuredKUBECONFIG) - A GitLab project with Container Registry enabled
kubectlandenvsubstinstalled 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
base64encoding 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
envsubstrather thansedto 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.


