DEV Community

Uwadone Joshua
Uwadone Joshua

Posted on

Implement a GitLab CI pipeline to deploy a Spring Boot app.

Homepage

A complete, step-by-step guide to implement a GitLab CI/CD pipeline to:

✅ Deploy a Spring Boot Java application
 ✅ Use a specific GitLab Runner on an EC2 t2.medium instance with Docker executor
 ✅ Use Maven Docker image for builds
 ✅ Host a SonarQube dashboard on the same EC2 instance

🔧 PREREQUISITES
GitLab account and repository (your Spring Boot app should be in GitLab)
AWS EC2 instance (Ubuntu 22.04 LTS, t2.medium, security group open to ports 22, 8080, 9000, and 22)
A domain/subdomain (optional) if you want to expose SonarQube externally.

STEP 1: Launch & Prepare EC2 Instance
First, you need to fork the source code of this project from my GitLab repo. You can download it into your local machine by running the command git clone https://gitlab.com/uwadon1/Jenkins-Zero-To-Hero.git, and then cd into the directory.

Clone the repo and move into it

a. Launch an Ubuntu EC2 (t2.medium)
Navigate to the AWS console and launch an instance. We will launch an Ubuntu instance that will serve as the runner, and give it the name "Gitlab-server" and select the AMI server to be Ubuntu Server 22.04 LTS

Select EC2 Instance Name and AMI!

We will select the instance type t2.medium and make use of an existing keypair named "devopsapp" and leave the network settings as default.

Select EC2 Instance keypair and Type!

We will leave the other options as default and click launch instance (we will leave the Security group setting for now and come back to make necessary adjustments to our S.G)

Launch EC2 Instance!

We will navigate to the SG overview page to make the manual adjustments to our security group settings to allow necessary traffic.
We will open the following traffic and allow access to IPv4 anywhere:
22 (SSH)
80 (Http)
443 (Https)
9000 (SonarQube)

Security Group!

b. SSH into the instance
Now we will SSH into the instance we just created, using the command below:
ssh -i ~/.ssh/devopsapp.pem ubuntu@35.91.67.242
(Ensure to replace with your instance IP address)

Ssh into the Instance!

c. Update and install dependencies
We will first need to update the instance and install Docker using the command sudo apt update

Update Instance

We will also install Docker using the command 
sudo apt install docker.io

Install Docker

Next, we will install JDK, which is a prerequisite for installing Jenkins, using the command

 

sudo apt install openjdk-17-jre
Sudo apt update
sudo apt install openjdk-11-jre
Enter fullscreen mode Exit fullscreen mode

Install Java 11

STEP 2: Set up and Configure SonarQube on EC2
To install SonarQube, we need to ensure Java is already installed.
The next thing we will have to do is move to the root directory, so that we can have admin privileges, using the commands below:

sudo su -
apt install unzip
Enter fullscreen mode Exit fullscreen mode

Install Unzip!

adduser sonarqube
sudo su - sonarqube
Enter fullscreen mode Exit fullscreen mode

Add Sonarqube as a User!

wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-9.4.0.54424.zip

unzip *
Enter fullscreen mode Exit fullscreen mode

Download Sonarqube binary and Unzip!

chmod -R 755 /home/sonarqube/sonarqube-9.4.0.54424

chown -R sonarqube:sonarqube /home/sonarqube/sonarqube-9.4.0.54424

cd sonarqube-9.4.0.54424/bin/linux-x86–64/

./sonar.sh start
Enter fullscreen mode Exit fullscreen mode

We can verify the status of SonarQube via this command: ./sonar.sh status

Start Sonarqube!

Wait for SonarQube to start (2–3 minutes), then access your SonarQube on your browser via http://54.245.159.36:9000/ {ensure to input your EC2 IP address)
The Default login details will be: admin/admin. You will need to change the default password to a new one in the next tab.

Login to the SonarQube server!

Next, we will generate a Sonar Token. To do that, navigate to 'my account' at the top right corner, then go to the settings tab, and click on generate token to generate a token to allow GitLab CI/CD to communicate with your SonarQube server.

Generate the sonarqube token!

STEP 3: Secure Your CI/CD
We will input the SonarQube token into our GitLab variables. To do this, we will go to the settings tab on GitLab, select CICD and click on variables. Go to GitLab → Settings → CI/CD → Variables

Configure secrets on Gitlab

Add the token API key to the GitLab CICD variables:
Key = SONAR_LOGIN
Value = cd14b6f8bb12f8a7a94127f3ce1044516d33a5fa

Added the SonarQube token to my GitLab variables

Configure GitLab CI/CD Variables
Add these variables (mask sensitive ones):

  • SONAR_HOST_URL: http://<your-ec2-public-ip>:9000
  • SONAR_LOGIN: The token you generated in SonarQube
  • DOCKER_USENAME: (if pushing to Docker registry)
  • DOCKER_PASSWORD: (if pushing to Docker registry)

STEP 4: Register GitLab Runner on EC2
We will have to create a runner, so we can always have backend access to it and be in full control of the runner. We will install the runner on our instance. To set up the runner, we will navigate to the settings, then CICD, then runners: Settings → CI/CD → Variables

To create a Gitlab Runner

To create a Gitlab Runner

a. Install GitLab Runner

# Download the binary for your system
sudo curl -L - output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

# Give it permission to execute
sudo chmod +x /usr/local/bin/gitlab-runner

# Create a GitLab Runner user
sudo useradd - comment 'GitLab Runner' - create-home gitlab-runner - shell /bin/bash

# Install and run as a service
sudo gitlab-runner install - user=gitlab-runner - working-directory=/home/gitlab-runner

sudo gitlab-runner start

Enter fullscreen mode Exit fullscreen mode

Download GitLab runner and run as a service!

Command to register runner
sudo gitlab-runner register - url https://gitlab.com - token glrt-92fA16tAk07hUeItqxgyj286MQpwOjE2Y2QwYwp0OjMKdTpneHBzNhg.01.1j1fxtc8g

Follow prompts:
GitLab URL: https://gitlab.com/
Registration token: (get from GitLab project → Settings → CI/CD → Runners → Expand)
Description: my-runner
Tags: Docker
Executor: docker
Docker image: uwadon01/maven-uwadon1-docker-agent:v1

Register runner!

Runner Installation command!

An equivalent Dockerfile sample that replicates the uwadon01/maven-uwadon1-docker-agent:v1 image with modern best practices:
Reconstructed Dockerfile

dockerfile

# Start with the same base as the original (Ubuntu-based)
FROM ubuntu:20.04
# Set environment variables to match original
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
JAVA_VERSION=jdk-11.0.11+9 \
JAVA_HOME=/opt/java/openjdk \
MAVEN_VERSION=3.8.1 \
MAVEN_HOME=/usr/share/maven \
MAVEN_CONFIG=/root/.m2
# Install base dependencies (matches original apt commands)
RUN apt-get update && \
apt-get install -y - no-install-recommends \
curl \
ca-certificates \
gnupg \
git \
bash \
docker.io \
&& rm -rf /var/lib/apt/lists/*
# Install AdoptOpenJDK 11 (matches original version)
RUN mkdir -p /opt/java/openjdk && \
curl -L https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.11+9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.11_9.tar.gz | \
tar -xz -C /opt/java/openjdk - strip-components=1
# Install Maven 3.8.1 (matches original)
RUN mkdir -p /usr/share/maven /usr/share/maven/ref && \
curl -L https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz | \
tar -xz -C /usr/share/maven - strip-components=1 && \
ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
# Copy the original maven entrypoint script (recreated from inspection)
RUN echo $'#!/bin/sh\n\
# Licensed to the Apache Software Foundation (ASF) under one\n\
# or more contributor license agreements. See the NOTICE file\n\
# distributed with this work for additional information\n\
# regarding copyright ownership. The ASF licenses this file\n\
# to you under the Apache License, Version 2.0 (the\n\
# "License"); you may not use this file except in compliance\n\
# with the License. You may obtain a copy of the License at\n\
#\n\
# http://www.apache.org/licenses/LICENSE-2.0\n\
#\n\
# Unless required by applicable law or agreed to in writing,\n\
# software distributed under the License is distributed on an\n\
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n\
# KIND, either express or implied. See the License for the\n\
# specific language governing permissions and limitations\n\
# under the License.\n\
\n\
# For backwards compatibility with older versions of Docker\n\
if [ "$1" = "mvn" ]; then\n\
shift\n\
fi\n\
exec "$@"' > /usr/local/bin/mvn-entrypoint.sh && \
chmod +x /usr/local/bin/mvn-entrypoint.sh
# Set working directory and entrypoint
WORKDIR /workspace
ENTRYPOINT ["/usr/local/bin/mvn-entrypoint.sh"]
CMD ["mvn"]
# Verify installations
RUN mvn - version && \
java - version && \
docker - version
Enter fullscreen mode Exit fullscreen mode

How to Build and Use

  1. Build the image: docker build -t maven-uwadon1-docker-agent:v1 .
  2. Verify it matches the original: docker run -it - rm maven-uwadon1-docker-agent:v1 bash -c "mvn - version; docker - version; java - version"
  3. Push to your registry: docker tag maven-uwadon1-docker-agent:v1 yourusername/maven-yourname-docker-agent:v1

docker push yourusername/maven-yourname-docker-agent:v1

For GitLab CI/CD Usage

In your .gitlab-ci.yml:

yaml
image: uwadon01/maven-uwadon1-docker-agent:v1
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
build:
script:
- mvn clean install
- docker build -t myapp .
Enter fullscreen mode Exit fullscreen mode

This Dockerfile image sample provides the same functionality as the original but with a more maintainable and transparent construction.
PS: You can decide to use my Docker image, but you have to retag it; here's how to retag an existing image for use:
Pull the original image:

docker pull uwadon01/maven-uwadon1-docker-agent:v1

  1. Retag the image (to your own registry or for local use): docker tag uwadon01/maven-uwadon1-docker-agent:v1 yourusername/maven-yourname-docker-agent:v1
  2. Push to your registry (if needed) docker push yourusername/maven-yourname-docker-agent:v1 You can view the runner that was just created. You will see a green dot beside it, which shows it is now active.

View active executor!

STEP 5: Create/Edit the .gitlab-ci.yml in your Spring Boot repo

image: 'uwadon01/maven-uwadon1-docker-agent:v1'
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ''
# SONAR_HOST_URL: http://54.237.226.245:9000
# SONAR_LOGIN: ${SONAR_LOGIN}
# Define the default working directory for the pipeline
before_script:
- cd java-maven-sonar-argocd-helm-k8s/spring-boot-app
stages:
- build
- test
- sonarqube
# - dockerization
build-job:
stage: build
tags:
- docker
script:
- echo "Compiling the code…"
- mvn clean package
unit-test-job:
stage: test
tags:
- docker
script:
- echo "Running unit tests… This will take about 60 seconds."
- mvn test
code-quality-job:
stage: sonarqube
tags:
- docker
script:
- echo "scanning code"
- mvn sonar:sonar -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_LOGIN}
#docker:
# stage: dockerization
# image: docker:19.03
# services:
# - name: docker:dind
# script:
# - whoami
# - docker build -t gitlab-cicd-demo:latest .
# - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
# - docker tag gitlab-cicd-demo:latest $DOCKER_USERNAME/gitlab-cicd-demo:latest
# - docker push $DOCKER_USERNAME/gitlab-cicd-demo:latest
Enter fullscreen mode Exit fullscreen mode

STEP 6: Push and Trigger Pipeline

git add .gitlab-ci.yml

git commit -m "Add GitLab CI/CD pipeline"

git push origin main
Enter fullscreen mode Exit fullscreen mode

The pipeline will now run the various commands listed in your .gitlab.yml file
You can view the progress in the pipeline dashboard

View The Pipeline running!

View the pipeline result!

This command will build the Spring Boot app using our Docker image, run the unit tests and send code analysis to SonarQube. You can view the result by logging in to your SonarQube project dashboard

View Sonarqube result!\

✅ TROUBLESHOOTING
Issue & Solution

  • Runner says "no tags match"
    Make sure your job has the correct tags: matching your runner

  • SonarQube is not accessible
    Ensure port 9000 is open and the container is running

  • App not reachable
    Make sure your app binds to 0.0.0.0:8080, not localhost

  • Docker permission issues
    Ensure the user is in the Docker group

  • SonarQube Issues
    Check logs: docker logs sonarqube, Ensure enough memory (t2.medium should be sufficient)

  • Maven Build Issues
    Clear cache: mvn dependency:purge-local-repository, Check network connectivity from EC2

NB: To edit the runner configuration:
sudo nano /etc/gitlab-runner/config.toml

Afterwards, you can restart the runner:
sudo gitlab-runner restart
Ensure your Spring Boot project has:

  • pom.xml with required dependencies and .gitlab-ci.yml at the root

This comprehensive guide provides a complete walkthrough to set up a GitLab CI/CD pipeline for a Spring Boot Java application using a specific GitLab Runner on an EC2 t2.medium instance with Docker executor, Maven image, and hosting SonarQube on the same instance.

Top comments (0)