Pulumi는 Infrastructure as Code(IaC) 도구로, 인프라를 편리하게 구성하고 관리하도록 돕습니다. 이 도구는 다양한 클라우드 서비스 제공업체(CSP) 리소스와 DevOps 도구를 지원하는데요. 여러 프로그래밍 언어를 사용해 클라우드 인프라와 관련 애플리케이션 리소스를 선언적으로 정의하고 관리하도록 합니다.

Pulumi는 CSP 리소스를 IaC 형식으로 관리하는 데 자주 사용되지만 GitLab의 리소스를 제어하는 데도 탁월한데요. 특히 이는 환경변수 설정, CI 스크립트 업로드 등 CI/CD를 작동시킬 때 필요한 사전 작업을 편리하게 수행하는 데 도움이 됩니다. 오늘은 Pulumi를 사용해 GitLab의 리소스를 생성, 파일을 업로드하는 방법을 알아보고요. GitLab에서 Pulumi로 IaC 자동화를 진행하는 방법도 살펴보겠습니다.

Pulumi로 GitLab 리소스 생성

1단계: 환경 설정

Pulumi를 처음 사용하는 분은 인포그랩 기술 블로그의 Pulumi로 인프라 구축하기 글을 참고해 기본 환경을 설정한 다음, 실습해 주세요.

아울러 이 실습을 진행하려면 다음 환경변수를 등록해야 합니다.

- PULUMI_ACCESS_TOKEN : Pulumi 계정에서 발급받을 수 있는 토큰입니다.
- PULUMI_ORG_NAME : Pulumi organization 혹은 개인 사용자의 이름입니다.
- GITLAB_TOKEN : GitLab 프로젝트를 생성할 수 있는 권한을 지닌 토큰입니다.
- AWS_ACCESS_KEY_ID : aws의 access_key_id입니다.
- AWS_SECRET_ACCESS_KEY : aws의 secret_access_key입니다.

이어서 Pulumi가 지원하는 언어 중 자신에게 가장 편한 언어를 선택하고, 해당 언어에 맞게 실습하면 됩니다.

이 실습은 Python으로 진행합니다. 각 언어의 상세 설명은 Pulumi의 공식 기술 문서를 참고해 주세요.

2단계: pulumi-python 프로젝트 생성

이제 Pulumi를 사용해 본격적으로 GitLab의 리소스를 생성하려는데요. 먼저 터미널에 pulumi new python을 입력해 pulumi-python 프로젝트를 생성합니다.

Python이 아닌 다른 언어를 사용하면 pulumi new 언어 이름(예: pulumi new typescript)을 입력하여 해당 언어에 맞는 프로젝트를 생성하면 됩니다(이때 빈 디렉터리에서 진행해야 합니다).

그다음, 패키지를 다운로드 받기 위해 source venv/bin/activate를 입력하여 가상 환경으로 이동하고요. pip로 pulumi-aws와 pulumi-gitlab을 설치합니다.

이어서 __main__.py 상단에 아래와 같이 import문을 추가해 AWS와 GitLab 라이브러리를 사용하도록 합니다.

from pulumi_aws import * 
from pulumi_gitlab import *

3단계: GitLab 프로젝트 생성

이제 Pulumi.gitlab 함수를 사용해 이름(path)으로 기존 GitLab 그룹을 가져오고, 이 그룹에 새로운 GitLab 프로젝트를 만듭니다.

이때 환경변수로 GitLab 프로젝트 생성 권한이 있는 GITLAB_TOKEN을 다음과 같이 등록합니다.

import pulumi
import pulumi_gitlab as gitlab
import os

token = os.environ['GITLAB_TOKEN']

# full_path는 자신이 조회하고자하는 group의 경로입니다.
group = gitlab.get_group(full_path="infograb/personal/john")

project = gitlab.Project("pulumi-gitlab-demo",
visibility_level="private",
default_branch="main",
namespace_id=group.id,
archive_on_destroy=False)

# 생성된 프로젝트의 ID를 출력합니다.
pulumi.export('project_id', project.id)

그다음, pulumi up을 입력하면 아래 이미지와 같이 GitLab 프로젝트가 생성됩니다.

GitLab 프로젝트 pulumi-gitlab-demo-8355309가 생성된 모습 | 인포그랩 GitLab
GitLab 프로젝트 pulumi-gitlab-demo-8355309가 생성된 모습

4단계: 리포지터리 파일 추가

이제 repo_file 디렉터리를 생성하고요. 하위에 .gitlab-ci.yml 파일을 만듭니다.

default:
image:
# 자신의 언어에 맞는 이미지 사용
name: "pulumi/pulumi-python"
entrypoint: [""]

stages:
- infra-update

pulumi-up:
stage: infra-update
script:
- pip3 install -r requirements.txt
- pulumi login
- pulumi org set-default $PULUMI_ORG
- pulumi stack select dev
- pulumi up -y
only:
- main # default branch
pulumi-preview:
stage: infra-update
script:
- pip3 install -r requirements.txt
- pulumi login
- pulumi org set-default $PULUMI_ORG
- pulumi stack select dev
- pulumi preview
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'

이어서 아래와 같이 __main__.py 를 수정해 .gitlab-ci.yml 파일을 pulumi로 프로젝트에 업로드하도록 합니다.

import pulumi
import pulumi_gitlab as gitlab

# 파일 목록
files = [
".gitlab-ci.yml",
]

# 파일별로 반복
for file in files:
# 파일 내용 읽기
with open(f"repo-file/{file}", "r", encoding="utf-8") as f:
content = f.read()

# GitLab 프로젝트에 파일 추가
gitlab_repository_file = gitlab.RepositoryFile(file,
project=project.id,
file_path=file,
branch="main",
content=content,
commit_message=f"Add {file}",
encoding="text",
)

pulumi.export("url", pulumi.Output.format('git clone git@gitlab.com:infograb/personal/john/pulumi-gitlab-demo-8366309.git'))

pulumi up 을 입력하면 변경 사항이 다음과 같이 터미널에 보입니다. 이때 ‘yes’를 선택하고 리소스를 생성합니다.

터미널에 나온 변경 사항 현황 | 인포그랩 GitLab
터미널에 나온 변경 사항 현황

pulumi up 이 완료된 뒤 GitLab에 접속하면 아래 이미지와 같이 .gitlab-ci.yml 파일이 정상적으로 생성, 업로드된 걸 확인할 수 있습니다. 이로써 Pulumi를 사용한 GitLab 리소스 생성 작업이 완료되었습니다.

`.gitlab-ci.yml` 파일이 생성된 모습 | 인포그랩 GitLab
.gitlab-ci.yml 파일이 생성된 모습

보셨다시피 Pulumi와 같은 IaC는 인프라 구성을 코드로 관리하도록 지원하는데요. 개발자와 운영팀은 인프라를 수동으로 설정하고 관리하는 대신 사전에 작성된 코드를 사용하여 자동화할 수 있습니다.

이 과정에서 반복적이고 일관성 있게 환경을 설정할 수 있고요. 휴먼 에러를 줄여 시스템 관리를 최소화할 수 있습니다. 또 팀의 작업 효율을 향상해 생산성을 높일 수 있고요.

GitLab에서 Pulumi로 IaC 자동화

1단계: GitLab에 CI/CD 환경변수 설정

이제 GitLab에서 Pulumi로 IaC 자동화를 진행하려는데요. 우선 GitLab 파이프라인에서 정상적으로 AWS의 리소스를 생성하도록 환경변수를 등록해야 합니다.

아울러 Pulumi Cloud 백엔드에 인증하도록 CI/CD 프로세스에 Pulumi 액세스 토큰이 필요하고요. Pulumi Cloud Organization 이름도 있어야 합니다(Pulumi Cloud를 개인으로 사용하면, Pulumi 사용자 이름을 추가하면 됩니다). 참고로 Pulumi Cloud 백엔드는 Pulumi 상태 파일을 보관하고, 시크릿의 암호화와 암호 해독을 처리합니다.

먼저 __main__.py 하단에 다음 코드를 추가하고 pulumi up을 입력해 GitLab에 CI/CD 환경변수를 추가합니다.

pulumi_access_token = os.getenv("PULUMI_ACCESS_TOKEN")
pulumi_org_name = os.getenv("PULUMI_ORG_NAME")
pulumi_aws_accesskey = os.getenv("AWS_ACCESS_KEY_ID")
pulumi_aws_secretkey = os.getenv("AWS_SECRET_ACCESS_KEY")

pulumi_access_token = gitlab.ProjectVariable("pulumi-access-token",
project=project.id,
key="PULUMI_ACCESS_TOKEN",
value=pulumi_access_token,
)

pulumi_org = gitlab.ProjectVariable("pulumi-org",
project=project.id,
key="PULUMI_ORG",
value=pulumi_org_name,
)

pulumi_aws_access = gitlab.ProjectVariable("pulumi-accesskey",
project=project.id,
key="AWS_ACCESS_KEY_ID",
value=pulumi_aws_accesskey,
)

pulumi_aws_secret = gitlab.ProjectVariable("pulumi-secretkey",
project=project.id,
key="AWS_SECRET_ACCESS_KEY",
value=pulumi_aws_secretkey,
)

pulumi up을 완료하면 아래와 같이 CI/CD 환경변수를 확인할 수 있습니다.

Pulumi로 생성된 CI/CD 환경변수 | 인포그랩 GitLab
Pulumi로 생성된 CI/CD 환경변수

2단계: 인프라 배포, 파이프라인 테스트

이제 AWS 리소스를 생성하는 프로젝트를 만들어 인프라를 배포하고, 파이프라인을 테스트합니다.

  1. git clone ${git_link} 를 입력하여 기존에 .gitlab-ci.yml 을 업로드한 프로젝트를 clone 합니다.
  2. 이후 git checkout -b ${branch_name}을 입력해 브랜치를 생성합니다.
  3. pulumi new aws-python -y --force 명령을 입력해 Python 기반의 pulumi-aws 프로젝트를 생성합니다.
  4. git add . , git commit -m "${commit_message}" , git push origin ${branch_name}을 터미널에 입력해 생성한 pulumi-aws 프로젝트를 GitLab 프로젝트에 반영합니다.
$ git clone https://gitlab.com/john/...
$ git checkout -b gitlab-pulumi
$ pulumi new aws-python -y --force
$ git add .
$ git commit -m "First Commit"
$ git push origin gitlab-pulumi

위 과정을 진행하고 GitLab 프로젝트로 이동하면 다음과 같이 ‘Create merge request’ 버튼이 보입니다. 이를 클릭해 Merge request를 생성합니다.

GitLab 프로젝트 페이지 | 인포그랩 GitLab
GitLab 프로젝트 페이지

Merge request를 생성한 다음, 아래처럼 파이프라인이 실행되는 걸 확인할 수 있습니다.

파이프라인 실행 현황을 보여주는 Merge request 페이지 | 인포그랩 GitLab
파이프라인 실행 현황을 보여주는 Merge request 페이지

현재 pulumi preview 가 실행되고 있어 ‘어떤 리소스가 생성될지’ 미리 확인할 수 있습니다. 파이프라인 실행이 완료되면, main 브랜치로 merge 합니다.

Job Log 화면 | 인포그랩 GitLab
Job Log 화면

main 브랜치로 merge 하면 pulumi up이 실행됩니다. 이때 ‘어떤 리소스가 실제 반영되었는지’ 다음과 같이 볼 수 있습니다.

Job Log에 나온 리소스 반영 사항 | 인포그랩 GitLab
Job Log에 나온 리소스 반영 사항

마지막으로 AWS에 로그인해 S3로 이동하면 pulumi up 명령으로 생성된 리소스를 아래와 같이 확인할 수 있습니다. 이로써 GitLab에서 Pulumi를 사용한 IaC 자동화 작업이 완료되었습니다.

`pulumi up` 명령으로 생성된 리소스 | 인포그랩 GitLab
pulumi up 명령으로 생성된 리소스

이처럼 파이프라인으로 IaC를 자동화하면, 코드 변경 사항이 자동으로 인프라에 반영돼 테스트, 프로덕션 환경에 신속히 배포됩니다. 이 과정에서 개발자는 인프라 설정 변경을 소프트웨어 코드 변경처럼 다루는데요. 모든 변경 사항이 자동으로 테스트 돼 안정성을 확보할 수 있습니다.

또한 배포 자동화로 프로젝트의 반복적인 업데이트와 수정이 자주 필요할 때 신속하게 반응할 수 있는데요. 이로써 개발 주기를 단축하고 효율적으로 운영할 수 있습니다. 이는 업무 생산성을 높이며 제품 품질을 향상하는 데 도움이 되죠.

맺음말

제가 Pulumi를 사용해 GitLab의 리소스를 생성하고, GitLab에서 Pulumi로 IaC 자동화를 진행하며 느낀 점은 이렇습니다.

  • IaC의 특수한 문법(Terraform의 HCL 등)을 따로 배우지 않아도 기존에 사용하던 프로그래밍 언어로 작업해 편리했습니다.
  • GitLab을 같이 사용하면 다른 사람과 함께 Pulumi 코드를 작업하거나 히스토리를 관리할 수 있습니다. 아울러 GitLab의 파이프라인을 사용해 인프라 변경 사항을 쉽게 적용할 수 있는데요. 이로써 인프라 작업을 더 효율적으로 수행할 수 있었습니다.
  • 그러나 Pulumi는 최근에 나온 도구라서 Terraform 등 다른 IaC 도구보다 참고 자료가 적은데요. 실습 도중 발생한 오류를 손쉽게 해결하기는 어려웠습니다.

Pulumi에 아쉬운 점도 있지만 인프라를 구성하고 관리할 때 단점보다 장점이 많은 도구라고 생각합니다. 꼭 Pulumi가 아니더라도 IaC 도구를 활용해 GitLab과 CSP 리소스를 정의하면 리소스를 안정적으로 관리할 수 있고요. 자동화에 힘입어 서비스를 신속하게 제공할 수 있습니다. 이는 엔지니어의 업무 생산성을 높이는 데도 도움이 되고요. 지금까지 읽어주셔서 감사합니다. 😊

인포그랩은 GitLab과 DevOps를 맞춤형으로 기술 지원합니다. GitLab(Omnibus/Cloud Native Hybrid) 구축 지원이 필요하시면 문의하기로 연락해 주십시오.

참고 자료

  1. Pulumi로 GitLab 리소스 관리하기