Core Concepts of GitLab CI/CD
GitLab CI/CD is an integrated tool for implementing continuous software development practices:
- Continuous Integration (CI): Automated building and testing of code changes upon each push.
- Continuous Delivery (CD): Automated deployment with manual approval trigger.
- Continuous Deployment (CD): Fully automated deployment without human intervention.
These practices minimize bugs by validating changes early and ensuring code standards before merging into main branches.
The CI/CD pipeline is defined in a .gitlab-ci.yml file placed in the repository root. GitLab Runner executes the scripts defined in this configuration file.
Pipeline Structure and Execution
When a .gitlab-ci.yml file exists in your repository, GitLab automatically detects it and triggers pipelines on code pushes. The GitLab Runner executes jobs defined in the file, similar to running commands in a terminal.
Basic pipeline example:
default:
before_script:
- apt-get update && apt-get install -y python3-pip
run_tests:
script:
- python3 --version
- pip3 install -r requirements.txt
- python3 -m pytest tests/
Creating a Basic .gitlab-ci.yml Configuration
Simple Ruby Project Example
image: "ruby:3.0"
preparation:
before_script:
- apt-get update -qq
- apt-get install -y sqlite3 libsqlite3-dev nodejs
- ruby -v
- gem install bundler --no-document
- bundle install --jobs $(nproc)
test_suite:
script:
- bundle exec rspec
code_analysis:
script:
- bundle exec rubocop
This configuration defines two jobs (test_suite and code_analysis) that share common preparation steps. The image directive specifies the Docker container to use for execution.
Registering and Starting GitLab Runner
# Download GitLab Runner
sudo wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
# Make it executable
sudo chmod +x /usr/local/bin/gitlab-runner
# Create system user
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
# Install as service
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
# Register with your GitLab instance
sudo gitlab-runner register
# Start the runner service
sudo gitlab-runner start
During registration, you'll need your GitLab instance URL and registration token, found under Settings → CI/CD → Runners in you're project.
Multi-Stage Pipeline for Java Applications
Example configuration for a Spring Boot application with Docker deployment:
image: openjdk:11-jdk-slim
stages:
- compile
- test
- package
- deploy
cache:
paths:
- .m2/repository
- target/
compile_code:
stage: compile
script:
- ./mvnw compile
execute_tests:
stage: test
script:
- ./mvnw test
create_artifact:
stage: package
script:
- ./mvnw package -DskipTests
artifacts:
paths:
- target/*.jar
expire_in: 1 week
deploy_to_cloud:
stage: deploy
script:
- curl -L "https://cli.example.com/stable?release=linux64-binary" | tar zx
- ./cloud-cli login -u $CLOUD_USER -p $CLOUD_PASS -a api.cloudprovider.com
- ./cloud-cli deploy
only:
- main
Advanced Docker-Based Pipeline
For complex projects with multiple services, you can use Docker Compose within your pipeline:
stages:
- build_base
- package_artifacts
- run_services
build_base_image:
stage: build_base
script:
- docker build -t java-build-env -f ./BaseDockerfile .
tags:
- docker-runner
compile_services:
stage: package_artifacts
script:
- docker build -t maven-builder -f ./BuildDockerfile .
- docker run -v $PWD/artifacts:/output maven-builder
- docker build -t service-api -f ./api/Dockerfile .
- docker build -t service-worker -f ./worker/Dockerfile .
artifacts:
paths:
- artifacts/
tags:
- docker-runner
start_environment:
stage: run_services
script:
- docker-compose up -d
tags:
- docker-runner
only:
- main
Dockerfile Examples for Java Services
Base Envirnoment Dockerfile
FROM centos:8
# Install Java
RUN yum install -y wget tar
RUN mkdir -p /opt/java
RUN wget -P /opt/java https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz
RUN tar -xzf /opt/java/openjdk-11.0.2_linux-x64_bin.tar.gz -C /opt/java
ENV JAVA_HOME /opt/java/jdk-11.0.2
ENV PATH $JAVA_HOME/bin:$PATH
# Install Maven
RUN wget -P /opt https://downloads.apache.org/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
RUN tar -xzf /opt/apache-maven-3.6.3-bin.tar.gz -C /opt
ENV M2_HOME /opt/apache-maven-3.6.3
ENV PATH $M2_HOME/bin:$PATH
Application Service Dockerfile
FROM openjdk:11-jre-slim
WORKDIR /app
COPY artifacts/service-app.jar /app/service-app.jar
RUN chmod +x /app/service-app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/service-app.jar"]
Docker Compose Configuration
version: '3.8'
services:
web-service:
image: service-api
ports:
- "8080:8080"
restart: unless-stopped
command: ["java", "-jar", "/app/service-app.jar"]
background-worker:
image: service-worker
restart: unless-stopped
command: ["java", "-jar", "/app/worker-app.jar"]
Environment Variables and Secrets
Store sensitive data like API keys and credentials in GitLab CI/CD variables (Settings → CI/CD → Variables):
deploy_production:
stage: deploy
script:
- echo "Deploying to $DEPLOY_ENV"
- ./deploy.sh --token $API_TOKEN --env $DEPLOY_ENV
environment:
name: production
url: https://app.example.com
only:
- main
Artifacts and Caching
Optimize build times by caching dependencies and preserving build outputs:
variables:
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- .m2/repository/
- node_modules/
- target/
policy: pull-push
build_job:
stage: build
script:
- mvn clean compile
artifacts:
paths:
- target/classes/
- target/*.jar
reports:
junit: target/surefire-reports/TEST-*.xml
Pipeline Visualization and Monitoring
View pipeline execution in GitLab under CI/CD → Pipelines. Monitor job logs, track execution time, and review test reports. Failed pipelines provide detailed error logs for debugging.
Troubleshooting Common Issues
Container Exits Immediately
Ensure your Docker containers have persistent processes. For Java applications, avoid using -d flag in ENTRYPOINT and ensure the JVM runs in foreground mode.
File Permission Problems
Set appropriate permissions in Dockerfile:
RUN chmod 755 /app/application.jar
USER 1001
ENTRYPOINT ["java", "-jar", "/app/application.jar"]
Build Context Path Issues
When copying files in Dockerfile, paths are relative to build context. Ensure proper directory structure:
# Correct: Copy from relative path in build context
COPY ./target/app.jar /app/app.jar
# Incorrect: Using absolute host paths
COPY /home/runner/build/app.jar /app/app.jar