IaC/CI CD Tool

7. Gitlab CI Template 활용

Somaz 2024. 6. 27. 13:37
728x90
반응형

Overview

Gitlab CI를 작성할때 Template을 활용하여 작성하는 방법에 대해서 알아본다. 

출처 : https://medium.com/globant/optimize-pipeline-implementation-using-gitlab-ci-templates-6eef54046231

 


 

Gitlab CI Template 활용

 

Gitlab에서 제공해주는 다양한 template 들도 있다.

 

template 파일을 참조하는 방법은 아래와 같다.

# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml

include:
  - template: Terraform/Base.gitlab-ci.yml  # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml
  - template: Jobs/SAST-IaC.gitlab-ci.yml   # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/SAST-IaC.gitlab-ci.yml

 

만약 자신의 gitlab의 project에 template이 정의되어 있다면 아래와 같이 작성하면 된다.

 

include:
  - project: 'somaz94/server'
    ref: master
    file: '/template/my_template_file.yml'

 

 

참조하지 않고 `.gitlab-ci.yml` 에 정의해도 무관하다.

 

 


 

 

Template 작성

 

아래와 같이 build 관련한 template을 작성한다.

.templates:
  .common_build_before_script: &common_build_before_script
    - echo "[INFO] Start build image."
    - echo "[INFO] CI_REGISTRY is $CI_REGISTRY"
    - echo "[INFO] CI_REGISTRY_IMAGE is $CI_REGISTRY_IMAGE"
    - echo "[INFO] BUILD_TAG is $BUILD_TAG"
    - echo "[INFO] IMAGE_URL is $IMAGE_URL"
    - echo "[INFO] BUILD_TAG_LATEST is $BUILD_TAG_LATEST"
    - echo "[INFO] IMAGE_URL_LATEST is $IMAGE_URL_LATEST"
    - echo "[INFO] CI_PROJECT_DIR is $CI_PROJECT_DIR"
    - echo "[INFO] SERVICE is $SERVICE"
    - echo "[INFO] GCP Config"
    - echo "[INFO] GCP_CI_REGISTRY is $GCP_CI_REGISTRY"
    - echo "[INFO] GCP_CI_REGISTRY_IMAGE is $GCP_CI_REGISTRY_IMAGE"
    - echo "[INFO] GCP_IMAGE_URL is $GCP_IMAGE_URL"
    - echo "[INFO] GCP_IMAGE_URL_LATEST is $GCP_IMAGE_URL_LATEST"
    - echo "[INFO] NAMESPACE is $NAMESPACE"
    - mkdir -p /kaniko/.docker
    - >
      if [[ "$NAMESPACE" =~ ^sarena- ]]; then
        echo "Configuring registry for special namespace $NAMESPACE"
        cp gcloud/config.json /kaniko/.docker/config.json
      else
        echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
      fi

  .common_build_script: &common_build_script
    - >
      if [[ "$NAMESPACE" =~ ^sarena- ]]; then
        /kaniko/executor --cache=true --cache-ttl=24h --snapshot-mode=redo --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/$SERVICE.Dockerfile --destination $GCP_IMAGE_URL --destination $GCP_IMAGE_URL_LATEST --build-arg NODE_ENV=$NAMESPACE --skip-tls-verify
      else        
        /kaniko/executor --cache=true --cache-ttl=24h --snapshot-mode=redo --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/$SERVICE.Dockerfile --destination $IMAGE_URL --destination $IMAGE_URL_LATEST --build-arg NODE_ENV=$NAMESPACE --skip-tls-verify
      fi 
    - KANIKO_RESULT=$?
    - echo "$SERVICE" > service_status.txt
    - >
      if [ $KANIKO_RESULT -eq 0 ]; then
        echo "✅ 성공" > build_status.txt
      else
        echo "❌ 실패" > build_status.txt
      fi

 

 

그리고 아래와 같이 활용할 수 있다.

build_manual_image:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:v1.22.0-debug
  interruptible: true
  retry:
    max: 2  # Maximum of 2 retries
    when:
      - runner_system_failure
      - unknown_failure
  before_script: *common_build_before_script
  script: *common_build_script
  artifacts:
    paths:
      - build_status.txt
      - service_status.txt
  rules:
    - if: '($CI_PIPELINE_SOURCE == "web")'
  tags:
    - build-image

 

 

그리고 다른 job에도 활용이 가능하다. 

.change_files_game: &change_files_game
  changes:
    - apps/game/src/**/*

build_auto_image_game:
  stage: build
  image: 
    name: gcr.io/kaniko-project/executor:v1.22.0-debug
  interruptible: true
  retry:
    max: 2  # Maximum of 2 retries
    when:
      - runner_system_failure
      - unknown_failure
  before_script: *common_build_before_script
  script: *common_build_script
  variables:
    SERVICE: $GAME_SERVICE
    IMAGE_URL: $IMAGE_URL_GAME
    IMAGE_URL_LATEST: $IMAGE_URL_LATEST_GAME
  artifacts:
    paths:
      - build_status.txt
      - service_status.txt
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"'
      <<: *change_files_game
  tags:
    - build-image

 

 

SLACK에 메세지 보내는 템플릿도 아래와 같이 작성할 수 있다. 각각의 job마다 artifact로 결과를 받아서 메세지를 보내면 된다.

  .common_update_after_script: &common_update_after_script
    - >
      if [ "$CI_JOB_STATUS" = "success" ]; then
        echo "✅ 성공" > /builds/somaz94/server/update_status.txt
      elif [ "$CI_JOB_STATUS" = "failed" ]; then
        echo "❌ 실패" > /builds/somaz94/server/update_status.txt
      elif [ "$CI_JOB_STATUS" = "canceled" ]; then
        echo "⚠️ 취소" > /builds/somaz94/server/update_status.txt
      else
        echo "🔍 상태 불명" > /builds/somaz94/server/update_status.txt
 ...
 
 update_manual_image:
  stage: update
  image: alpine:latest
  interruptible: true
  retry:
    max: 2  # Maximum of 2 retries
    when:
      - runner_system_failure
      - unknown_failure
  before_script: *common_update_before_script
  script: *common_update_script 
  after_script: *common_update_after_script
  artifacts:
    paths:
      - update_status.txt
  rules:
    - if: $CI_PIPELINE_SOURCE == "web"
  tags:
    - deploy-image
  dependencies:
    - build_manual_image

 

 

나는 SLACK 웹훅을 활용했고, 워크플로우 빌더를 활용해 결과 값만 받으면 되게 작성하였다.

Build Result
[작업 상태]
- 프로젝트 : 
- 대상 환경 : 
- 배포 서비스: 
- 기준 브랜치 : 
- generator 결과 : 
- 빌드 결과 : 
- 배포 결과 : 
- Gitlab CI URL : 
- Commit Message : 
- 트리거 유저 :

 

 

 

Slack notify Template을 작성해준다.

  .common_notify_slack_script: &common_notify_slack_script
    - export GENERATOR_STATUS=$(cat generator_status.txt || echo "⏭️ 스킵 or ✅ Commit Massage 확인")
    - export BUILD_STATUS=$(cat build_status.txt || echo "⏭️ 스킵")
    - export UPDATE_STATUS=$(cat update_status.txt || echo "⏭️ 스킵")
    - export DEPLOY_SERVICE=$(cat service_status.txt || echo "⏭️ 스킵")
    - export CLEAN_COMMIT_MESSAGE=$(echo "$CI_COMMIT_MESSAGE" | tr -d '\n' | tr -d '\r')
    - >
      export JSON_DATA="{\"source_branch\": \"$CI_COMMIT_REF_NAME\", \"generator_result\": \"$GENERATOR_STATUS\", \"deploy_result\": \"$UPDATE_STATUS\", \"build_result\": \"$BUILD_STATUS\", \"commit_message\": \"$CLEAN_COMMIT_MESSAGE\", \"trigger_user\": \"$GITLAB_USER_LOGIN\", \"gitlab_ci_run_url\": \"$CI_PIPELINE_URL\", \"repository_name\": \"$CI_PROJECT_PATH\", \"environment\": \"$NAMESPACE\", \"deploy_service\": \"$DEPLOY_SERVICE\"}"
    - >
      echo "Sending the following data to Slack: $JSON_DATA"
    - >
      export RESPONSE=$(curl -sS -X POST -H 'Content-type: application/json' --data "$JSON_DATA" $SLACK_WEBHOOK_URL)
    - >
      echo "Slack response: $RESPONSE"

 

 

그리고 아래와 같이 yml 파일을 작성해준다.

notify_slack:
  stage: notify
  image: curlimages/curl:latest
  script: *common_notify_slack_script
  rules:
    - if: $CI_PIPELINE_SOURCE == "web"
    - if: $CI_PIPELINE_SOURCE == "trigger"
  tags:
    - deploy-image
  when: always

...
notify_slack_auto_game:
  stage: notify
  image: curlimages/curl:latest
  script: *common_notify_slack_script
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push"'
      <<: *change_files_game
  tags:
    - deploy-image
  when: always
  dependencies:
    - build_auto_image_game
    - update_auto_image_game

 

 

 

 

이런식으로 활용하면, template을 작성해 아래와 같이 다양한 job에 적용이 가능하다.

 

 


Reference

https://icinga.com/blog/2022/10/05/gitlab-ci-cd-job-templates/

https://about.gitlab.com/blog/2020/09/23/get-started-ci-pipeline-templates/#what-are-ci-pipeline-templates

728x90
반응형