Understanding CI/CD Concepts
Continuous Integration (CI) involves frequently merging code changes into a shared repository, followed by automated builds and tests to detect integration issues early.
Continuous Delivery (CD) ensures that code is always in a deployable state and can be released to production at any time with minimal manual intervention.
Continuous Deployment (CD) goes a step further by automatically deploying every change that passes the pipeline directly to production environments.
- Setting Up GitLab with Docker
Deploy GitLab using Docker with persistent volumes and exposed ports:
docker run -d \
--name gitlab \
-p 8443:443 \
-p 9999:80 \
-p 9998:22 \
-v $PWD/config:/etc/gitlab \
-v $PWD/logs:/var/log/gitlab \
-v $PWD/data:/var/opt/gitlab \
-v /etc/localtime:/etc/localtime \
gitlab/gitlab-ce:latest
Access GitLab at http://<host-ip>:9999. Ensure the host has atleast 2 GB RAM (4 GB recommended for production).
To initialize a local project and push to GitLab:
git init
git config --global user.email "user@example.com"
git config --global user.name "YourName"
git remote add origin http://192.168.1.11:9999/root/java-demo.git
git add .
git commit -m "Initial commit"
git push origin master
- Deploying Harbor as a Private Registry
Install Docker Compose first, then configure and launch Harbor:
tar zxvf harbor-offline-installer-v1.9.1.tgz
cd harbor
# Edit harbor.yml: set hostname to 192.168.1.10
./prepare
./install.sh
After building an image locally, tag it for Harbor:
docker tag my-app:1.0 192.168.1.10/library/my-app:1.0
- Configuring Jenkins for CI/CD
Since Harbor uses HTTP (not HTTPS), configure Docker to trust the insecure registry:
{
"registry-mirrors": ["http://f1361db2.m.daocloud.io"],
"insecure-registries": ["192.168.1.10"]
}
Restart Docker: systemctl restart docker.
Install JDK and Maven on the host:
tar zxvf jdk-8u45-linux-x64.tar.gz
mv jdk1.8.0_45 /usr/local/jdk
tar zxf apache-maven-3.5.0-bin.tar.gz
mv apache-maven-3.5.0 /usr/local/maven
Run Jenkins container with necessary volume mounts:
docker run -d --name jenkins \
-p 8080:8080 -p 50000:50000 -u root \
-v /opt/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
-v /usr/local/maven:/usr/local/maven \
-v /usr/local/jdk:/usr/local/jdk \
-v /etc/localtime:/etc/localtime \
jenkins/jenkins:lts
Install required plugins (Pipeline, Git) and create a new pipeline job with a string parameter named Branch (default: master).
Pipeline Script
#!/usr/bin/env groovy
def REGISTRY = "192.168.1.10"
def PROJECT = "library"
def APP_NAME = "java-demo"
def IMAGE_TAG = "${REGISTRY}/${PROJECT}/${APP_NAME}:${params.Branch}-${BUILD_NUMBER}"
def GIT_REPO = "http://192.168.1.11:9999/root/java-demo.git"
def HARBOR_CRED = "harbor-credentials-id"
def GIT_CRED = "git-credentials-id"
pipeline {
agent any
stages {
stage('Clone Repository') {
steps {
checkout([$class: 'GitSCM',
branches: [[name: "*/${params.Branch}"]],
doGenerateSubmoduleConfigurations: false,
extensions: [],
userRemoteConfigs: [[
credentialsId: GIT_CRED,
url: GIT_REPO
]]
])
}
}
stage('Build Application') {
steps {
sh '''
export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:/usr/local/maven/bin:$PATH
mvn clean package -DskipTests
'''
}
}
stage('Build and Push Image') {
steps {
withCredentials([usernamePassword(
credentialsId: HARBOR_CRED,
passwordVariable: 'HARBOR_PASS',
usernameVariable: 'HARBOR_USER'
)]) {
sh """
cat > Dockerfile <<eof .="" add="" build="" container="" docker="" echo="" eof="" from="" label="" login="" maintainer="dev-team" push="" rm="" run="" sh="" stage="" steps="" stop="" target="" true=""></eof>
Before running the pipeline, add two credentials in Jenkins:
- A username/password credential for GitLab (used as
GIT_CRED) - A username/password credential for Harbor (used as
HARBOR_CRED)
Each pipeline stage logs detailed output for debugging and validation.