GitLab

KH55S·2025년 12월 2일
post-thumbnail

GitLab

  • GitLab은 소프트웨어 개발 및 협업을 위한 올인원 DevOps 플랫폼으로, 코드 저장소 관리뿐만 아니라 CI/CD 기능까지 제공하는 강력한 도구이다.
  • GitLab이 대기업에서 깃허브보다 많이 사용되는 이유
    • 소프트웨어를 다운로드해서 회사의 폐쇄망 서버에 직접 설치할 수 있다.
    • 내부 소스코드나 인프라 설정(IaC) 코드가 외부로 유출되면 안 되기 때문에 인터넷이 차단된 폐쇄망 환경 내부에 GitLab 서버를 구축해두면 외부 인터넷 연결 없이도 내부 직원들끼리 코드를 공유하고 배포할 수 있다. 즉, 자체 호스팅이 가능해진다.
    • 태생부터 코드 저장소 + CI/CD 파이프라인이 하나로 합쳐져 있다.
      • 코드를 푸시하자마자 테스트하고, 이미지를 빌드하고, 배포하는 과정이 GitLab 화면 하나에서 다 보인다. 별도의 Jenkins 서버를 관리할 필요가 줄어들어 운영 복잡도가 낮아진다.
  • GitLab 자체 호스팅
    • GitLab 자체가 하나의 리눅스 애플리케이션이라는 의미
    • 설치 : 회사의 서버에 GitLab 패키지(Omnibus 또는 Docker 이미지)를 다운로드하여 설치한다.
    • 구성 : gitlab.rb라는 설정 파일을 통해 웹서버, 데이터베이스, 캐시 등을 자동으로 구성한다.
    • 접속 : 설치가 끝나면 회사 내부 IP나 도메인으로 웹 브라우저를 통해 접속한다. Github와 똑같은 UI가 뜨지만, 이 서버는 오직 회사 내부에만 존재한다.
  • CE (Community Edition) vs EE (Enterprise Edition)
    • CE : 누구나 무료로 설치해서 쓸 수 있다. 기능 제한이 있다고는 하지만, 사실상 개발하고 배포하는 데 필요한 기능은 다 있다.
    • EE : 누가 언제 이 코드를 승인했는가? 같은 감사(Audit) 기능, 여러 서버에 GitLab을 분산시켜 죽지 않게 만드는 고가용성(HA), 그리고 보안 스캔 기능 등이 추가된다.
비교 항목GitLab CE (무료)GitLab EE (유료)
라이센스오픈소스 (MIT)프로프라이어터리 (독점)
기본 기능Git 리포지토리, CI/CD, 코드 리뷰CE의 모든 기능 + 고급 보안 및 관리 기능
CI/CD포함고급 CI/CD (병렬 실행, 실행 우선순위)
보안 및 규정 준수제한적스캔, 감사 로그, SAML 인증
고급 DevOps 기능없음프로젝트 관리, Jira 통합
Self-Hosted 지원가능가능
SaaS(Cloud) 지원가능가능 (GitLab Ultimate)

  • GitLab 설치
sudo apt update
sudo apt upgrade -y

# Install package 
sudo apt install -y ca-certificates curl openssh-server tzdata

# GitLab CE Repository 추가
sudo apt install debian-archive-keyring lsb-release ca-certificates apt-transport-https software-properties-common -y

# GitLab 설치용 저장소 등록
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash

# 패키지 저장소 업데이트 및 설치
sudo apt update

# GitLab CE 설치
# EXTERNAL_URL : GitLab에 접속할 주소
# 설치 시 이 변수를 넘겨주면 gitlab.rb 설정 파일에 자동으로 기록된다.
sudo EXTERNAL_URL="https://gitlab.example.com" apt-get install gitlab-ce

# HTTPS (SSL) 설정
sudo vi /etc/gitlab/gitlab.rb

# Let's Encrypt 활성화
letsencrypt['enable'] = true

# 외부에서 접속할 URL (반드시 https)
external_url 'https://gitlab.example.com'

# 인증서 만료 알림을 받을 이메일
letsencrypt['contact_emails'] = ['admin@example.com']

# 인증서 자동 갱신 활성화 (무료 인증서는 90일 만료라 자동 갱신 필수)
letsencrypt['auto_renew'] = true

# 30일마다 갱신 시도
letsencrypt['auto_renew_day_of_month'] = "*/30"

# 로그 저장 위치
letsencrypt['auto_renew_log_directory'] = '/var/log/gitlab/lets-encrypt'

sudo gitlab-ctl reconfigure

# 운영 및 관리 명령어

# 설정 적용
# gitlab.rb 파일을 수정했다면 무조건 실행해야 한다.
# Chef라는 자동화 도구가 내부적으로 돌면서,Nginx, DB 등을 설정에 맞게 다시 세팅
sudo gitlab-ctl reconfigure

# 서비스 재시작
# 설정 변경 없이 단순히 프로세스만 껐다 켤 때 사용
sudo gitlab-ctl restart

# 상태 확인
# 모든 서비스(Nginx, DB, Redis 등)가 run 상태인지 확인
sudo gitlab-ctl status

# 초기 root 비밀번호 확인 (설치 후 24시간 내에만 유효)
sudo cat /etc/gitlab/initial_root_password

  • 중요 디렉토리
  • /var/opt/gitlab/gitlab-rails/shared/lfs-objects
    • 해당 디렉터리는 Git 대용량 파일 저장소(LFS) 개체를 저장하는 데 사용된다.
    • Git LFS는 사용자가 바이너리 자산과 같은 대용량 파일을 보다 효율적으로 버전화할 수 있도록 하는 Git용 extension이다.
    • 전체 대용량 파일을 Git 저장소에 저장하는 대신 LFS는 파일에 대한 포인터만 저장하는 반면 실제 파일은 서버에 별도로 저장된다. (이 경우 lfs-objects 디렉토리)
    • 이 설정은 Git 리포지토리의 크기를 줄이고 Git 작업의 성능을 향상시키는 데 도움이 된다.
    • 이 디렉토리는 용량이 매우 빠르게 늘어나기 때문에 서버를 구축할 때 이 경로에 용량이 큰 디스크를 별도로 마운트 하는 경우가 많다.
  • /var/opt/gitlab/git-data
    • 해당 디렉토리는 GitLab 인스턴스에서 관리하는 실제 Git 리포지토리 및 기타 리포지토리 관련 데이터를 저장하는 데 사용된다. (모든 프로젝트의 코드, 커밋 기록, 브랜치 정보)
    • GitLab 설치에서 각 프로젝트에는 프로젝트의 소스 코드, 버전 기록 및 기타 관련 데이터가 포함된 자체 Git 리포지토리가 있다.
    • /var/opt/gitlab/git-data 디렉토리는 이러한 모든 리포지토리와 관련 데이터를 저장하기 위한 루트 디렉토리 역할을 한다.
    • 만약 Gitlab 서버가 해킹당하거나 고장 나도, 이 폴더만 무사하면 코드는 복구할 수 있다.

Docker로 GitLab 설치

mkdir gitlab-docker && cd gitlab-docker
vi docker-compose.yml


version: '3.6'

services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab
    restart: always
    hostname: '10.10.10.3'           # VM의 IP로 고정
    
    # 메모리 부족 에러 방지 (GitLab 권장 사항)
    shm_size: '256m'
    
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://10.10.10.3'
        
        # SSH 포트 변경 (Host의 22번과 충돌 방지)
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        
    ports:
      - '80:80'
      - '443:443'
      - '2222:22'  # 호스트 2222 포트를 컨테이너 22로 연결
      
    volumes:
      # 호스트의 현재 폴더(./)에 데이터를 저장
      - './config:/etc/gitlab'
      - './logs:/var/log/gitlab'
      - './data:/var/opt/gitlab'
      
# ID : root      
# 비밀번호 확인
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

📌 트러블슈팅
ERROR: for gitlab Cannot start service gitlab: failed to set up container networking: driver failed programming external connectivity on endpoint gitlab (5d7a6f2f7d86f3098f1bfe1becd17c3fc21bed2115a6c73522fae6f75d1472f6): failed to bind host port 0.0.0.0:443/tcp: address already in use

  • 이미 포트 443을 다른 프로그램이 사용하고 있어서 Docker가 실행되지 못함
  • 443 포트를 사용하고 프로세스 확인 : sudo netstat -tulpn | grep :443
  • 글쓴이는 Docker로 GitLab을 설치하기 전 apt install로 설치를 했었기 때문에 다음의 단계를 진행
    • 기존 GitLab 서비스 중지 : sudo gitlab-ctl stop
    • 기존 GitLab 제거 : sudo apt-get remove gitlab-ce gitlab-ee
    • 포트가 비었는지 확인 : sudo netstat -tulpn | grep :443

GitLab Runner

  • GitLab CI/CD 파이프라인에서 정의된 작업을 실제로 수행하고 그 결과를 GitLab 서버로 반환하는 톡립적인 오픈소스 애플리케이션.
  • GitLab 서버는 작업을 실행하지 않는다. 대신 어떤 작업을 해야 한다고 스케줄링만 한다. 실제로 코드를 다운로드, 빌드, 테스트, 배포하는 연산 작업은 전부 GitLab Runner가 담당한다.
    • 구조적 특징 : GitLab 서버와 Runner는 1:N 관계. 하나의 GitLab 서버에 수십, 수백 개의 Runner를 연결할 수 있어 부하 분산이 가능하다.
    • 보안적 특징 : 실제 소스 코드가 실행되는 환경이므로, 운영 서버와 분리된 별도의 격리된 환경(VM, 컨테이너 등)에서 실행하는 것이 원칙이다.
  • GitLab Runner의 종류 (사용 범위와 실행 환경으로 분류)
    • 사용 범위에 따른 분류
    • Shared Runner (공유 러너)
      • GitLab 인스턴스 전체에서 공유해서 사용하는 Runner
      • 관리자가 설정하며, 모든 프로젝트가 이 Runner를 사용하여 작업을 수행할 수 있다.
      • 일반적으로 큐 방식으로 요청한 작업부터 처리한다.
    • Group Runner (그룹 러너)
      • 특정 그룹 내의 모든 프로젝트와 하우 그룹이 공유하는 Runner
    • Specific Runner (프로젝트 전용 러너)
      • 특정 프로젝트에만 할당된 Runner
      • 특수한 요구사항이 있거나, 다른 프로젝트와 리소스를 공유하고 싶지 않을 때 사용한다.

    • 실행 환경(Executor)에 따른 분류
    • Shell Executor : Runner가 설치된 머신의 쉘에서 직접 명령어를 실행한다.
    • Kubernetes Executor : 작업이 요청되면 K8s 클러스터 내에 새로운 Pod를 생성하여 실행한다.
    • Docker Executor (가장 많이 사용)
      • 작업이 시작될 때마다 지정된 Docker 이미지를 기반으로 새로운 컨테이너를 생성하여 그 안에서 스크립트를 실행한다.
      • 완벽한 환경 격리가 보장되고, 작업이 끝나면 컨테이너는 삭제된다.

  • Runner 작동 방식
    • Runner는 서버가 시킬 때까지 가만히 기다리는 것이 아니라, 능동적으로 서버에 요청하는 폴링(Polling) 방식을 사용한다. 이 구조 덕분에 Runner가 사설망에 있어도 외부의 GitLab 서버와 통신이 가능하다.
    1. 등록 : Runner 설치 후, GitLab 서버의 URL과 등록 토큰을 이용해 서버에 등록한다.
    2. 폴링 : Runner 주기적으로(기본 3초) GitLab 서버 API에 POST /api/v4/jobs/request 요청을 보낸다.
    3. 할당 : GitLab 서버에 대기 중인 파이프라인 작업이 있다면, 서버는 해당 작업의 정보를 암호화하여 Runner에게 응답으로 보낸다.
    4. 실행 : Runner는 설정된 Executor를 구동한다. .gitlab-ci.yml에 정의된 명령어들을 순차적으로 실행한다.
    5. 보고 : 실행 중에 발생하는 로그를 실시간으로 서버에 전송한다.
      • 작업 성공/실패 여부를 최종적으로 서버에 통보한다.
    6. 아티팩트 업로드 : 빌드 결과물이 있다면 이를 압축하여 GitLab 서버로 전송한다.
    7. 종료 : Docker나 K8s를 사용했다면, 실행했던 컨테이너나 파드를 삭제하여 자원을 회수한다.

  • Group Runner 설정
  1. 원하는 그룹 선택 - 왼쪽 사이드바 메뉴 - Build - Runners - Create group runner
  2. Group Runner 생성 후 토큰 복사
  3. 러너 컨테이너 실행
docker run -d --name gitlab-runner --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  gitlab/gitlab-runner:latest
  1. 등록 명령어 실행
docker exec -it gitlab-runner gitlab-runner register


5. .gitlab-ci.yml 작성

stages:
    - build
    - test

build-job:
  stage: build
  script:
      - echo "Starting build..."
      - mkdir build_output
      - echo "build outputs..." > build_output/result.txt
  artifacts:
      paths:
          - build_output/
test-job:
    stage: test
    script:
        - echo "String test..."
        - grep "build outputs" build_output/result.txt
        - echo "Success Test!"

GitLab CI/CD

  • 파이프라인 : 코드가 저장소에 푸시되면, 미리 정의된 순서대로 작업이 진행되는 과정 전체를 의미한다.
  • .gitlab-ci.yml 파일이 존재하기만 하면 모든 Push 이벤트에 대해 실행하는 것이 기본 설정
    • Job 레벨 : rules를 써서 특정 작업만 실행/스킵
    • 전체 레벨 : workflow: rules를 써서 파이프라인 생성 자체를 제어
    workflow: # 파일의 최상단
     rules:
       - if: $CI_COMMIT_BRANCH == "main"
      
     rules:
     - if: $CI_COMMIT_BRANCH == "main"
       when: always
  • GitLab의 기본 규칙
    • Stage 간에는 순차 실행
    • 같은 Stage 안의 Job들은 병렬 실행
  • Github Action의 steps는 Gitlab의 script
    • 리스트 형태로 작성하며, 위에서 아래로 한 줄씩 차례대로 실행된다.
      [Stage: build]        [Stage: test]        [Stage: deploy]
      +-----------+         +-----------+        +-------------+
      |  Job A    | ------> |   Job C   | -----> |    Job E    |
      +-----------+  (대기) +-----------+   (대기  +-------------+
      |  Job B    |         |   Job D   |
      +-----------+         +-----------+
      (A, B 동시 실행)      (C, D 동시 실행)
  • needs 키워드 : 스테이지 순서를 무시하고 needs에 적힌 잡이 끝나면 바로 시작
같은 stage인 build_a 와 build_b는 동시에 실행된다. 
- 만약 needs가 없었다면 : test 잡은 build_a와 build_b가 모두 종료되어야 실행된다.
  (마찬가지로 test_a와 test_b 동시에 시작)
- 하지만 needs가 있기 때문에 : build b가 끝나지 않았어도 build_a가 끝났다면
  test_a, deploy_a가 실행될 수 있다.

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

  • 자주 쓰이는 시스템 변수 (Predefined Variables)

    # 커밋 해시값의 앞 8자리. 버전 태그로 가장 많이 씀.	
    # 1a2b3c4d
    CI_COMMIT_SHORT_SHA
    
    # 현재 빌드 중인 브랜치 이름 또는 태그 이름.
    # main, develop
    CI_COMMIT_REF_NAME
    
    # 파이프라인이 왜 실행됐는지 (푸시, 웹 클릭, 스케줄 등).	
    # push, web, schedule
    CI_PIPELINE_SOURCE
    
    # 이 프로젝트 전용 도커 이미지 저장소 주소.
    # registry.gitlab.com/group/project
    CI_REGISTRY_IMAGE
    
    # 레지스트리에 로그인하기 위한 일회용 ID.	
    # gitlab-ci-token
    CI_REGISTRY_USER
    
    # 레지스트리에 로그인하기 위한 일회용 패스워드.	
    # (자동 생성된 토큰)
    CI_REGISTRY_PASSWORD	

stages:
  - test
  - package
  - deploy

# 전역 변수 설정 
variables:
  # 생성될 이미지의 풀 네임 (예: registry.gitlab.com/my-group/my-project:1a2b3c4d)
  DOCKER_IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  DOCKER_IMAGE_LATEST: $CI_REGISTRY_IMAGE:latest


unit_test_job:
  stage: test
  image: python:3.9-slim  # 테스트를 수행할 환경(이미지)
  script:
    - echo "테스트를 시작합니다..."
    - python --version
    - echo "테스트 통과!" 
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: always


build_push_docker_job:
  stage: package
  image: docker:24.0.5
  services:
    - docker:24.0.5-dind  # Docker-in-Docker: 컨테이너 안에서 도커를 실행하기 위한 서비스
  
  # 변수: DIND 사용 시 TLS 인증 끄기 (설정 간소화)
  variables:
    DOCKER_TLS_CERTDIR: ""
    
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
    
  script:
    - echo " 도커 이미지를 빌드합니다..."
    - docker build -t $DOCKER_IMAGE_TAG -t $DOCKER_IMAGE_LATEST .
    
    - echo " GitLab 레지스트리로 푸시합니다..."
    - docker push $DOCKER_IMAGE_TAG
    - docker push $DOCKER_IMAGE_LATEST
    
  after_script:
    - docker logout


deploy_prod_job:
  stage: deploy
  image: alpine:latest
  # environment: GitLab UI의 'Environments' 메뉴에서 배포 이력을 볼 수 있게 해줌
  environment:
    name: production
    url: http://10.10.10.3
  
  script:
    - echo "운영 서버(Production)에 배포를 시작합니다..."
    - echo "배포할 이미지 $DOCKER_IMAGE_TAG"
    - echo "SSH 접속 및 컨테이너 교체 명령 실행 중..."
    - echo "배포 완료!"
  
  # 수동 배포 설정 (실수로 배포되는 것 방지)
  when: manual

GitLab으로 ECR에 이미지 업로드

  • 간단한 Django 프로젝트 준비

  • Dockerfile

    FROM python:3.9-slim
    
     WORKDIR /app
    
     COPY requirements.txt .
    
     RUN pip install --no-cache-dir -r requirements.txt
    
     COPY . .
    
     RUN python manage.py makemigrations && python manage.py migrate
    
     EXPOSE 8000
    
     CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
  • 프로젝트 - Settings - CI/CD - Variables 등록

  • gitlab-ci.yml

    stages:
     - build-push
    
    variables:
      DOCKER_TLS_CERTDIR: ""
      IMAGE_TAG: $CI_COMMIT_SHORT_SHA
    
    build_and_push_to_ecr:
      stage: build-push
    
      image: docker:latest
    
      before_script:
        - echo "AWS CLI 설치 및 ECR 로그인을 준비합니다..."
    
        - apk add --no-cache aws-cli
      
        - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $ECR_DOMAIN
    
      script:
        - echo "Django 이미지를 빌드합니다..."
       - docker build -t $ECR_REGISTRY_URL:$IMAGE_TAG -t $ECR_REGISTRY_URL:latest .
        - echo "AWS ECR로 이미지를 푸시합니다..."
      
        - docker push $ECR_REGISTRY_URL:$IMAGE_TAG
        - docker push $ECR_REGISTRY_URL:latest
      
        - echo "배포(푸시) 완료!"
  • ECR에 이미지 배포 완료

    aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $ECR_DOMAIN


    [ AWS_ACCESS_KEY_IDSECRET_KEY 가 로드되고 사용되는 시점 ]

    • 이 두 값은 명령어 라인에는 직접 적혀있지 않지만, GitLab CI 설정에서 등록했기 때문에 리눅스 환경 변수 영역에 존재하고 있다.
    • 로드 시점
      • aws ecr get-login-password 명령어가 실행되면, AWS CLI 프로그램이 메모리에 로드된다.
      • 이 프로그램은 실행되자마자 내부적으로 자격 증명 공급자 체인 로직을 수행한다.
      • 가장 먼저 현재 쉘의 환경 변수를 스캔한다. 여기서 AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY 값을 찾아내어 메모리로 읽어 들인다.
    • 사용 시점
      - AWS CLI는 ECR 서비스에 임시 인증 토큰을 발급해달라는 API 요청을 생성한다.
      - 이때 메모리에 로드한 Secrey Key를 사용하여 이 API 요청 패킷에 전자 서명(SigV4 Signing)을 한다.
      - 서명된 요청을 AWS ECR 서버로 전송한다. AWS 서버는 서명을 검증하여 이 요청이 유효한 사용자가 보낸 것임을 확인한다.
      | 를 통해 AWS CLI가 표준 출력으로 뱉어낸 인증 토큰을 Docker CLI의 표준 입력으로 전달
      [ Docker 로그인 과정 ]
    • Docker CLI 실행
      • docker login 명령어가 실행된다.
      • --username AWS : ID는 무조건 AWS라는 고정된 문자열을 사용한다. (ECR의 규칙)
      • --password-stdin : 비밀번호는 키보드로 치지 않고, 파이프를 통해 들어오는 표준 입력(stdin)에서 읽겠다는 옵션
      • $ECR_DOMAIN : 인증할 서버 주소
    • 인증 처리
      • Docker 클라이언트는 전달받은 비밀번호와 ID를 가지고 $ECR_DOMAIN 서버에 HTTPS 요청을 보낸다.
      • ECR 서버는 토큰을 검증하고, 유효하다면 로그인 성공 응답을 보낸다.
    • 결과 저장
      • 로그인이 성공하면 Docker는 로컬 파일 시스템(~/.docker/config.json)에 이 도메인에 접근할 때는 이 토큰을 사용하라는 정보를 저장한다.
      • 이후 docker push 명령어가 실행될 때, Docker는 이 config.json 파일을 참조하여 저장된 토큰을 헤더에 실어 이미지를 업로드한다.

GitLab Template

  • GitLab CI/CD 템플릿은 중복되는 코드를 줄이고 파이프라인 구성을 표준화하기 위해 사용하는 기능으로 GitLab에서 템플릿을 사용하는 방식은 크게 3가지가 있다.
  • GitLab 제공 공식 템플릿 참조
    • GitLab이 사전에 정의해 둔 보안 스캔, 언어별 빌드, 배포 템플릿을 가져와 사용하는 방식
    • 별도의 파일 생성 없이 이름만으로 호출 가능
    • include:
        - template: Auto-DevOps.gitlab-ci.yml
        - template: Security/SAST.gitlab-ci.yml
  • 외부 프로젝트의 템플릿 참조
    • 회사 내 별도의 프로젝트에 .yml 파일을 만들어두고, 여러 서비스 프로젝트에서 이를 가져와 사용하는 방식
    • 전사 표준을 강제하거나 중앙에서 CI/CD 로직을 관리할 때 사용
    • include:
        - project: 'my-comnay/devops/ci-templates'
          ref: main
          file: 'build/docker-build.yml'
  • .gitlab-ci.yml 내부 직접 정의
    • 파일 내부에서만 재사용할 로직을 정의
    • Hidden Job (.으로 시작) : .templatess 처럼 Job 이름 앞에 .을 붙이면 파이프라인에서 실제로 실행되지 않는다. 오직 참조용으로만 존재한다.
    • Anchor( & )와 Alias( * )
      • &이름 : 이 코드 블록을 '이름'으로 저장하겠다는 의미
      • *이름 : 저장된 '이름'의 코드 블록을 여기에 그대로 복사해 넣겠다는 의미
      • <<: : 저장된 블록의 키-값 쌍을 현재 위치에 병합

  • SLACK 메시지 전송 템플릿
    • 프로젝트 - Settings - CI/CD - Variables - Slack Webhook URL 등록
  • .gitlab-ci.yml
# 템플릿
.slack_notification_template: &slack_notification
  - |
    (apk add --no-cache curl || (apt-get update && apt-get install -y curl)) 2>&1 >/dev/null || true
    
    # curl 설치 확인 
    echo "Curl version: $(curl --version | head -n 1)"
    
    # 현재 작업 상태에 따라 메시지 색상과 아이콘 결정
    if [ "$CI_JOB_STATUS"  == "success" ]; then
      COLOR="#366a64"
      ICON="✅"
      STATUS_MSG="성공"
    else
      COLOR="#ff0000"
      ICON="❌"
      STATUS_MSG="실패"
    fi

    # Slack으로 보낼 JSON 데이터 구성
    PAYLOAD=$(cat <<EOF
    {
      "attachments": [
        {
          "color": "$COLOR",
          "title": "$ICON 빌드 알림 : $CI_PROJECT_NAME",
          "title_link": "$CI_PIPELINE_URL",
          "text": "작업: *$CI_JOB_NAME*\n상태: *$STATUS_MSG*\n요청자: $GITLAB_USER_NAME",
          "mrkdwn_in": ["text"]
        }
      ]
    }
    EOF
    )

    # webhook 전송
    curl -X POST -H 'Content-type: application/json' --data "$PAYLOAD" "$SLACK_WEBHOOK_URL"



# 실제 빌드 작업 정의
build_job:
  stage: build
  image: alpine:latest
  script:
    - echo "Starting build..."
    - sleep 2
    - echo "Success build"
  after_script: *slack_notification  # 템플릿 사용

deploy_job:
  stage: deploy
  image: alpine:latest
  script:
    - echo "Starting deploy"
    - exit 1 # 강제 실패
  after_script: *slack_notification

Template 매개변수화 / include / Template Lint

  • Template 매개변수화 (Variable Overriding)
    • 템플릿에 기본값을 적어두고, 실제 Job에서 같은 변수명을 다시 선언하면 실제 Job의 값이 적용된다.
.templates:
  .deploy_templates: &deploy_template
    image: alpine:latest
    variables: # 기본값
      DEPLOY_ENV: "staging"
      SERVER_IP: "10.10.10.10"
    script:
      - echo "배포 시작. 환경=$DEPLOY_ENV"
      - echo "대상 서버 $SERVER_IP로 접속 중..."
      - echo "배포 스크립트 실행 완료"


deploy_dev:
  stage: deploy
  <<: *deploy_template  # 템플릿 내용을 여기세 복사
  variables:  # 템플릿의 변수 덮어쓰기
    DEPLOY_ENV: "deployment"
    SERVER_IP: "10.10.10.3"

deploy_prod:
  stage: deploy
  <<: *deploy_template
  variables:
    DEPLOY_ENV: "production"
    SERVER_IP: "192.168.10.100"
  when: manual

  • Condition 분기 및 include 전략 (환경별 파일 분리)

    • .gitlab-ci.yml 파일 하나에 모든 코드를 다 넣으면 관리가 힘들어진다. 이때 include: rules를 사용하면, 특정 브랜치일 때 특정 설정 파일만 가져오는 식으로 필요한 파일만 가져와서 사용할 수 있다.
    • 예시) 브랜치에 따라 다른 파일 로딩
      • 파일 구조는 아래와 같다고 가정한다
        • .gitlabci.yml (메인)
        • ci/common.yml (빌드, 테스트 공동 작업)
        • ci/dev-deploy.yml (개발 배포 설정)
        • ci/prod-deploy.yml (운영 배포 설정)
    stages:
      - build
      - test
      - deploy
      
    include:
      - local: '/ci/common.yml'
      
      - local: '/ci/dev-deploy.yml'
        rules:
          - if: '$CI_COMMIT_BRANCH == "develop"'
          
      - local: '/ci/prod-deploy.yml'
        rules:
          - if: '$CI_COMMIT_BRANCH == "main"'
          
          
    develop 브랜치에 푸시하면 : common.yml + dev-deploy.yml 내용만 실행됨. (운영 배포 실수 방지)
    
    main 브랜치에 푸시하면 : common.yml + prod-deploy.yml 내용만 실행됨.        

  • Template Lint 및 시각화
    • CI Lint : 복잡하게 템플릿을 쪼개고 include를 쓰다 보면, 최종적으로 합쳐진 코드가 어떻게 생긴 건지 헷갈릴 때 사용할 수 있는 기능.
    • GitLab 프로젝트 - Build - Pipeline editor - 상단 탭의 Validate
    • 문법이 틀렸는지 검사
    • include로 가져온 파일들과 <<: *anchor로 복사된 내용들이 전부 하나로 합쳐진 최종 결과를 보여준다.
    • API를 사용한 Lint 자동화
      • curl --header "PRIVATE-TOKEN: glpat-내토큰값..." \
              --data "{\"content\": \"$(cat .gitlab-ci.yml | sed 's/"/\\"/g')\"}" \
              "https://gitlab.example.com/api/v4/ci/lint"

Reference : https://somaz.tistory.com/322

0개의 댓글