Comprehensive CI/CD Pipeline Templates for Java Projects with Build, Test, Code Analysis, Artifact Management, and Kubernetes Deployment
This article provides a detailed guide to structuring GitLab CI/CD pipelines for Java projects, covering job templates for building, testing, code analysis, artifact handling, and Kubernetes deployment, along with variable definitions, workflow rules, and stage configurations to enable flexible and automated DevOps workflows.
The guide explains how to organize CI/CD pipeline components using a jobs directory for job templates and a templates directory for the base pipeline definition, leveraging default-pipeline.yml as the foundational template.
Job Templates
Build job template (jobs/build.yml) includes two templates: a standard build and a Docker image build.
.build:
stage: build
script:
- |
${BUILD_SHELL}
variables:
GIT_CHECKOUT: "true"
rules:
- if: " $RUN_PIPELINE_BUILD == 'no' "
when: never
- when: always .build-docker:
stage: buildimage
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWD $CI_REGISTRY
- docker build -t ${IMAGE_NAME} -f ${DOCKER_FILE_PATH} .
- docker push ${IMAGE_NAME}
- docker rmi ${IMAGE_NAME}
rules:
- if: " $RUN_BUILD_IMAGE == 'no' "
when: never
- when: alwaysTest job template (jobs/test.yml) runs unit tests for Maven, Gradle, or npm projects.
.test:
stage: test
script:
- $TEST_SHELL
artifacts:
reports:
junit: ${JUNIT_REPORT_PATH}
rules:
- if: " $RUN_PIPELINE_TEST == 'no' "
when: never
- when: alwaysCode analysis template (jobs/codeanalysis.yml) configures SonarQube scanning and result retrieval.
.code_analysis:
stage: code_analysis
script:
- echo ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${GLOBAL_MR_ARGS}
- |
if [ $CI_PIPELINE_SOURCE == 'merge_request_event' ]
then
sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS}
else
sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${MULTI_BRANCH_ARGS}
fi
rules:
- if: " $RUN_CODE_ANALYSIS == 'no' "
when: never
- when: always .get_analysis_result:
stage: get_analysis_result
script:
- |
SONAR_REPORT_URL=$(grep "ceTaskUrl" .scannerwork/report-task.txt | awk -F = '{OFS="=";print $2,$3}')
echo ${SONAR_REPORT_URL}
for i in {1..10}
do
curl -k -u "${SONAR_SERVER_LOGIN}":"" ${SONAR_REPORT_URL} -o sonar_result.txt -s
grep '"status":"SUCCESS"' sonar_result.txt && SONAR_SCAN_RESULT='SUCCESS'
if [ ${SONAR_SCAN_RESULT} == 'SUCCESS' ]; then
echo "${SONAR_SCAN_RESULT}"
curl -k -u "${SONAR_SERVER_LOGIN}":"" "${SONAR_SERVER_URL}/api/qualitygates/project_status?projectKey=${CI_PROJECT_NAME}&branch=${CI_COMMIT_REF_NAME}" -o result.txt -s
result=$(cat result.txt | awk -F ':' '{print $3}' | awk -F '"' '{print$2}')
echo $result
if [ $result == 'ERROR' ]; then
echo "${result}"
exit 122
else
echo "success!"
fi
break
else
echo "Attempt $i: not successful, sleeping 10s"
sleep 10
fi
done
rules:
- if: " $RUN_CODE_ANALYSIS == 'no' "
when: never
- when: alwaysArtifact management template (jobs/artifactory.yml) handles uploading and downloading of build artifacts.
.deploy-artifact:
stage: deploy-artifact
script:
- echo "curl -u${ARTIFACT_USER}:${ARTIFACT_PASSWD} -T ${ARTIFACT_PATH} $ARTIFACTORY_URL/$ARTIFACTORY_NAME/$TARGET_FILE_PATH/$TARGET_ARTIFACT_NAME"
- curl -u${ARTIFACT_USER}:${ARTIFACT_PASSWD} -T ${ARTIFACT_PATH} "$ARTIFACTORY_URL/$ARTIFACTORY_NAME/$TARGET_FILE_PATH/$TARGET_ARTIFACT_NAME"
rules:
- if: " $RUN_DEPLOY_ARTIFACTS == 'no' "
when: never
- when: always .down-artifact:
stage: down-artifact
script:
- curl -u${ARTIFACT_USER}:${ARTIFACT_PASSWD} -O "$ARTIFACTORY_URL/$ARTIFACTORY_NAME/$TARGET_FILE_PATH/$TARGET_ARTIFACT_NAME"
- lsDeployment template (jobs/deploy.yml) provides Kubernetes deployment and rollback configurations.
.deploy_k8s:
stage: deploy
script:
- echo $KUBE_TOKEN
- kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}"
- kubectl config set-credentials admin --token=${KUBE_TOKEN}
- sed -i "s#__namespace__#${NAMESPACE}#g" ${DEPLOY_FILE}
- sed -i "s#__appname__#${APP_NAME}#g" ${DEPLOY_FILE}
- sed -i "s#__containerport__#${CONTAINER_PORT}#g" ${DEPLOY_FILE}
- sed -i "s#__nodeport__#${NODE_PORT}#g" ${DEPLOY_FILE}
- sed -i "s#__imagename__#${IMAGE_NAME}#g" ${DEPLOY_FILE}
- cat ${DEPLOY_FILE}
- "kubectl create secret docker-registry ${APP_NAME} \
--docker-server=${CI_REGISTRY} \
--docker-username=$CI_REGISTRY_USER \
--docker-password=${CI_REGISTRY_PASSWD} \
[email protected] -n ${NAMESPACE} || echo 'secrets already exists'"
- kubectl apply -f ${DEPLOY_FILE}
rules:
- if: " $RUN_DEPLOY_K8S == 'no' "
when: never
- when: manual
environment:
name: "${ENV_NAME}"
url: "http://${ENV_NAME}.${CI_PROJECT_NAMESPACE}.${CI_PROJECT_NAME}.devops.com" .rollout_k8s:
stage: deploy
script:
- rm -rf $HOME/.kube
- kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}"
- kubectl config set-credentials admin --token=${KUBE_TOKEN}
- kubectl rollout history deployment ${APP_NAME} -n ${NAMESPACE}
- kubectl rollout undo deployment ${APP_NAME} -n ${NAMESPACE}
rules:
- if: " $RUN_DEPLOY_K8S == 'no' "
when: never
- when: manual
environment:
name: "${ENV_NAME}"
action: stopThe templates/default-pipeline.yml file defines the overall pipeline structure, including include statements to import the job templates, global variables, workflow rules to filter triggers, and the ordered list of stages such as build, test, code analysis, artifact handling, and deployment.
include:
- project: 'cidevops/cidevops-newci-service'
ref: master
file: 'jobs/build.yml'
- project: 'cidevops/cidevops-newci-service'
ref: master
file: 'jobs/test.yml'
- project: 'cidevops/cidevops-newci-service'
ref: master
file: 'jobs/codeanalysis.yml'
- project: 'cidevops/cidevops-newci-service'
ref: master
file: 'jobs/deploy.yml'
- project: 'cidevops/cidevops-newci-service'
ref: master
file: 'jobs/artifactory.yml' variables:
## Global configuration
GIT_CLONE_PATH: ${CI_BUILDS_DIR}/builds/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}/${CI_PIPELINE_ID}
GIT_CHECKOUT: "false"
CACHE_DIR: ""
## Job control flags
RUN_PIPELINE_BUILD: ""
RUN_PIPELINE_TEST: ""
RUN_CODE_ANALYSIS: ""
RUN_BUILD_IMAGE: ""
RUN_DEPLOY_ARTIFACTS: ""
RUN_DEPLOY_K8S: ""
## Dependency images
BUILD_IMAGE: ""
CURL_IMAGE: "curlimages/curl:7.70.0"
SONAR_IMAGE: "sonarsource/sonar-scanner-cli:latest"
KUBECTL_IMAGE: "lucj/kubectl:1.17.2"
...The workflow section defines rules to prevent pipeline execution on merge requests, on branch creation, or on specific branch patterns, while allowing manual triggers.
workflow:
rules:
- if: "$CI_MERGE_REQUEST_ID"
when: never
- if: "$CI_PIPELINE_SOURCE == 'web'"
when: always
- if: "$CI_COMMIT_REF_NAME =~ /^RELEASE-*/ || $CI_COMMIT_REF_NAME =~ /master/"
when: never
- if: "$CI_COMMIT_BEFORE_SHA == '0000000000000000000000000000000000000000'"
when: never
- when: alwaysFinally, the article showcases a complete Java project pipeline example, demonstrating how to import the default template, set project‑specific variables, and enable or disable individual stages such as building, testing, code analysis, artifact upload, and Kubernetes deployment.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
DevOps Cloud Academy
Exploring industry DevOps practices and technical expertise.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
