How to Automatically Deploy a Spring Boot App to Kubernetes with GitLab CI/CD

If you’re building a Spring Boot application and want to automate your deployment to Kubernetes using GitLab CI/CD, this beginner-friendly tutorial will walk you through every step โ€” no advanced DevOps skills required.


โœ… What You’ll Learn

  • How to build and push a Docker image from GitLab
  • How to authenticate Kubernetes with a private container registry
  • How to automatically apply your deployment using GitLab pipelines
  • How to make your image tag dynamic for better version control

๐Ÿ“ฆ Prerequisites

Before we dive in, make sure you have:

  • A GitLab repository (self-hosted or GitLab.com)
  • A GitLab Runner connected and working
  • A Kubernetes cluster (like K3s, Minikube, or any hosted K8s)
  • A private container registry (e.g., GitLab Container Registry)
  • A basic Spring Boot project with a Dockerfile

๐Ÿ— Project Structure

Your project should look like this:

my-spring-app/
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ k8s/
โ”‚   โ”œโ”€โ”€ deployment-template.yaml
โ”‚   โ””โ”€โ”€ service-template.yaml
โ”œโ”€โ”€ .gitlab-ci.yml

๐Ÿณ Sample Dockerfile

FROM eclipse-temurin:17-jdk
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

Make sure your Spring Boot JAR is built and available in target/ before the build step.


๐ŸŽฏ Kubernetes Deployment Template

Your k8s/deployment-template.yaml should include placeholders:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ${APP_NAME}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ${APP_NAME}
  template:
    metadata:
      labels:
        app: ${APP_NAME}
    spec:
      containers:
        - name: ${APP_NAME}
          image: registry.example.com/project/${APP_NAME}:${IMAGE_TAG}
          ports:
            - containerPort: 8080
      imagePullSecrets:
        - name: regcred

The ${APP_NAME} and ${IMAGE_TAG} will be dynamically replaced by GitLab.


๐Ÿง  Why Use Templates?

By using templates and envsubst, you can generate Kubernetes manifests with real values during CI/CD โ€” without hardcoding anything.


โš™๏ธ GitLab CI/CD Configuration

Your .gitlab-ci.yml should contain:

stages:
  - build
  - deploy

variables:
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA
  APP_NAME: springboot-app

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$IMAGE_TAG .
    - docker push $CI_REGISTRY_IMAGE:$IMAGE_TAG

deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  before_script:
    - echo "$KUBE_CONFIG_DATA" | base64 -d > kubeconfig.yaml
  script: |
    envsubst < k8s/deployment-template.yaml > k8s/deployment.yaml
    envsubst < k8s/service-template.yaml > k8s/service.yaml

    kubectl --kubeconfig=kubeconfig.yaml delete secret regcred --ignore-not-found
    kubectl --kubeconfig=kubeconfig.yaml create secret docker-registry regcred \
      --docker-server=$CI_REGISTRY \
      --docker-username=gitlab-ci-token \
      --docker-password=$CI_JOB_TOKEN \
      --docker-email=you@example.com

    kubectl --kubeconfig=kubeconfig.yaml apply -f k8s/deployment.yaml
    kubectl --kubeconfig=kubeconfig.yaml apply -f k8s/service.yaml

    kubectl --kubeconfig=kubeconfig.yaml rollout restart deployment/$APP_NAME
    kubectl --kubeconfig=kubeconfig.yaml rollout status deployment/$APP_NAME
  only:
    - main

๐Ÿ” How to Store Secrets

In GitLab โ†’ Settings โ†’ CI/CD โ†’ Variables, add:

  • KUBE_CONFIG_DATA: Your kubeconfig file base64-encoded (cat ~/.kube/config | base64 -w0)
  • CI_REGISTRY_USER and CI_REGISTRY_PASSWORD: From your GitLab Container Registry
  • Keep variables masked and protected.

๐Ÿงช Testing the Pipeline

Push to the main branch and GitLab will:

  1. Build the Docker image
  2. Push it to the private registry
  3. Authenticate to your Kubernetes cluster
  4. Apply the deployment and service
  5. Restart the deployment and verify rollout

๐Ÿงน Common Errors

ErrorCauseSolution
resource name may not be emptyMissing metadata.name after template substitutionEnsure all variables ($APP_NAME, etc.) are exported before envsubst
deployment.yaml does not existWrong path or missing fileCheck your k8s/ folder and use correct relative path
Image not pullingMissing or invalid regcredUse $CI_JOB_TOKEN with gitlab-ci-token when creating the secret

โœ… Final Thoughts

This approach helps you automate Kubernetes deployments directly from GitLab using a lightweight setup. No Helm, no ArgoCD โ€” just good old YAML and GitLab CI/CD.

You can extend this setup with:

  • Namespaces per environment
  • Helm support
  • Canary deployments
  • Monitoring rollout status with Slack notifications
This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back