Operations 14 min read

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.

DevOps Cloud Academy
DevOps Cloud Academy
DevOps Cloud Academy
Comprehensive CI/CD Pipeline Templates for Java Projects with Build, Test, Code Analysis, Artifact Management, and Kubernetes Deployment

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: always

Test 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: always

Code 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: always

Artifact 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"
    - ls

Deployment 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: stop

The 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: always

Finally, 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Dockerci/cdAutomationKubernetesDevOpsGitLabPipeline
DevOps Cloud Academy
Written by

DevOps Cloud Academy

Exploring industry DevOps practices and technical expertise.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.