1. 개요
최근 Github Action 포스팅 이후, 이번에는 GitLab CI/CD를 간단하게나마 사용해볼 기회가 생겨 정리글을 남기게 되었다. 이번 포스팅에서는 GitLab CI/CD의 기본적인 사용 방법을 간단히 소개하고, 실습을 통해 CI/CD 워크플로우 파일을 작성하고 실행하는 과정을 다뤄보겠다.
2. GitLab CICD 란
GitLab CI/CD는 GitLab에서 제공하는 강력한 DevOps 도구로, 프로젝트 내에서 코드 변경 사항을 자동으로 테스트, 빌드, 배포할 수 있도록 지원한다. GitLab CI/CD는 GitLab과 통합되어 동작하기 때문에, GitLab 리포지토리와 직접 연결되어 프로젝트 관리와 배포 프로세스를 단순화한다. 또한 Github Actions와 다르게 파이프라인을 작성하고 실행하는 데 필요한 설정은 .gitlab-ci.yml 파일에 정의되어 자동화된 작업을 수행한다.

주요 컴포넌트는 다음과 같다.
Pipeline
- 파이프라인은 CI/CD 작업의 전체 프로세스를 정의하며, .gitlab-ci.yml 파일에서 stages 키워드로 선언
Stage:
- Stage는 파이프라인 내에서 그룹화된 작업(Job)의 집합
Job:
- 각 Job은 자신의 Stage에 속하며, 특정 작업(Script)을 실행
Script:
• 각 Job의 script 필드에 명령어 스크립트를 정의
Runner:
• 모든 Job은 Runner에서 실행되고 사용자가 설정한 Runner가 필요

3. GitLab CICD 주요기능
GItLab CI/CD에서 사용하는 주요 기능에 대해서 간단히 알아보자 .
CI 환경변수 활용
1. 사용자 정의 환경 변수
사용자 정의 환경 변수는 프로젝트별로 설정할 수 있고, 코드에 민감한 정보를 직접 노출하지 않고도 필요한 값을 파이프라인에서 사용할 수 있다. GitLab UI → Settings → CI/CD → Variables
메뉴를 통해 CICD에서 사용할 아래 변수를 생성해보자.
• HARBOR_USERNAME: Docker Hub 사용자 이름
• HARBOR_PASSWORD: Docker Hub 비밀번호
• HARBOR_URL: Docker Hub URL

2. GitLab에서 제공하는 환경변수
GitLab CI/CD는 사용자가 정의한 변수 외에도, 기본적으로 제공되는 환경 변수를 활용할 수 있다. 이 환경 변수들은 파이프라인의 동작과 GitLab의 통합된 정보를 동적으로 제공하여 파이프라인을 구성에 활용할 수 있다. 예를들어, Git의 커밋 정보, 브랜치, 태그, 프로젝트 정보 등을 쉽게 참조할 수 있어, 동적인 파이프라인 구성에 유용하다.
CI 변수 예시는 다음과 같으며 CI_<변수명>
이라는 prefix 접두사가 붙는다는게 특징이다.
• CI_PROJECT_NAME: 현재 프로젝트 이름.
• CI_COMMIT_SHA: 현재 커밋의 SHA 값.
• CI_PIPELINE_ID: 현재 파이프라인의 고유 ID.
• CI_JOB_NAME: 현재 실행 중인 Job 이름.
아래 스크립트를 통해서 사용하는 변수를 확인할 수 있다.
# gitlab-ci.yaml
...
job_name:
script:
- export
...
# 결과
export ARGOCD_SERVER_SERVICE_HOST='10.233.37.136'
export ARGOCD_SERVER_SERVICE_PORT='80'
export ARGOCD_SERVER_SERVICE_PORT_HTTP='80'
export ARGOCD_SERVER_SERVICE_PORT_HTTPS='443'
export CI='true'
export CI_API_GRAPHQL_URL='http://gitlab.dev.com/api/graphql'
export CI_API_V4_URL='http://gitlab.dev.com/api/v4'
export CI_BUILDS_DIR='/builds'
export CI_COMMIT_AUTHOR='장성필 <sp.jang@okestro.com>'
export CI_COMMIT_BEFORE_SHA='c467ed0f562a9115f3157e6ea20b6467a6688fc5'
3. 쿠버네티스 환경 변수 활용
쿠버네티스 환경을 사용한다면, 서비스 디스커버리 변수를 활용하여 CI/CD 작업의 자동화 수준을 크게 높일 수 있다. 쿠버네티스 서비스 디스커버리에 의해 같은 네임스페이스 내의 서비스 정보가 자동으로 모든 파드에 주입된다. 예를들어 GitLab과 같은 네임스페이스에 ArgoCD 파드가 존재한다고 가정하면 파이프라인에서 $ARGOCD_SERVER_HOST
환경변수를 참조 사용할 수 있다

조건문 활용
특정 이벤트나 조건에 해당하는 경우에만 파이프라인을 실행하도록하는 조건문을 활용할 수 있다.
Dockerfile이 존재할때만 빌드
...
# Run this job in a branch where a Dockerfile exists
rules:
- if: $CI_COMMIT_BRANCH
exists:
- Dockerfile
브랜치 제약
- main 브랜치에서만 실행
...
only:
- main
tags:
- runner
GitLab Template
GitHub Actions가 마켓플레이스를 통해 강력한 플러그인을 제공한다면, GitLab은 다양한 CI/CD 템플릿을 기본으로 제공한다. GitLab의 템플릿은 자주 사용되는 워크플로우를 빠르게 설정하고, 파이프라인을 간소화하는 데 유용하다.
GitLab CI/CD는 .gitlab-ci.yml 단일 파일로 파이프라인을 구성하지만, 템플릿을 활용하면 이를 더 구조화하고 재사용 가능하게 만들 수 있다. include 키워드를 사용해 GitLab이 제공하는 템플릿이나 외부 파일을 손쉽게 가져올 수 있습니다.
다양한 환경에서 파일을 가져올 수 있도록 지원한다.
include:
- local: 'templates/base.yml' # 같은 프로젝트의 파일
- project: 'group/project-name' # 다른 프로젝트에서 가져오기
file: '/templates/base.yml'
- remote: 'https://example.com/base.yml' # URL에서 가져오기
- template: 'Node.js.gitlab-ci.yml' # GitLab의 제공 템플릿
다음은 Node.js.gitlab-ci.yaml 템플릿을 사용 예시이다.
include:
- template: 'Node.js.gitlab-ci.yml'
test-job:
stage: test
script:
- echo "Running additional custom tests..."
Node.js.gitlab-ci.yml
파일 내용은 기본적인 Node.js 애플리케이션의 빌드 및 테스트 과정을 정의하고 있다.
# Node.js.gitlab-ci.yml
image: node:latest
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: https://docs.gitlab.com/ee/ci/services/index.html
services:
- mysql:latest
- redis:latest
- postgres:latest
# This folder is cached between builds
# https://docs.gitlab.com/ee/ci/yaml/index.html#cache
cache:
paths:
- node_modules/
test_async:
script:
- npm install
- node ./specs/start.js ./specs/async.spec.js
test_db:
script:
- npm install
- node ./specs/start.js ./specs/db-postgres.spec.js
deploy:
stage: deploy
script: echo "Define your deployment script!"
environment: production
이처럼 CI 템플릿 기능을 사용하면 재사용성이나 유지보수가 용이하고 표준화된 일관된 CICD 설정을 가져갈 수 있다. 또한 GitLab이 제공하는 공식 템플릿 외에도, 사용자 정의 템플릿을 만들어 필요에 따라 확장하거나 커스터마이징할 수 있다.
Node,Java,Go,Docker,Kubernetes 등 아래 링크를 통해 GitLab이 제공하는 다양한 CI 템플릿을 확인하고, 프로젝트에 적합한 템플릿을 활용해보자.
https://gitlab.com/gitlab-org/gitlab-foss/-/tree/master/lib/gitlab/ci/templates
4. GitLab Runner란?
GitLab Runner는 GitHub Actions의 Self-hosted Runner와 유사한 개념으로, GitLab CI/CD 파이프라인에서 정의된 작업(Job)을 실행하기 위한 에이전트 역할을 한다. GitHub Actions는 기본적으로 GitHub 호스팅 Runner를 제공하지만, GitLab은 기본 Runner를 제공하지 않기 때문에 사용자가 직접 GitLab Runner를 설치하고 구성해야 한다.
GitLab Runner를 설치하고 구성하는 방법을 알아보겠습니다. 이 예제에서는 Kubernetes 환경에서 Runner를 구성하는 과정을 다룬다.
사전준비
GitLab Runner를 설치하고 실행하기 전에 다음 환경이 준비되어 있어야 한다.
- 쿠버네티스 환경
- Kubernetes 클러스터가 이미 구축되어 있어야 한다.
- GitLab 구성
- GitLab 서버가 설치되어 있어야 한다.
- 본 예제에서는 GitLab 16.9.0 버전을 기준으로 진행
GitLab Runner 생성
GitLab Runner를 설치하기 위해서는 먼저 GitLab UI에서 Runner를 생성하고, 필요한 Runner 토큰을 발급받아야 한다.. 발급된 토큰은 Runner를 GitLab과 연결하는 데 사용된다.
Admin Area > Runners > New
메뉴에 접속하여 Runner를 생성한다. Runner가 설치될 호스트의 플랫폼에 맞게 선택하고 runner를 호출할 tag를 지정한다. 나의 경우 Linux 환경에서 러너를 설치하고 runner라는 tag를 지정하였다. 태그는 .gitlab-ci.yml
파일 내에서 특정 Job이 어떤 Runner에서 실행될지 지정하는 데 사용된다.

runner를 생성하게 되면 아래와 같이 Runner를 설치할 스크립트와 토큰 정보가 출력된다. 이번 포스팅에서는 GitLab UI에서 제공된 스크립트를 사용하지 않고, Helm Chart를 통해 Runner를 설치할 예정이다. 따라서 출력된 등록 토큰만 저장해 두고, 나머지 스크립트는 사용하지 않는다.

아직 Runner가 설치 및 등록되지 않았으므로, 상태가 연결되지 않음(Not Connected)으로 표시된다.

Gitlab Ruuner 설치
GitLab Runner를 설치할 때, GitLab 서버의 버전과 호환되는 Runner 버전을 사용하는 것이 중요하다. GitLab 서버와 동일한 GitLab 16.9.0 버전의 runner를 설치한다. helm pull 명령어를 사용해 GitLab Runner의 Helm Chart를 로컬로 가져온다.
• --untar 옵션을 사용하여 Chart를 압축 해제합니다.
helm repo add gitlab https://charts.gitlab.io
helm repo update
helm search repo -l gitlab/gitlab-runner | grep 16.9
gitlab/gitlab-runner 0.62.2 16.9.2 GitLab Runner
gitlab/gitlab-runner 0.62.1 16.9.1 GitLab Runner
gitlab/gitlab-runner 0.62.0 16.9.0 GitLab Runner
root@trb-dev-master-3:~/spjang/gitlab-runner# helm pull gitlab/gitlab-runner --version=0.62.0 --untar
override할 values 파일을 생성하고 아래 내용을 작성하여 배포한다.
gitlabUrl
: 연결할 깃랩 URL을 입력runnerToken
: 깃랩에서 발급한 runner 토큰을 입력
# custom values 작성
cat << EOF > runner-values.yaml
# runner-values.yaml
gitlabUrl: http://gitlab.dev.com/ # GitLab Url 넣기 !
runnerToken: "glrt-nyTDFzhGDwySY_QxWogs"
rbac:
create: true
EOF
# 배포
helm install gitlab-runner . -f runner-values.yaml -n trb-oss
# 업그레이드
helm upgrade gitlab-runner . -f runner-values.yaml -n trb-oss
# 파드 확인
kubectl get pod -n trb-oss | grep runner
gitlab-runner-778b75dfbb-dmh7g 1/1 Running
GitLab URL과 등록 토큰이 올바르게 설정되었다면, GitLab Runner는 Online 상태로 표시되며, CI/CD 파이프라인 작업을 실행할 준비가 완료되었다.

5. GitLab 파이프라인 구성하기
이제 GitLab CI/CD에서 사용할 파이프라인을 작성하고, 워크플로우를 실행해보자.
GitLab CI 파일 작성
이제 빌드할 소스 레포지토리를 클론받아 Docker 컨테이너 이미지를 빌드하고 배포하는 간단한 GitOps 파이프라인을 작성해보자.

Job 1 : git clone(Present)
빌드할 소스 레포지토리를 Clone 한다.
- bitnami/git:latest
- Git 명령어를 실행하기 위햐 git 명령어가 설치된 경량 컨테이너 이미지를 사용
- paths:
- 클론된 리포지토리(test-gitlab-runner-repo/)를 아티팩트로 저장.
- 아티팩트는 다음 단계(Job)에서 사용하거나 다운로드 가능.
- expire_in:
- 아티팩트의 유효 기간은 1시간.
- 이 시간이 지나면 저장된 아티팩트가 삭제됩니다.
git_clone:
stage: preset
image:
name: bitnami/git:latest
script:
- git clone http://gitlab-runner-credential:<GITLAB_TOKEN>@gitlab.dev.trb.com/system/test-gitlab-runner-repo.git --branch main
- ls -lh
artifacts:
paths:
- test-gitlab-runner-repo/
expire_in: 1 hour
tags:
- runner
Job 2 : docker(build)
- docker dind 방식을 사용하기 때문에, 실행 호스트의 Docker 데몬이 필요.
- 테스트 환경으로
Insecure
설정으로 레지스트리 간 HTTP 통신
stages:
- build
docker-build:
# Use the official docker image.
image: docker:cli
needs: ["clone_repo"]
stage: build
services:
- docker:dind
variables:
DOCKER_IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
before_script:
- docker images
- docker ps -a
- mkdir -p /etc/docker
- echo "{\"insecure-registries\":[\"$HARBOR_URL\"]}" > /etc/docker/daemon.json
- docker login -u "$HARBOR_USERNAME" -p "$HARBOR_PASSWORD" $HARBOR_URL
# All branches are tagged with $DOCKER_IMAGE_NAME (defaults to commit ref slug)
# Default branch is also tagged with `latest`
script:
- docker build --pull -t "$DOCKER_IMAGE_NAME" .
- docker push "$DOCKER_IMAGE_NAME"
- |
if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
docker tag "$DOCKER_IMAGE_NAME" "$CI_REGISTRY_IMAGE:latest"
docker push "$CI_REGISTRY_IMAGE:latest"
fi
tags:
- runner
Job 2-2 : Kaniko(build)
- DinD 방식은 호스트의 영향을 주기 때문에 Kaniko 사용을 추천.
before_script
를 활용하여 이미지 레지스트리 인증을 먼저 진행한다.- 테스트 환경이므로,
--insecure
옵션으로 레지스트리 HTTP 통신 - ci 파일 작성 시,
" "
안에"
는 앞에\
로 처리해줘야 함- 띄어쓰기 및 특수문자 주의
stages:
- build
image_build:
stage: build
needs: ["clone_repo"]
before_script:
# Setting to Kaniko
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$HARBOR_URL\":{\"username\":\"$HARBOR_USERNAME\",\"password\":\"$HARBOR_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cat /kaniko/.docker/config.json
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
# artifacts:
# paths:
# - output/
script:
- export
- echo "Building the app"
- /kaniko/executor --context dir://$CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $HARBOR_URL/library/gitlab-ci-test:$CI_COMMIT_SHORT_SHA --insecure
tags:
- runner
# Run this job in a branch where a Dockerfile exists
# rules:
# - if: $CI_COMMIT_BRANCH
# exists:
# - Dockerfile
Job 3 : ArgoCD(Deploy)
ArgoCD의 레포지토리의 애플리케이션을 미리 생성하자.
cat << EOF | kubectl apply -f -n argocd
# 레포지토리 생성
apiVersion: v1
kind: Secret
metadata:
name: runner-manifest-repo
namespace: trb-oss
labels:
argocd.argoproj.io/secret-type: repository
type: Opaque
data:
# Base64로 인코딩된 값
url: aHR0cDovL2dpdGxhYi5kZXYudHJiLmNvbS9zeXN0ZW0vdGVzdC1hcmdvY2QtbWFuaWZlc3QtcmVwby5naXQ=
username: cm9vdA==
password: Y2xvdWQxMjM0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: runner-deployment
labels:
app: runner
spec:
replicas: 1
selector:
matchLabels:
app: runner
template:
metadata:
labels:
app: runner
spec:
containers:
- name: runner-test
image: harbor.dev.trb.com/library/runner-test:87a9a810
ports:
- containerPort: 80
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitlab-runner-test
namespace: trb-oss
spec:
destination:
namespace: default
server: https://kubernetes.default.svc
project: default
source:
path: deploy/
repoURL: http://gitlab.dev.trb.com/system/test-argocd-manifest-repo.git
targetRevision: main
EOF
Stage 작성
- ArgoCD 애플리케이션에 연결되어 있는 메니페스트 레포지토리를 Clone 받는다.
CI_COMMIT_SHORT_SHA
라는 짧은 커밋 해쉬 값의 CI 변수를 활용하여 yq명령어를 이용해 태그 수정
#variables:
# CI_DEBUG_TRACE: "true"
stages:
- deploy
deploy_argocd:
stage: deploy
image:
name: alpine:latest
before_script:
- apk add --no-cache git curl jq yq
script:
- git clone http://runner-manifest-repo-credential:glpat-fdnJ5dRAwysCJ9AfFojY@gitlab.dev.trb.com/system/test-argocd-manifest-repo.git --branch main
- cd test-argocd-manifest-repo
- pwd && ls -al
# - yq -i ".image.tag = \"$CI_COMMIT_SHORT_SHA\"" ./grpc-helm/$CI_PROJECT_NAME/values.yaml
- yq e ".spec.template.spec.containers[0].image = \"$HARBOR_URL/library/runner-test:$CI_COMMIT_SHORT_SHA\"" -i deploy/deployment.yaml
- git config --global user.email "devops@gmail.com"
- git config --global user.name "devops"
- git status
- git add -A
- >
git commit -m "UPDATE :: $CI_PROJECT_NAME - runner test "
#- git commit -m *commit_message
- git push origin main
only:
- main
tags:
- runner
전체 파이프라인 스크립트는 다음과 같다.
#variables:
# CI_DEBUG_TRACE: "true"
stages:
- build
- deploy
image_build:
stage: build
# needs: ["clone_repo"]
before_script:
# Setting to Kaniko
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$HARBOR_URL\":{\"username\":\"$HARBOR_USERNAME\",\"password\":\"$HARBOR_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cat /kaniko/.docker/config.json
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
# artifacts:
# paths:
# - output/
script:
- export
- echo "Building the app"
- /kaniko/executor --context dir://$CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $HARBOR_URL/library/runner-test:$CI_COMMIT_SHORT_SHA --insecure
tags:
- runner
# Run this job in a branch where a Dockerfile exists
# rules:
# - if: $CI_COMMIT_BRANCH
# exists:
# - Dockerfile
deploy_argocd:
stage: deploy
image:
name: alpine:latest
before_script:
- apk add --no-cache git curl jq yq
script:
- git clone http://runner-manifest-repo-credential:glpat-fdnJ5dRAwysCJ9AfFojY@gitlab.dev.trb.com/system/test-argocd-manifest-repo.git --branch main
- cd test-argocd-manifest-repo
- pwd && ls -al
# - yq -i ".image.tag = \"$CI_COMMIT_SHORT_SHA\"" ./grpc-helm/$CI_PROJECT_NAME/values.yaml
- yq e ".spec.template.spec.containers[0].image = \"$HARBOR_URL/library/runner-test:$CI_COMMIT_SHORT_SHA\"" -i deploy/deployment.yaml
- git config --global user.email "devops@gmail.com"
- git config --global user.name "devops"
- git status
- git add -A
- >
git commit -m "UPDATE :: $CI_PROJECT_NAME - runner test "
#- git commit -m *commit_message
- git push origin main
only:
- main
tags:
- runner
파이프라인 실행 및 확인
Repository > Build > Pipeline
메뉴에 접속하여 파이프라인을 목록을 확인한다. 해당 레포지토리에 푸시가 발생하면 파이프라인이 실행되고 결과를 확인할 수 있다.
파이프라인 목록

파이프라인 상세 정보

파이프라인 > 특정 Job 확인

이미지 레지스트리 확인
image_build 스테이지에서 이미지를 빌드하고 레지스트리로 푸시가 정상적으로 되었음을 확인할 수 있다.

메니페스트 저장소 확인
deploy 스테이지에서 메니페스트 저장소에 커밋 해쉬값이 태그로 잘 변경됨을 확인할 수 있다.

ArgoCD 확인
ArgoCD에서도 애플리케이션이 잘 배포되었음을 확인할 수 있다.
6. 결론
GitLab CI/CD를 사용해보며 느낀 점은 젠킨스와 비교하였을때, 문법이 간결하고 직관적이어서(병렬수행도 손쉽게) YAML 파일로 CI/CD 워크플로우를 쉽게 구성할 수 있었다. GitLab 레포지토리와 통합된 환경(변수,UI 등)을 제공하기 때문에 편리하였고 활용할 수 있는 부분들이 많았다. 간단한 GitLab CI/CD 기능만 다루어보았는데 향후에는 멀티 프로젝트 파이프라인, 동적 환경 설정 등 엔터프라이즈 환경에서의 고급 기능을 활용해 더 정교한 CI/CD 워크플로우를 구성해보자.
'CICD' 카테고리의 다른 글
GoCD 설치 및 기본 사용법 정리 (Feat. Kubernetes) (0) | 2025.04.04 |
---|---|
README.md만 수정했는데 ArgoCD가 파드를 재배포해요… 이거 진짜에요?(Diffing Customization) (0) | 2025.03.29 |
ArgoCD Autopilot: ArgoCD 및 GitOps 환경 자동 구축하기 (0) | 2024.12.19 |
Github Actions 기본 사용 방법 및 CI/CD 워크플로우 구성하기 (2) | 2024.12.14 |
jib를 활용하여 젠킨스 파이프라인 구성하기(GitOps + SpringBoot + Gradle ) (2) | 2024.12.08 |
1. 개요
최근 Github Action 포스팅 이후, 이번에는 GitLab CI/CD를 간단하게나마 사용해볼 기회가 생겨 정리글을 남기게 되었다. 이번 포스팅에서는 GitLab CI/CD의 기본적인 사용 방법을 간단히 소개하고, 실습을 통해 CI/CD 워크플로우 파일을 작성하고 실행하는 과정을 다뤄보겠다.
2. GitLab CICD 란
GitLab CI/CD는 GitLab에서 제공하는 강력한 DevOps 도구로, 프로젝트 내에서 코드 변경 사항을 자동으로 테스트, 빌드, 배포할 수 있도록 지원한다. GitLab CI/CD는 GitLab과 통합되어 동작하기 때문에, GitLab 리포지토리와 직접 연결되어 프로젝트 관리와 배포 프로세스를 단순화한다. 또한 Github Actions와 다르게 파이프라인을 작성하고 실행하는 데 필요한 설정은 .gitlab-ci.yml 파일에 정의되어 자동화된 작업을 수행한다.

주요 컴포넌트는 다음과 같다.
Pipeline
- 파이프라인은 CI/CD 작업의 전체 프로세스를 정의하며, .gitlab-ci.yml 파일에서 stages 키워드로 선언
Stage:
- Stage는 파이프라인 내에서 그룹화된 작업(Job)의 집합
Job:
- 각 Job은 자신의 Stage에 속하며, 특정 작업(Script)을 실행
Script:
• 각 Job의 script 필드에 명령어 스크립트를 정의
Runner:
• 모든 Job은 Runner에서 실행되고 사용자가 설정한 Runner가 필요

3. GitLab CICD 주요기능
GItLab CI/CD에서 사용하는 주요 기능에 대해서 간단히 알아보자 .
CI 환경변수 활용
1. 사용자 정의 환경 변수
사용자 정의 환경 변수는 프로젝트별로 설정할 수 있고, 코드에 민감한 정보를 직접 노출하지 않고도 필요한 값을 파이프라인에서 사용할 수 있다. GitLab UI → Settings → CI/CD → Variables
메뉴를 통해 CICD에서 사용할 아래 변수를 생성해보자.
• HARBOR_USERNAME: Docker Hub 사용자 이름
• HARBOR_PASSWORD: Docker Hub 비밀번호
• HARBOR_URL: Docker Hub URL

2. GitLab에서 제공하는 환경변수
GitLab CI/CD는 사용자가 정의한 변수 외에도, 기본적으로 제공되는 환경 변수를 활용할 수 있다. 이 환경 변수들은 파이프라인의 동작과 GitLab의 통합된 정보를 동적으로 제공하여 파이프라인을 구성에 활용할 수 있다. 예를들어, Git의 커밋 정보, 브랜치, 태그, 프로젝트 정보 등을 쉽게 참조할 수 있어, 동적인 파이프라인 구성에 유용하다.
CI 변수 예시는 다음과 같으며 CI_<변수명>
이라는 prefix 접두사가 붙는다는게 특징이다.
• CI_PROJECT_NAME: 현재 프로젝트 이름.
• CI_COMMIT_SHA: 현재 커밋의 SHA 값.
• CI_PIPELINE_ID: 현재 파이프라인의 고유 ID.
• CI_JOB_NAME: 현재 실행 중인 Job 이름.
아래 스크립트를 통해서 사용하는 변수를 확인할 수 있다.
# gitlab-ci.yaml
...
job_name:
script:
- export
...
# 결과
export ARGOCD_SERVER_SERVICE_HOST='10.233.37.136'
export ARGOCD_SERVER_SERVICE_PORT='80'
export ARGOCD_SERVER_SERVICE_PORT_HTTP='80'
export ARGOCD_SERVER_SERVICE_PORT_HTTPS='443'
export CI='true'
export CI_API_GRAPHQL_URL='http://gitlab.dev.com/api/graphql'
export CI_API_V4_URL='http://gitlab.dev.com/api/v4'
export CI_BUILDS_DIR='/builds'
export CI_COMMIT_AUTHOR='장성필 <sp.jang@okestro.com>'
export CI_COMMIT_BEFORE_SHA='c467ed0f562a9115f3157e6ea20b6467a6688fc5'
3. 쿠버네티스 환경 변수 활용
쿠버네티스 환경을 사용한다면, 서비스 디스커버리 변수를 활용하여 CI/CD 작업의 자동화 수준을 크게 높일 수 있다. 쿠버네티스 서비스 디스커버리에 의해 같은 네임스페이스 내의 서비스 정보가 자동으로 모든 파드에 주입된다. 예를들어 GitLab과 같은 네임스페이스에 ArgoCD 파드가 존재한다고 가정하면 파이프라인에서 $ARGOCD_SERVER_HOST
환경변수를 참조 사용할 수 있다

조건문 활용
특정 이벤트나 조건에 해당하는 경우에만 파이프라인을 실행하도록하는 조건문을 활용할 수 있다.
Dockerfile이 존재할때만 빌드
...
# Run this job in a branch where a Dockerfile exists
rules:
- if: $CI_COMMIT_BRANCH
exists:
- Dockerfile
브랜치 제약
- main 브랜치에서만 실행
...
only:
- main
tags:
- runner
GitLab Template
GitHub Actions가 마켓플레이스를 통해 강력한 플러그인을 제공한다면, GitLab은 다양한 CI/CD 템플릿을 기본으로 제공한다. GitLab의 템플릿은 자주 사용되는 워크플로우를 빠르게 설정하고, 파이프라인을 간소화하는 데 유용하다.
GitLab CI/CD는 .gitlab-ci.yml 단일 파일로 파이프라인을 구성하지만, 템플릿을 활용하면 이를 더 구조화하고 재사용 가능하게 만들 수 있다. include 키워드를 사용해 GitLab이 제공하는 템플릿이나 외부 파일을 손쉽게 가져올 수 있습니다.
다양한 환경에서 파일을 가져올 수 있도록 지원한다.
include:
- local: 'templates/base.yml' # 같은 프로젝트의 파일
- project: 'group/project-name' # 다른 프로젝트에서 가져오기
file: '/templates/base.yml'
- remote: 'https://example.com/base.yml' # URL에서 가져오기
- template: 'Node.js.gitlab-ci.yml' # GitLab의 제공 템플릿
다음은 Node.js.gitlab-ci.yaml 템플릿을 사용 예시이다.
include:
- template: 'Node.js.gitlab-ci.yml'
test-job:
stage: test
script:
- echo "Running additional custom tests..."
Node.js.gitlab-ci.yml
파일 내용은 기본적인 Node.js 애플리케이션의 빌드 및 테스트 과정을 정의하고 있다.
# Node.js.gitlab-ci.yml
image: node:latest
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: https://docs.gitlab.com/ee/ci/services/index.html
services:
- mysql:latest
- redis:latest
- postgres:latest
# This folder is cached between builds
# https://docs.gitlab.com/ee/ci/yaml/index.html#cache
cache:
paths:
- node_modules/
test_async:
script:
- npm install
- node ./specs/start.js ./specs/async.spec.js
test_db:
script:
- npm install
- node ./specs/start.js ./specs/db-postgres.spec.js
deploy:
stage: deploy
script: echo "Define your deployment script!"
environment: production
이처럼 CI 템플릿 기능을 사용하면 재사용성이나 유지보수가 용이하고 표준화된 일관된 CICD 설정을 가져갈 수 있다. 또한 GitLab이 제공하는 공식 템플릿 외에도, 사용자 정의 템플릿을 만들어 필요에 따라 확장하거나 커스터마이징할 수 있다.
Node,Java,Go,Docker,Kubernetes 등 아래 링크를 통해 GitLab이 제공하는 다양한 CI 템플릿을 확인하고, 프로젝트에 적합한 템플릿을 활용해보자.
https://gitlab.com/gitlab-org/gitlab-foss/-/tree/master/lib/gitlab/ci/templates
4. GitLab Runner란?
GitLab Runner는 GitHub Actions의 Self-hosted Runner와 유사한 개념으로, GitLab CI/CD 파이프라인에서 정의된 작업(Job)을 실행하기 위한 에이전트 역할을 한다. GitHub Actions는 기본적으로 GitHub 호스팅 Runner를 제공하지만, GitLab은 기본 Runner를 제공하지 않기 때문에 사용자가 직접 GitLab Runner를 설치하고 구성해야 한다.
GitLab Runner를 설치하고 구성하는 방법을 알아보겠습니다. 이 예제에서는 Kubernetes 환경에서 Runner를 구성하는 과정을 다룬다.
사전준비
GitLab Runner를 설치하고 실행하기 전에 다음 환경이 준비되어 있어야 한다.
- 쿠버네티스 환경
- Kubernetes 클러스터가 이미 구축되어 있어야 한다.
- GitLab 구성
- GitLab 서버가 설치되어 있어야 한다.
- 본 예제에서는 GitLab 16.9.0 버전을 기준으로 진행
GitLab Runner 생성
GitLab Runner를 설치하기 위해서는 먼저 GitLab UI에서 Runner를 생성하고, 필요한 Runner 토큰을 발급받아야 한다.. 발급된 토큰은 Runner를 GitLab과 연결하는 데 사용된다.
Admin Area > Runners > New
메뉴에 접속하여 Runner를 생성한다. Runner가 설치될 호스트의 플랫폼에 맞게 선택하고 runner를 호출할 tag를 지정한다. 나의 경우 Linux 환경에서 러너를 설치하고 runner라는 tag를 지정하였다. 태그는 .gitlab-ci.yml
파일 내에서 특정 Job이 어떤 Runner에서 실행될지 지정하는 데 사용된다.

runner를 생성하게 되면 아래와 같이 Runner를 설치할 스크립트와 토큰 정보가 출력된다. 이번 포스팅에서는 GitLab UI에서 제공된 스크립트를 사용하지 않고, Helm Chart를 통해 Runner를 설치할 예정이다. 따라서 출력된 등록 토큰만 저장해 두고, 나머지 스크립트는 사용하지 않는다.

아직 Runner가 설치 및 등록되지 않았으므로, 상태가 연결되지 않음(Not Connected)으로 표시된다.

Gitlab Ruuner 설치
GitLab Runner를 설치할 때, GitLab 서버의 버전과 호환되는 Runner 버전을 사용하는 것이 중요하다. GitLab 서버와 동일한 GitLab 16.9.0 버전의 runner를 설치한다. helm pull 명령어를 사용해 GitLab Runner의 Helm Chart를 로컬로 가져온다.
• --untar 옵션을 사용하여 Chart를 압축 해제합니다.
helm repo add gitlab https://charts.gitlab.io
helm repo update
helm search repo -l gitlab/gitlab-runner | grep 16.9
gitlab/gitlab-runner 0.62.2 16.9.2 GitLab Runner
gitlab/gitlab-runner 0.62.1 16.9.1 GitLab Runner
gitlab/gitlab-runner 0.62.0 16.9.0 GitLab Runner
root@trb-dev-master-3:~/spjang/gitlab-runner# helm pull gitlab/gitlab-runner --version=0.62.0 --untar
override할 values 파일을 생성하고 아래 내용을 작성하여 배포한다.
gitlabUrl
: 연결할 깃랩 URL을 입력runnerToken
: 깃랩에서 발급한 runner 토큰을 입력
# custom values 작성
cat << EOF > runner-values.yaml
# runner-values.yaml
gitlabUrl: http://gitlab.dev.com/ # GitLab Url 넣기 !
runnerToken: "glrt-nyTDFzhGDwySY_QxWogs"
rbac:
create: true
EOF
# 배포
helm install gitlab-runner . -f runner-values.yaml -n trb-oss
# 업그레이드
helm upgrade gitlab-runner . -f runner-values.yaml -n trb-oss
# 파드 확인
kubectl get pod -n trb-oss | grep runner
gitlab-runner-778b75dfbb-dmh7g 1/1 Running
GitLab URL과 등록 토큰이 올바르게 설정되었다면, GitLab Runner는 Online 상태로 표시되며, CI/CD 파이프라인 작업을 실행할 준비가 완료되었다.

5. GitLab 파이프라인 구성하기
이제 GitLab CI/CD에서 사용할 파이프라인을 작성하고, 워크플로우를 실행해보자.
GitLab CI 파일 작성
이제 빌드할 소스 레포지토리를 클론받아 Docker 컨테이너 이미지를 빌드하고 배포하는 간단한 GitOps 파이프라인을 작성해보자.

Job 1 : git clone(Present)
빌드할 소스 레포지토리를 Clone 한다.
- bitnami/git:latest
- Git 명령어를 실행하기 위햐 git 명령어가 설치된 경량 컨테이너 이미지를 사용
- paths:
- 클론된 리포지토리(test-gitlab-runner-repo/)를 아티팩트로 저장.
- 아티팩트는 다음 단계(Job)에서 사용하거나 다운로드 가능.
- expire_in:
- 아티팩트의 유효 기간은 1시간.
- 이 시간이 지나면 저장된 아티팩트가 삭제됩니다.
git_clone:
stage: preset
image:
name: bitnami/git:latest
script:
- git clone http://gitlab-runner-credential:<GITLAB_TOKEN>@gitlab.dev.trb.com/system/test-gitlab-runner-repo.git --branch main
- ls -lh
artifacts:
paths:
- test-gitlab-runner-repo/
expire_in: 1 hour
tags:
- runner
Job 2 : docker(build)
- docker dind 방식을 사용하기 때문에, 실행 호스트의 Docker 데몬이 필요.
- 테스트 환경으로
Insecure
설정으로 레지스트리 간 HTTP 통신
stages:
- build
docker-build:
# Use the official docker image.
image: docker:cli
needs: ["clone_repo"]
stage: build
services:
- docker:dind
variables:
DOCKER_IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
before_script:
- docker images
- docker ps -a
- mkdir -p /etc/docker
- echo "{\"insecure-registries\":[\"$HARBOR_URL\"]}" > /etc/docker/daemon.json
- docker login -u "$HARBOR_USERNAME" -p "$HARBOR_PASSWORD" $HARBOR_URL
# All branches are tagged with $DOCKER_IMAGE_NAME (defaults to commit ref slug)
# Default branch is also tagged with `latest`
script:
- docker build --pull -t "$DOCKER_IMAGE_NAME" .
- docker push "$DOCKER_IMAGE_NAME"
- |
if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
docker tag "$DOCKER_IMAGE_NAME" "$CI_REGISTRY_IMAGE:latest"
docker push "$CI_REGISTRY_IMAGE:latest"
fi
tags:
- runner
Job 2-2 : Kaniko(build)
- DinD 방식은 호스트의 영향을 주기 때문에 Kaniko 사용을 추천.
before_script
를 활용하여 이미지 레지스트리 인증을 먼저 진행한다.- 테스트 환경이므로,
--insecure
옵션으로 레지스트리 HTTP 통신 - ci 파일 작성 시,
" "
안에"
는 앞에\
로 처리해줘야 함- 띄어쓰기 및 특수문자 주의
stages:
- build
image_build:
stage: build
needs: ["clone_repo"]
before_script:
# Setting to Kaniko
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$HARBOR_URL\":{\"username\":\"$HARBOR_USERNAME\",\"password\":\"$HARBOR_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cat /kaniko/.docker/config.json
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
# artifacts:
# paths:
# - output/
script:
- export
- echo "Building the app"
- /kaniko/executor --context dir://$CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $HARBOR_URL/library/gitlab-ci-test:$CI_COMMIT_SHORT_SHA --insecure
tags:
- runner
# Run this job in a branch where a Dockerfile exists
# rules:
# - if: $CI_COMMIT_BRANCH
# exists:
# - Dockerfile
Job 3 : ArgoCD(Deploy)
ArgoCD의 레포지토리의 애플리케이션을 미리 생성하자.
cat << EOF | kubectl apply -f -n argocd
# 레포지토리 생성
apiVersion: v1
kind: Secret
metadata:
name: runner-manifest-repo
namespace: trb-oss
labels:
argocd.argoproj.io/secret-type: repository
type: Opaque
data:
# Base64로 인코딩된 값
url: aHR0cDovL2dpdGxhYi5kZXYudHJiLmNvbS9zeXN0ZW0vdGVzdC1hcmdvY2QtbWFuaWZlc3QtcmVwby5naXQ=
username: cm9vdA==
password: Y2xvdWQxMjM0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: runner-deployment
labels:
app: runner
spec:
replicas: 1
selector:
matchLabels:
app: runner
template:
metadata:
labels:
app: runner
spec:
containers:
- name: runner-test
image: harbor.dev.trb.com/library/runner-test:87a9a810
ports:
- containerPort: 80
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitlab-runner-test
namespace: trb-oss
spec:
destination:
namespace: default
server: https://kubernetes.default.svc
project: default
source:
path: deploy/
repoURL: http://gitlab.dev.trb.com/system/test-argocd-manifest-repo.git
targetRevision: main
EOF
Stage 작성
- ArgoCD 애플리케이션에 연결되어 있는 메니페스트 레포지토리를 Clone 받는다.
CI_COMMIT_SHORT_SHA
라는 짧은 커밋 해쉬 값의 CI 변수를 활용하여 yq명령어를 이용해 태그 수정
#variables:
# CI_DEBUG_TRACE: "true"
stages:
- deploy
deploy_argocd:
stage: deploy
image:
name: alpine:latest
before_script:
- apk add --no-cache git curl jq yq
script:
- git clone http://runner-manifest-repo-credential:glpat-fdnJ5dRAwysCJ9AfFojY@gitlab.dev.trb.com/system/test-argocd-manifest-repo.git --branch main
- cd test-argocd-manifest-repo
- pwd && ls -al
# - yq -i ".image.tag = \"$CI_COMMIT_SHORT_SHA\"" ./grpc-helm/$CI_PROJECT_NAME/values.yaml
- yq e ".spec.template.spec.containers[0].image = \"$HARBOR_URL/library/runner-test:$CI_COMMIT_SHORT_SHA\"" -i deploy/deployment.yaml
- git config --global user.email "devops@gmail.com"
- git config --global user.name "devops"
- git status
- git add -A
- >
git commit -m "UPDATE :: $CI_PROJECT_NAME - runner test "
#- git commit -m *commit_message
- git push origin main
only:
- main
tags:
- runner
전체 파이프라인 스크립트는 다음과 같다.
#variables:
# CI_DEBUG_TRACE: "true"
stages:
- build
- deploy
image_build:
stage: build
# needs: ["clone_repo"]
before_script:
# Setting to Kaniko
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$HARBOR_URL\":{\"username\":\"$HARBOR_USERNAME\",\"password\":\"$HARBOR_PASSWORD\"}}}" > /kaniko/.docker/config.json
- cat /kaniko/.docker/config.json
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
# artifacts:
# paths:
# - output/
script:
- export
- echo "Building the app"
- /kaniko/executor --context dir://$CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $HARBOR_URL/library/runner-test:$CI_COMMIT_SHORT_SHA --insecure
tags:
- runner
# Run this job in a branch where a Dockerfile exists
# rules:
# - if: $CI_COMMIT_BRANCH
# exists:
# - Dockerfile
deploy_argocd:
stage: deploy
image:
name: alpine:latest
before_script:
- apk add --no-cache git curl jq yq
script:
- git clone http://runner-manifest-repo-credential:glpat-fdnJ5dRAwysCJ9AfFojY@gitlab.dev.trb.com/system/test-argocd-manifest-repo.git --branch main
- cd test-argocd-manifest-repo
- pwd && ls -al
# - yq -i ".image.tag = \"$CI_COMMIT_SHORT_SHA\"" ./grpc-helm/$CI_PROJECT_NAME/values.yaml
- yq e ".spec.template.spec.containers[0].image = \"$HARBOR_URL/library/runner-test:$CI_COMMIT_SHORT_SHA\"" -i deploy/deployment.yaml
- git config --global user.email "devops@gmail.com"
- git config --global user.name "devops"
- git status
- git add -A
- >
git commit -m "UPDATE :: $CI_PROJECT_NAME - runner test "
#- git commit -m *commit_message
- git push origin main
only:
- main
tags:
- runner
파이프라인 실행 및 확인
Repository > Build > Pipeline
메뉴에 접속하여 파이프라인을 목록을 확인한다. 해당 레포지토리에 푸시가 발생하면 파이프라인이 실행되고 결과를 확인할 수 있다.
파이프라인 목록

파이프라인 상세 정보

파이프라인 > 특정 Job 확인

이미지 레지스트리 확인
image_build 스테이지에서 이미지를 빌드하고 레지스트리로 푸시가 정상적으로 되었음을 확인할 수 있다.

메니페스트 저장소 확인
deploy 스테이지에서 메니페스트 저장소에 커밋 해쉬값이 태그로 잘 변경됨을 확인할 수 있다.

ArgoCD 확인
ArgoCD에서도 애플리케이션이 잘 배포되었음을 확인할 수 있다.
6. 결론
GitLab CI/CD를 사용해보며 느낀 점은 젠킨스와 비교하였을때, 문법이 간결하고 직관적이어서(병렬수행도 손쉽게) YAML 파일로 CI/CD 워크플로우를 쉽게 구성할 수 있었다. GitLab 레포지토리와 통합된 환경(변수,UI 등)을 제공하기 때문에 편리하였고 활용할 수 있는 부분들이 많았다. 간단한 GitLab CI/CD 기능만 다루어보았는데 향후에는 멀티 프로젝트 파이프라인, 동적 환경 설정 등 엔터프라이즈 환경에서의 고급 기능을 활용해 더 정교한 CI/CD 워크플로우를 구성해보자.
'CICD' 카테고리의 다른 글
GoCD 설치 및 기본 사용법 정리 (Feat. Kubernetes) (0) | 2025.04.04 |
---|---|
README.md만 수정했는데 ArgoCD가 파드를 재배포해요… 이거 진짜에요?(Diffing Customization) (0) | 2025.03.29 |
ArgoCD Autopilot: ArgoCD 및 GitOps 환경 자동 구축하기 (0) | 2024.12.19 |
Github Actions 기본 사용 방법 및 CI/CD 워크플로우 구성하기 (2) | 2024.12.14 |
jib를 활용하여 젠킨스 파이프라인 구성하기(GitOps + SpringBoot + Gradle ) (2) | 2024.12.08 |