Overview
오늘은 GitLab CI/CD 구동방식과 문법에 대해 공부해보려고 한다.
그리고 .gitlab-ci.yml 파일을 작성하여 실습을 할 예정이다.
Gitlab 설치와 Gitlab Runner 설치는 아래의 페이지를 참고하길 바란다.
2023.04.20 - [IaC/CI CD Tool] - 1. GitLab이란? / 개념 및 설치
2023.04.23 - [IaC/CI CD Tool] - 2. GitLab이란? / GitLab Runner 개념 및 설치
GitLab CI/CD란?
GitLab CI/CD(연속 통합/연속 배포)는 애플리케이션 구축, 테스트 및 배포 프로세스를 자동화하는 GitLab의 기본 제공 기능이다.
모든 코드 변경에 대해 테스트 및 유효성 검사를 실행하여 코드베이스의 품질과 안정성을 보장하는 데 도움이 된다.
GitLab CI/CD는 휴먼 에러를 최소화하고 소프트웨어 개발 및 배포의 효율성을 높이는 것을 목표로 한다.
GitLab CI/CD의 작동 방식
구성(Configuration)
GitLab CI/CD는 Git 리포지토리의 루트 디렉터리에 저장된 .gitlab-ci.yml이라는 YAML 파일을 사용하여 구성된다.
이 파일은 빌드, 테스트 및 배포 프로세스를 설명하는 다양한 작업, 단계 및 규칙을 정의한다.
파이프라인(Pipeline)
커밋이 Git 리포지토리로 푸시되거나 병합 요청이 생성되면 GitLab CI/CD가 자동으로 파이프라인을 트리거한다.
파이프라인은 .gitlab-ci.yml 파일에 정의된 단계와 규칙에 따라 실행된다. 그리고 수동또는 예약된 이벤트에 의해 트리거될 수도 있다.
작업(Jobs)
작업은 애플리케이션 구축, 테스트 실행 또는 스테이징 또는 프로덕션 환경에 배포와 같은 파이프라인 내의 개별 작업이다. 각 작업은 .gitlab-ci.yml 파일에 정의되어 있으며 Docker 컨테이너, Kubernetes 클러스터 또는 GitLab Runner 내에서 실행된다.
단계(Stage)
단계는 빌드, 테스트 및 배포와 같은 파이프라인의 여러 단계를 나타낸다. 동일한 스테이지 내의 작업은 병렬로 실행되고 스테이지는 순차적으로 실행된다. 그리고 구조화된 방식으로 파이프라인을 구성하고 시각화하는 데 도움이 된다.
Runners
GitLab Runners는 파이프라인에 정의된 작업을 실행하는 에이전트이다. Linux, macOS 또는 Windows와 같은 다양한 플랫폼에 설치할 수 있으며 물리적 서버, 가상 머신 또는 컨테이너 환경에서 실행할 수 있다. 그리고 여러 프로젝트에서 공유하거나 특정 프로젝트 전용으로 사용할 수 있다.
아티팩트 및 캐싱(Artifacts and Caching)
아티팩트는 빌드 출력, 테스트 결과 또는 로그와 같이 작업 실행 중에 생성되는 파일이다.
파이프라인의 작업 간에 아티팩트를 전달하거나 추가 분석을 위해 다운로드할 수 있다. 캐싱은 파이프라인 실행 간에 파일 또는 종속성을 재사용하여 작업 실행 속도를 높이는 데 사용할 수 있다.
환경 및 배포(Environments and Deployments)
GitLab CI/CD는 스테이징, 프로덕션 또는 기능 분기와 같은 다양한 환경에 대한 배포를 지원한다. 그리고 환경은 배포를 관리 및 추적하고 애플리케이션 상태를 모니터링하며 롤백을 관리하는 데 도움이 된다.
GitLab Predefined Variable
GitLab에는 이미 정의된 변수들이 있다. 변수의 종류가 너무 많기 때문에 자주 쓰는 변수에 대해서만 알아보려고 한다.
자세한 내용은 아래의 사이트를 참고하길 바란다.
https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
CI_COMMIT_REF_NAME # 프로젝트가 빌드되는 브랜치
CI_COMMIT_SHORT_SHA # 8자리의 Commit 메세지
CI_REGISTRY # GitLab Container Registry의 주소(저는 Private Registry로 Harbor 사용중)
CI_PROJECT_DIR # 리포지토리가 복제되는 전체 경로 및 작업이 실행되는 위치
CI_REGISTRY_USER # gitlab USER
CI_REGISTRY_PASSWORD # gitlab password
GitLab Pipeline 예제
1. Basic Pipeline
# .gitlab-ci.yml
stages:
- build
- test
- deploy
image: alpine
build_a:
stage: build
script:
- echo "This job builds something."
build_b:
stage: build
script:
- echo "This job builds something else."
test_a:
stage: test
script:
- echo "This job tests something. It will only run when all jobs in the"
- echo "build stage are complete."
test_b:
stage: test
script:
- echo "This job tests something else. It will only run when all jobs in the"
- echo "build stage are complete too. It will start at about the same time as test_a."
deploy_a:
stage: deploy
script:
- echo "This job deploys something. It will only run when all jobs in the"
- echo "test stage complete."
environment: production
deploy_b:
stage: deploy
script:
- echo "This job deploys something else. It will only run when all jobs in the"
- echo "test stage complete. It will start at about the same time as deploy_a."
environment: production
2. Directed Acyclic Graph Pipelines
# .gitlab-ci.yml
stages:
- build
- test
- deploy
image: alpine
build_a:
stage: build
script:
- echo "This job builds something quickly."
build_b:
stage: build
script:
- echo "This job builds something else slowly."
test_a:
stage: test
needs: [build_a]
script:
- echo "This test job will start as soon as build_a finishes."
- echo "It will not wait for build_b, or other jobs in the build stage, to finish."
test_b:
stage: test
needs: [build_b]
script:
- echo "This test job will start as soon as build_b finishes."
- echo "It will not wait for other jobs in the build stage to finish."
deploy_a:
stage: deploy
needs: [test_a]
script:
- echo "Since build_a and test_a run quickly, this deploy job can run much earlier."
- echo "It does not need to wait for build_b or test_b."
environment: production
deploy_b:
stage: deploy
needs: [test_b]
script:
- echo "Since build_b and test_b run slowly, this deploy job will run much later."
environment: production
3. Parent-child pipelines
# /.gitlab-ci.yml
stages:
- triggers
trigger_a:
stage: triggers
trigger:
include: a/.gitlab-ci.yml
rules:
- changes:
- a/*
trigger_b:
stage: triggers
trigger:
include: b/.gitlab-ci.yml
rules:
- changes:
- b/*
# /a/.gitlab-ci.yml
stages:
- build
- test
- deploy
image: alpine
build_a:
stage: build
script:
- echo "This job builds something."
test_a:
stage: test
needs: [build_a]
script:
- echo "This job tests something."
deploy_a:
stage: deploy
needs: [test_a]
script:
- echo "This job deploys something."
environment: production
# /b/.gitlab-ci.yml
stages:
- build
- test
- deploy
image: alpine
build_b:
stage: build
script:
- echo "This job builds something else."
test_b:
stage: test
needs: [build_b]
script:
- echo "This job tests something else."
deploy_b:
stage: deploy
needs: [test_b]
script:
- echo "This job deploys something else."
environment: production
GitLab Pipeline 실습
1. 간단한 .gitlab-ci.yml 파일 작성
아래와 같이 간단히 작성해 본다.(main branch에 작성)
BRANCH 변수는 빌드할때 사용한다.
NAMESPACE 변수는 배포할때 사용한다.
따라서 dev1 이미지를 dev2 Namespace에 배포할수도 있고 그 반대도 가능하다.
# gitlab 파일
$ ls
README.md admin.Dockerfile apps config docker-compose.yml game.Dockerfile libs nest-cli.json package-lock.json package.json tsconfig.build.json tsconfig.json
$ cat .gitlab-ci.yml
stages:
- build # buld images & push to private image registry at once
- deploy # deploy to server
# 스크립트에서 사용할 변수 설정
variables:
# build 할때 사용
BRANCH:
value: "dev1"
description: "Select the branch: dev1 or dev2(use build)"
# deploy 할때 사용
NAMESPACE:
value: "dev1"
description: "Select the namespace: dev1 or dev2(use deploy)"
SERVICE:
value: "game"
description: "Select admin or game or etc."
CI_REGISTRY_IMAGE: $CI_REGISTRY/$SERVICE
BUILD_TAG: $BRANCH-$CI_COMMIT_SHORT_SHA
IMAGE_URL: '${CI_REGISTRY_IMAGE}:${BUILD_TAG}'
BUILD_TAG_LATEST: $BRANCH-latest
IMAGE_URL_LATEST: '${CI_REGISTRY_IMAGE}:${BUILD_TAG_LATEST}'
STATIC_DATA_PROJECT_ID: $project_id
GENERATE_JOB_ID: $job_id
.build_image: &build_image
stage: build
image:
# kaniko debug 이미지 사용
name: gcr.io/kaniko-project/executor:debug
# entrypoint 는 명시적으로 "" 빈 스트링 지정해야함.
entrypoint: [""]
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] BRANCH is $BRANCH
# registry 접속 정보를 저장하기 위한 디렉토리 생성
- mkdir -p /kaniko/.docker
# private 레지스트리에 대한 접속 정보 지정
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
script:
- /kaniko/executor --cache=true --cache-ttl=24h --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/$SERVICE.Dockerfile --destination $IMAGE_URL --destination $IMAGE_URL_LATEST --build-arg NODE_ENV=$BRANCH --skip-tls-verify
build_image:
<<: *build_image
rules:
- if: '($CI_PIPELINE_SOURCE == "web")'
- if: '($CI_PIPELINE_SOURCE == "trigger")'
tags:
- somaz-build-image
.deploy_job: &deploy_job
stage: deploy
image: dtzar/helm-kubectl
script:
- echo [INFO] Start deploy images.
- 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] IMAGE_TAG is $IMAGE_TAG
- echo [INFO] SERVICE is $SERVICE
- echo [INFO] NAMESPACE is $NAMESPACE
- kubectl set image deployment somaz-server-$SERVICE-$NAMESPACE app=$IMAGE_URL -n somaz-server-$NAMESPACE --insecure-skip-tls-verify
deploy_job:
<<: *deploy_job
rules:
- if: '($CI_PIPELINE_SOURCE == "web")'
- if: '($CI_PIPELINE_SOURCE == "trigger")'
# runner에 작성한 tag
tags:
- somaz-deploy-$NAMESPACE
그리고 Variable을 위와 같이 value로 작성하면 Run pipeline할때 아래와 같이 고를 수 있다.
그리고 저는 CI_REGISTRY로 Harbor를 사용중이다.
이제 build를 해줍니다. build를 해주면 아래와 같이 build가 잘되는것을 볼수 있다.
아래와 같이 잘 배포됩니다. 저는 deploy runner는 해당 namespace에 같이 만들었다.
$ k get po -n somaz-server-dev2
NAME READY STATUS RESTARTS AGE
somaz-server-game-dev2-5cf7d58769-mnf5k 1/1 Running 0 1h
gitlab-runner-somaz-dev2-gitlab-runner-574b7d4db-72qzb 1/1 Running 0 7d15h
gitlab-runner-somaz-dev2-gitlab-runner-574b7d4db-jw8dj 1/1 Running 0 7d15h
2. 조건을 사용한 .gitlab-ci.yml 파일 작성
그리고 지금은 수동으로 GitLab Web에서 Run Pipeline 버튼을 눌러 이미지를 Build하고 Deploy하는 코드이다.
아래와 같이 rules를 주면 코드가 바뀔때 자동으로 빌드/배포가 가능하게 할 수 있다.
changes 밑에 있는 파일들의 변경이 일어나고 push가 되면 자동으로 build를 해준다.
.change_files: &change_files
changes:
- apps/**/*
- config/*
- libs/**/*
- *.Dockerfile
- .gitlab-ci.yml
...
build_image:
<<: *build_image
rules:
- if: '($CI_PIPELINE_SOURCE == "push")'
<<: *change_files
- if: '($CI_PIPELINE_SOURCE == "web")'
- if: '($CI_PIPELINE_SOURCE == "trigger")'
tags:
- somaz-build-image
- * : 단일 디렉터리 내의 파일 또는 디렉터리와 일치한다.
- ** : 여러 디렉터리의 파일 또는 디렉터리와 일치한다.
3. 트리거를 사용하여 .gitlab-ci.yml 파일 작성
두개의 gitlab Repository(=Project)를 사용하여 A 프로젝트에서 WebHook URL과 Trigger Token을 사용하여 API를 전달하고 B 프로젝트에서 받아서 사용할수도 있다.
A Project(=Repository)
Token을 사용하여 100번 Project(=Repository)에 해당 API를 전달한다. variables를 사용하여 현재 Repository의 $CI_PROJECT_ID를 $project_id라는 변수로 전달하고 $CI_JOB_ID는 $job_id라는 변수로 전달한다.
그 이유는 B Project에서 A의 Project와 Job ID를 받아서 사용을 해야하기 때문이다.
B Project ID는 100번이다.
<생략>...
after_script:
- apk add curl
- "curl -X POST -F token=${GAMESERVER_TRIGGER_TOKEN} -F ref=${CI_COMMIT_REF_NAME} -F variables[project_id]=${CI_PROJECT_ID} -F variables[job_id]=${CI_JOB_ID} http://<gitlab 주소>/api/v4/projects/100/trigger/pipeline"
tags:
- build-image
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && ($CI_COMMIT_REF_NAME == "main")'
<<: *change_files
- $CI_PROJECT_ID : 현재 Project ID
- $CI_JOB_ID : 현재 Job ID
B Project
# 받은 변수 지정
variables:
STATIC_DATA_PROJECT_ID: $project_id
GENERATE_JOB_ID: $job_id
before_script:
- apt update && apt install -y unzip
- npm install
- 'curl --location --output artifacts.zip --header "PRIVATE-TOKEN: ${ARTIFACT_DOWNLOAD_TOKEN}" "http://<gitlab 주소>/api/v4/projects/${STATIC_DATA_PROJECT_ID}/jobs/${GENERATE_JOB_ID}/artifacts"'
Reference
GitLab CI/CD docs
GitLab Predefined Variable
GitLab CI/CD Workflow
GitLab Pipeline archiecture
'IaC > CI CD Tool' 카테고리의 다른 글
2. Github Action (With Syntax) (0) | 2023.05.22 |
---|---|
1. Github Action이란? (0) | 2023.05.19 |
ArgoCD란? (0) | 2023.05.17 |
2. GitLab이란? / GitLab Runner 개념 및 설치 (0) | 2023.04.23 |
1. GitLab이란? / 개념 및 설치 (0) | 2023.04.20 |