GitHub Actions에서 마이그레이션
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
GitHub Actions에서 GitLab CI/CD로 마이그레이션하는 경우, GitHub Action 워크플로를 그대로 재현하면서 기능을 강화한 CI/CD 파이프라인을 만들 수 있습니다. 직접 손으로 작업할 수도 있고, 원하는 에이전트와 GitHub Actions to GitLab CI/CD 에이전트 스킬을 함께 사용할 수도 있습니다.
GitHub Actions에서 GitLab CI/CD로 마이그레이션하는 경우, GitHub Action 워크플로를 그대로 재현하면서 기능을 강화한 CI/CD 파이프라인을 만들 수 있습니다.
직접 손으로 작업할 수도 있고, 원하는 에이전트와 GitHub Actions to GitLab CI/CD 에이전트 스킬을 함께 사용할 수도 있습니다.
주요 공통점과 차이점#
GitHub Actions와 GitLab CI/CD는 둘 다 코드 빌드·테스트·배포를 자동화하는 파이프라인을 생성하는 데 사용됩니다. 두 도구는 다음과 같은 공통점을 갖습니다.
- CI/CD 기능이 프로젝트 리포지터리에 저장된 코드에 직접 접근합니다.
- 파이프라인 구성이 YAML로 작성되어 프로젝트 리포지터리에 저장됩니다.
- 파이프라인은 구성 가능하며 여러 단계로 나뉘어 실행될 수 있습니다.
- 각 작업(job)은 서로 다른 컨테이너 이미지를 사용할 수 있습니다.
이 외에 두 도구 사이에는 다음과 같은 중요한 차이점도 있습니다.
- GitHub는 서드파티 액션을 내려받을 수 있는 마켓플레이스를 제공하며, 여기에는 추가 지원이나 라이선스가 필요할 수 있습니다.
- GitLab은 모든 기능을 자체적으로 유지·지원하며, 일부 서드파티 통합은 템플릿을 통해 이용할 수 있습니다.
- GitLab은 컨테이너 레지스트리를 기본 제공합니다.
- GitLab은 Kubernetes 배포를 네이티브로 지원합니다.
- GitLab은 세밀한 보안 정책을 제공합니다.
기능·개념 비교#
GitHub의 많은 기능과 개념은 GitLab에서 동일한 기능을 제공하는 대응 요소를 갖고 있습니다.
구성 파일#
GitHub Actions는 워크플로 YAML 파일로
구성합니다. GitLab CI/CD는 기본적으로 .gitlab-ci.yml YAML 파일을 사용합니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
on: [push]
jobs:
hello:
runs-on: ubuntu-latest
steps:
- run: echo "Hello World"
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
stages:
- hello
hello:
stage: hello
script:
- echo "Hello World"
GitHub Actions 워크플로 문법#
GitHub Actions 구성은 특정 키워드를 사용하는 workflow YAML 파일로 정의됩니다.
GitLab CI/CD도 이와 유사한 기능을 제공하며, 마찬가지로 대개 YAML 키워드로 구성합니다.
| GitHub | GitLab | 설명 |
|---|---|---|
env |
variables |
env는 워크플로, job, step 단위로 설정되는 변수를 정의합니다. GitLab은 전역 또는 job 단위에서 CI/CD 변수를 정의할 때 variables를 사용합니다. 변수는 UI에서도 추가할 수 있습니다. |
jobs |
stages |
jobs는 워크플로에서 실행되는 모든 job을 묶습니다. GitLab은 job을 묶을 때 stages를 사용합니다. |
on |
해당 없음 | on은 워크플로가 트리거되는 시점을 정의합니다. GitLab은 Git과 긴밀하게 통합되어 있어 트리거를 위한 SCM 폴링 옵션이 필요하지 않지만, 필요하다면 job 단위로 구성할 수 있습니다. |
run |
해당 없음 | job에서 실행할 명령입니다. GitLab은 script 키워드 아래 YAML 배열을 사용하며, 실행할 명령마다 하나의 항목을 둡니다. |
runs-on |
tags |
runs-on은 job 이 실행되어야 할 GitHub 러너를 정의합니다. GitLab은 러너를 선택할 때 tags를 사용합니다. |
steps |
script |
steps는 job에서 실행되는 모든 단계를 묶습니다. GitLab은 job에서 실행되는 모든 명령을 묶을 때 script를 사용합니다. |
uses |
include |
uses는 step에 추가될 GitHub Action을 정의합니다. GitLab은 다른 파일의 구성을 job에 추가할 때 include를 사용합니다. |
일반적인 구성#
이 섹션에서는 자주 사용되는 CI/CD 구성이 GitHub Actions에서 GitLab CI/CD로 어떻게 변환되는지 살펴봅니다.
GitHub Action 워크플로는
새 커밋 푸시와 같은 특정 이벤트가 발생했을 때 트리거되는 자동화된 CI/CD job을
생성합니다. GitHub Action 워크플로는 리포지터리 루트의 .github/workflows
디렉터리에 위치한 YAML 파일로 정의됩니다. GitLab에서 이에 대응하는 것은
.gitlab-ci.yml 구성 파일이며, 이 역시 리포지터리 루트 디렉터리에 위치합니다.
Job#
Job은 컨테이너 빌드나 프로덕션 배포와 같이 특정 결과를 얻기 위해 정해진 순서로 실행되는 명령의 집합입니다.
예를 들어 다음 GitHub Actions workflow는 컨테이너를 빌드한 뒤 프로덕션에
배포합니다. deploy job 이 build job에 의존하므로 job 들은 순차적으로
실행됩니다.
on: [push]
jobs:
build:
runs-on: ubuntu-latest
container: golang:alpine
steps:
- run: apk update
- run: go build -o bin/hello
- uses: actions/upload-artifact@v3
with:
name: hello
path: bin/hello
retention-days: 7
deploy:
if: contains( github.ref, 'staging')
runs-on: ubuntu-latest
container: golang:alpine
steps:
- uses: actions/download-artifact@v3
with:
name: hello
- run: echo "Deploying to Staging"
- run: scp bin/hello remoteuser@remotehost:/remote/directory
이 예시는 다음과 같은 작업을 수행합니다.
golang:alpine컨테이너 이미지를 사용합니다.- 코드를 빌드하는 job을 실행합니다.
- 빌드된 실행 파일을 아티팩트로 저장합니다.
staging에 배포하는 두 번째 job을 실행하며, 이 job은 다음도 함께 수행합니다.- 실행 전에 build job 이 성공해야 합니다.
- 커밋의 대상 브랜치가
staging이어야 합니다. - 빌드된 실행 파일 아티팩트를 사용합니다.
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
default:
image: golang:alpine
stages:
- build
- deploy
build-job:
stage: build
script:
- apk update
- go build -o bin/hello
artifacts:
paths:
- bin/hello
expire_in: 1 week
deploy-job:
stage: deploy
script:
- echo "Deploying to Staging"
- scp bin/hello remoteuser@remotehost:/remote/directory
rules:
- if: $CI_COMMIT_BRANCH == 'staging'
병렬 실행#
GitHub와 GitLab 모두 job은 기본적으로 병렬로 실행됩니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
on: [push]
jobs:
python-version:
runs-on: ubuntu-latest
container: python:latest
steps:
- run: python --version
java-version:
if: contains( github.ref, 'staging')
runs-on: ubuntu-latest
container: openjdk:latest
steps:
- run: java -version
이 예시는 서로 다른 컨테이너 이미지를 사용하여 Python job과 Java job을
병렬로 실행합니다. Java job은 staging 브랜치가 변경되었을 때만 실행됩니다.
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
python-version:
image: python:latest
script:
- python --version
java-version:
image: openjdk:latest
rules:
- if: $CI_COMMIT_BRANCH == 'staging'
script:
- java -version
이 경우 job을 병렬로 실행하기 위해 별도의 구성이 필요하지 않습니다. 모든 job을
처리할 만큼 러너가 충분하다면, job은 기본적으로 서로 다른 러너에서 병렬로
실행됩니다. Java job은 staging 브랜치가 변경되었을 때만 실행되도록 설정되어
있습니다.
매트릭스#
GitLab과 GitHub 모두 매트릭스를 사용하여 하나의 파이프라인 안에서 job을 여러 번 병렬로 실행하되, job 인스턴스마다 서로 다른 변수 값을 적용할 수 있습니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "Building $PLATFORM for $ARCH"
strategy:
matrix:
platform: [linux, mac, windows]
arch: [x64, x86]
test:
runs-on: ubuntu-latest
steps:
- run: echo "Testing $PLATFORM for $ARCH"
strategy:
matrix:
platform: [linux, mac, windows]
arch: [x64, x86]
deploy:
runs-on: ubuntu-latest
steps:
- run: echo "Deploying $PLATFORM for $ARCH"
strategy:
matrix:
platform: [linux, mac, windows]
arch: [x64, x86]
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
stages:
- build
- test
- deploy
.parallel-hidden-job:
parallel:
matrix:
- PLATFORM: [linux, mac, windows]
ARCH: [x64, x86]
build-job:
extends: .parallel-hidden-job
stage: build
script:
- echo "Building $PLATFORM for $ARCH"
test-job:
extends: .parallel-hidden-job
stage: test
script:
- echo "Testing $PLATFORM for $ARCH"
deploy-job:
extends: .parallel-hidden-job
stage: deploy
script:
- echo "Deploying $PLATFORM for $ARCH"
트리거#
GitHub Actions는 워크플로에 트리거를 추가해야 합니다. GitLab은 Git과 긴밀하게 통합되어 있어 트리거를 위한 SCM 폴링 옵션이 필요하지 않지만, 필요하다면 job 단위로 구성할 수 있습니다.
GitHub Actions 구성 예시입니다.
on:
push:
branches:
- main
이에 대응하는 GitLab CI/CD 구성은 다음과 같습니다.
rules:
- if: '$CI_COMMIT_BRANCH == main'
파이프라인은 Cron 문법을 사용해 예약할 수도 있습니다.
컨테이너 이미지#
GitLab에서는 image 키워드를 사용하여
CI/CD job을 별도의 격리된 Docker 컨테이너에서 실행할
수 있습니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
jobs:
update:
runs-on: ubuntu-latest
container: alpine:latest
steps:
- run: apk update
이 예시에서 apk update 명령은 alpine:latest 컨테이너에서 실행됩니다.
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
update-job:
image: alpine:latest
script:
- apk update
GitLab은 모든 프로젝트에 컨테이너 이미지를 호스팅할 수 있는 컨테이너 레지스트리를 제공합니다. 컨테이너 이미지는 GitLab CI/CD 파이프라인에서 직접 빌드하고 저장할 수 있습니다.
예를 들면 다음과 같습니다.
stages:
- build
build-image:
stage: build
variables:
IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE .
- docker push $IMAGE
변수#
variables 키워드를 사용하면 런타임에 서로 다른 CI/CD 변수를
정의할 수 있습니다. 파이프라인에서 구성 데이터를 재사용해야 할 때 변수를
사용합니다. 변수는 전역 또는 job 단위로 정의할 수 있습니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
env:
NAME: "fern"
jobs:
english:
runs-on: ubuntu-latest
env:
Greeting: "hello"
steps:
- run: echo "$GREETING $NAME"
spanish:
runs-on: ubuntu-latest
env:
Greeting: "hola"
steps:
- run: echo "$GREETING $NAME"
이 예시에서는 변수에 따라 job 마다 서로 다른 출력이 나옵니다.
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
default:
image: ubuntu-latest
variables:
NAME: "fern"
english:
variables:
GREETING: "hello"
script:
- echo "$GREETING $NAME"
spanish:
variables:
GREETING: "hola"
script:
- echo "$GREETING $NAME"
변수는 GitLab UI의 CI/CD 설정에서도 설정할 수 있으며, 여기서 변수를 보호하거나 마스킹할 수 있습니다. 마스킹된 변수는 job 로그에서 숨겨지며, 보호된 변수는 보호된 브랜치나 태그에 대한 파이프라인에서만 접근할 수 있습니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
jobs:
login:
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
steps:
- run: my-login-script.sh "$AWS_ACCESS_KEY"
AWS_ACCESS_KEY 변수가 GitLab 프로젝트 설정에 정의되어 있다면, 이에 대응하는
GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
login:
script:
- my-login-script.sh $AWS_ACCESS_KEY
또한 GitHub Actions와 GitLab CI/CD 모두 파이프라인과 리포지터리에 관련된 데이터를 담은 내장 변수를 제공합니다.
조건문#
새 파이프라인이 시작되면 GitLab은 파이프라인 구성을 확인하여 해당 파이프라인에서
어떤 job을 실행할지 결정합니다. 변수의 상태나 파이프라인 유형과 같은 조건에 따라
job 실행 여부를 구성하려면 rules 키워드를 사용할 수
있습니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
jobs:
deploy_staging:
if: contains( github.ref, 'staging')
runs-on: ubuntu-latest
steps:
- run: echo "Deploy to staging server"
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
deploy_staging:
stage: deploy
script:
- echo "Deploy to staging server"
rules:
- if: '$CI_COMMIT_BRANCH == staging'
러너#
러너는 job을 실행하는 서비스입니다. GitLab.com을 사용하는 경우, 별도로 셀프 매니지드 러너를 프로비저닝하지 않고도 인스턴스 러너 플릿을 사용해 job을 실행할 수 있습니다.
러너에 대한 주요 사항은 다음과 같습니다.
- 러너는 인스턴스 전체, 그룹, 또는 단일 프로젝트 전용으로 구성할 수 있습니다.
- 더 세밀한 제어를 위해
tags키워드를 사용하여 러너를 특정 job과 연결할 수 있습니다. 예를 들어 전용의, 더 강력한, 또는 특정한 하드웨어가 필요한 job에 태그를 사용할 수 있습니다. - GitLab은 러너 오토스케일링을 지원합니다. 오토스케일링을 사용하면 필요할 때만 러너를 프로비저닝하고, 필요하지 않을 때는 축소할 수 있습니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
linux_job:
runs-on: ubuntu-latest
steps:
- run: echo "Hello, $USER"
windows_job:
runs-on: windows-latest
steps:
- run: echo "Hello, %USERNAME%"
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
linux_job:
stage: build
tags:
- linux-runners
script:
- echo "Hello, $USER"
windows_job:
stage: build
tags:
- windows-runners
script:
- echo "Hello, %USERNAME%"
아티팩트#
GitLab에서는 job 이 완료될 때 저장할 아티팩트 집합을 정의하기 위해 모든 job에서 artifacts 키워드를 사용할 수 있습니다. 아티팩트는 이후의 job에서 사용할 수 있는 파일입니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
on: [push]
jobs:
generate_cat:
steps:
- run: touch cat.txt
- run: echo "meow" > cat.txt
- uses: actions/upload-artifact@v3
with:
name: cat
path: cat.txt
retention-days: 7
use_cat:
needs: [generate_cat]
steps:
- uses: actions/download-artifact@v3
with:
name: cat
- run: cat cat.txt
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
stage:
- generate
- use
generate_cat:
stage: generate
script:
- touch cat.txt
- echo "meow" > cat.txt
artifacts:
paths:
- cat.txt
expire_in: 1 week
use_cat:
stage: use
script:
- cat cat.txt
캐싱#
캐시는 job 이 하나 이상의 파일을 다운로드하여 이후 더 빠르게 접근할 수 있도록 저장할 때 생성됩니다. 동일한 캐시를 사용하는 이후 job은 파일을 다시 다운로드할 필요가 없으므로 더 빠르게 실행됩니다. 캐시는 러너에 저장되며, 분산 캐시가 활성화된 경우 S3에 업로드됩니다.
예를 들어 GitHub Actions의 workflow 파일은 다음과 같습니다.
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "This job uses a cache."
- uses: actions/cache@v3
with:
path: binaries/
key: binaries-cache-$CI_COMMIT_REF_SLUG
이에 대응하는 GitLab CI/CD .gitlab-ci.yml 파일은 다음과 같습니다.
cache-job:
script:
- echo "This job uses a cache."
cache:
key: binaries-cache-$CI_COMMIT_REF_SLUG
paths:
- binaries/
템플릿#
GitHub에서 액션(Action)은 CI/CD 파이프라인을 매번 새로 정의하지 않고 재사용할 수
있도록 저장된, 자주 반복해야 하는 복잡한 작업의 집합입니다. GitLab에서 이에
대응하는 것은 include 키워드로, 이를 사용하면 GitLab에
내장된 템플릿 파일을 포함하여 다른 파일의 CI/CD 파이프라인을 추가할
수 있습니다.
GitHub Actions 구성 예시입니다.
- uses: hashicorp/setup-terraform@v2.0.3
이에 대응하는 GitLab CI/CD 구성은 다음과 같습니다.
include:
- template: Terraform.gitlab-ci.yml
이 예시에서 setup-terraform GitHub action과 Terraform.gitlab-ci.yml GitLab
템플릿이 정확히 일치하는 것은 아닙니다. 두 예시는 복잡한 구성을 재사용하는
방법을 보여주기 위한 것일 뿐입니다.
보안 스캐닝 기능#
GitLab은 SDLC 전 구간의 취약점을 탐지하기 위한 다양한 보안 스캐너를 기본으로 제공합니다. 템플릿을 사용하면 이러한 기능을 GitLab CI/CD 파이프라인에 추가할 수 있습니다.
예를 들어 파이프라인에 SAST 스캐닝을 추가하려면 .gitlab-ci.yml에 다음을
추가합니다.
include:
- template: Jobs/SAST.gitlab-ci.yml
SAST 스캐너의 경우처럼, CI/CD 변수를 사용하여 보안 스캐너의 동작을 사용자 정의할 수 있습니다.
시크릿 관리#
흔히 "시크릿(secret)"이라 부르는 권한이 있는 정보는 CI/CD 워크플로에서 필요한 민감한 정보나 자격 증명입니다. 도구, 애플리케이션, 컨테이너, 클라우드 네이티브 환경에서 보호된 리소스나 민감한 정보를 잠금 해제하는 데 시크릿을 사용할 수 있습니다.
GitLab에서 시크릿을 관리하려면 외부 서비스에 대한 지원되는 통합 중 하나를 사용할 수 있습니다. 이러한 서비스는 GitLab 프로젝트 외부에 시크릿을 안전하게 저장하지만, 해당 서비스에 대한 구독이 있어야 합니다.
GitLab은 OIDC를 지원하는 다른 서드파티 서비스를 위한 OIDC 인증도 지원합니다.
또한 자격 증명을 CI/CD 변수에 저장하여 job에서 사용할 수 있게 만들 수 있지만, 평문으로 저장된 시크릿은 실수로 노출될 위험이 있습니다. 민감한 정보는 항상 마스킹되고 보호된 변수에 저장해야 하며, 이렇게 하면 위험을 일부 완화할 수 있습니다.
또한 시크릿을 .gitlab-ci.yml 파일에 변수로 저장해서는 안 됩니다. 이 파일은
프로젝트에 접근 권한이 있는 모든 사용자에게 공개되기 때문입니다. 민감한 정보를
변수에 저장하는 작업은 반드시
프로젝트, 그룹, 또는 인스턴스 설정에서만
수행해야 합니다.
CI/CD 변수의 안전성을 높이려면 보안 가이드라인을 확인합니다.
마이그레이션 계획 및 수행#
다음 단계는 이 마이그레이션을 계획하고 수행하는 데 도움이 됩니다.
마이그레이션 계획 세우기#
마이그레이션을 시작하기 전에 마이그레이션 준비를 위해 마이그레이션 계획을 세워야 합니다.
사전 준비 사항#
마이그레이션 작업을 하기 전에 먼저 다음을 수행해야 합니다.
- GitLab에 익숙해집니다.
- 주요 GitLab CI/CD 기능을 읽어봅니다.
- 튜토리얼을 따라 첫 GitLab 파이프라인을 만들고, 정적 사이트를 빌드·테스트·배포하는 더 복잡한 파이프라인도 만들어 봅니다.
- CI/CD YAML 문법 레퍼런스를 검토합니다.
- GitLab을 설정하고 구성합니다.
- GitLab 인스턴스를 테스트합니다.
- 공유 GitLab.com 러너를 사용하거나 새 러너를 설치하여 러너를 사용할 수 있는지 확인합니다.
마이그레이션 단계#
- 프로젝트를 GitHub에서 GitLab으로 마이그레이션합니다.
- (권장) GitHub Importer를 사용하면 외부 SCM 제공업체로부터의 대량 임포트를 자동화할 수 있습니다.
- URL로 리포지터리를 임포트할 수도 있습니다.
- 각 프로젝트에
.gitlab-ci.yml을 생성합니다. - GitHub Actions job을 GitLab CI/CD job으로 마이그레이션하고, 결과가 머지 리퀘스트에 직접 표시되도록 구성합니다. 이 작업은 제공되는 Agent Skill을 사용하여 자동화할 수 있습니다.
- 클라우드 배포 템플릿, 환경, GitLab Kubernetes 에이전트를 사용하여 배포 job을 마이그레이션합니다.
- 여러 프로젝트에서 재사용할 수 있는 CI/CD 구성이 있는지 확인한 뒤, CI/CD 컴포넌트를 만들어 공유합니다.
- GitLab CI/CD 파이프라인을 더 빠르고 효율적으로 만드는 방법을 알아보려면 파이프라인 효율성 문서를 확인합니다.