DevOps, Infra

[CI/CD] Advanced GitLab CI, gitlab-ci.yml

seulseul 2023. 9. 14. 01:53

현재 진행중인 프로젝트에서는 CI툴로 gitlab runner 를 helm chart 기반으로 구성하여 eks에 띄워, gitlab ci로 CI 작업을 이행하고 있습니다.

 

gitlab ci 를 사용하며 템플릿 ,공통 yaml 을 구성하며 익힌 팁을 공유합니다.

 

1. 사전에 정의된 variable

GitLab 사전에 정의된 variable 값 사용 (Predefined Variables)

 

CI_COMMIT_BRANCH (커밋 브랜치) , CI_PROJECT_DIR (프로젝트 경로) , CI_PROJECT_NAME (프로젝트 이름) 을 비롯해

CI_COMMIT_TITLE (커밋 메세지) 등은 사전에 gitlab에 정의된 variable들인데 이를 잘 활용하면 프로젝트 정보를 코드에서 쉽게 사용할 수 있습니다.

variables:
  # Docker Image NAME (ex : nexus.seul.com/demo-api)
  REGISTRY_IMAGE: $REGISTRY_URL/$CI_PROJECT_NAME
  # Docker Image TAG  (ex : main-54-223)
  BUILD_TAG: $CI_COMMIT_REF_NAME-$CI_PROJECT_ID-$CI_PIPELINE_ID

2. rules

rules 기반 variable값을 다르게 지정함으로써 하나의 ci 파일로 여러 프로젝트에 공용할 수 있습니다.

variables:
  DOCKER_TAG: $CI_COMMIT_REF_NAME-$CI_PROJECT_ID-$CI_PIPELINE_ID # DOCKER 이미지 tag
  rules:
    - if: $CI_COMMIT_REF_NAME == "main"
      variables:
        DOCKER_TAG: "latest"      # Override
    - if: $CI_COMMIT_BRANCH == "main" && $CI_COMMIT_TAG != null
      variables:
        DOCKER_TAG: $CI_COMMIT_TAG # Override

 

 

3. template 형태로 코드를 재사용하기

image나 rule, script 코드가 여러 stage에서 동일하거나 유사한 구조인 경우가 많습니다.

이때는 매번 코드를 반복해서 적는 것 보다는 template 형태로 관리하는 것이 추후 코드 수정시에도 용이하고, 코드의 가독성을 높여줍니다.

템플렛은 기본적으로 .으로 시작되도록 네이밍을 하고, extends나 !reference를 통해서 불러올 수 있습니다. 아래 예시는 위의 2번에서 쓴 코드를 template 기반으로 재구성한 형태입니다.

.rules_template:
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "master"
      variables:
        DOCKER_BASE_IMAGE: $DOCKER_BASE_IMAGE_PRD
      when: always
    - if: $CI_COMMIT_BRANCH == "develop"  || $CI_COMMIT_BRANCH == "dev"
      variables:
        DOCKER_BASE_IMAGE: $DOCKER_BASE_IMAGE_DEV
      when: always
    - if: $CI_COMMIT_BRANCH == "main" && $CI_COMMIT_TAG != null
      variables:
        BUILD_TAG: $CI_COMMIT_TAG
        DOCKER_BASE_IMAGE: $DOCKER_BASE_IMAGE_PRD
      when: always
    - when: never
deploy:
  rules:
    - !reference [ .rules_template, rules ]
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache git curl bash coreutils
    - curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash
    - mv kustomize /usr/local/bin/
  script:
    - echo "------------------------------------------------------------"
    - echo "GitOps Repository deploy"
    - echo "------------------------------------------------------------"
    - git remote set-url origin "https://${CI_USERNAME}:${CI_PUSH_TOKEN}@${GITOPS_REPO_URL}"
    - git config --global user.email "${GITLAB_USER_EMAIL}"
    - git config --global user.name "${GITLAB_USER_LOGIN}"
...

4. artifacts

artifacts 는 저장 및 업로드할 수 있도록 Job에 의해 생성되는 파일이다.

동일한 파이프라인의 이후 단계의 Job에서 아티팩트를 가져와 사용할 수 있다.

이 데이터는 다른 파이프라인에서 사용할 수 없지만 최대 아티팩트 크기(1G)  를 넘지 않으면 GitLab UI 에서 다운로드 할 수 있다.

애플리케이션을 빌드하는 동안 모듈을 다운로드하는 경우, 이를 아티팩트로 선언하고 후속 단계의 Job에서 이를 사용할 수 있다.

Source-Build:
  stage: build
  image: eclipse-temurin:17-jdk
  script:
    - echo "------------------------------"
    - echo "메이븐 빌드&패키지 $CI_PROJECT_PATH"
    - echo "------------------------------"
    - sh mvnw package
  artifacts:
    paths:
      - "target/*.jar"
    expire_in: 5 mins

Docker-Build:
  stage: docker
  image:
    name: docker/compose:latest
  services:
    - docker:dind
  script:
    - echo "Docker Image Build & Push"
    - ls -al $CI_PROJECT_DIR/target
    
    (... 생략 ...)

5. GitLab Runner tags 기능

gitlab에서는 각각의 환경에서 작업이 수행되도록 runner를 2종류(window executor, k8s executor) 준비하고, 각각의 runner에 tag를 지정해 둡니다.

그리고 ci file에서 tags라는 값에 설정해놓은 값을 넣어주면 해당 작업이 지정한 아키텍처에서 구동되도록 해줍니다.

deploy-job:
  extends: .rules_template
  stage: deploy
  image: !reference [.templates_build, image]
  tags:
    - window-executor
  script:
    - !reference [.templates_build, script]