IaC로 Pulumi 적용하기

YujinLee
8 min readAug 20, 2022

--

IaC란?

IaC는 Infrastucture as Code의 약자로, 말 그대로 인프라를 코드로 관리한다는 의미입니다.

그럼 IaC는 왜 적용해야 할까요? 인프라를 수동 프로세스가 아닌 코드로 관리하면 다음과 같은 이점이 있습니다.

  • 인프라의 일관성이 향상됩니다.
  • 버전 관리가 가능해집니다. 또한 인프라를 모듈식 구성 요소로 분할하고 재구성하여 사용할 수 있습니다.
  • 배포 속도가 빨라집니다.
  • 오류가 감소합니다.

DevOps 측면에서도 IaC는 중요한 의미를 갖습니다. 프로비저닝 작업을 대부분 IaC로 처리하면 개발자는 스크립트만으로 인프라 구성이 가능해집니다.

IaC 툴에는 대표적으로 다음과 같이 있습니다.

  • Chef
  • Puppet
  • Terraform
  • AWS CloudFormation
  • Pulumi

Pulumi를 선택한 이유

https://www.pulumi.com/blog/pulumi-2-0/pulumi-2-0.png

사내에서는 현재 IaC를 위해 Pulumi로 코드 관리를 하고 있습니다. Pulumi는 다양한 프로그래밍 언어를 통해 IaC 구현이 가능합니다. 흔히 사용되는 IaC툴인 Terraform은 Terraform 전용 언어인 Hashicorp라는 언어를 사용해야 하지만 그에 반해 Pulumi는 개발자가 익숙한 언어를 선택할 수 있다는 장점이 있습니다. 현재 저희 회사의 경우파이썬으로 인프라를 구현하고 코드로 관리합니다.

Pulumi는 AWS, GCP, Azure, Kubernetes 와 같은 주요 클라우드 플랫폼 및 시스템을 지원하고 있으며 이외에도 Snowflake와 같은 다양한 플랫폼도 지원됩니다.

Components

Pulumi의 구성요소는 다음과 같습니다.

https://www.pulumi.com/images/docs/pulumi-programming-model-diagram.svg
  • Program : Program은 Python, Javascript, Go, Java 등 프로그래밍 언어로 인프라를 구현한 코드입니다. 인프라는 Resource 객체로 구성되며 각 Resource의 Property는 상태가 지속적으로 관리됩니다. Property는 다른 Resource에 참조되기 위해 Input 또는 Output으로 저장될 수 있습니다.
  • Project : Program은 Project에 상주합니다. Program의 소스 코드와 실행 방식에 대한 메타 데이터를 포함하는 스크립트가 존재합니다. Program 내용을 구현하면 pulumi up 명령어로 인프라를 셋업하게 됩니다.
  • Stack : Stack은 Project에 대한 독립된 배포 단위를 가집니다 . 각각의 Stack은 별개의 설정값과 환경을 구성합니다. staging, development, production과 같은 분리된 배포 환경을 별도의 Stack으로 관리할 수 있습니다.

예를 들어, pulumi new aws-python을 실행하여 python으로 AWS project를 생성하고자 하면 기본적인 구성 요소는 다음과 같습니다.

├── Pulumi.yaml
├── Pulumi.dev.yaml
├── __main__.py
├── requirements.txt
└── venv
  • Pulumi.yaml : Project에 대한 정의가 포함됩니다.
  • Pulumi.dev.yaml : default로는 dev 라는 Stack을 생성하는데 Stack마다 정의하는 고유의 설정값이 포함됩니다.
  • __main__.py : 리소스를 정의합니다. 실제로 배포할 리소스에 대한 코드가 반영됩니다.

venv는 pulumi가 돌아갈 파이썬 가상 환경이고, requirements.txt는 파이썬 패키지 의존성을 관리하기 위한 패키지들을 명시하는 파일입니다.

Pulumi로 코드 관리하기

실제로 Pulumi로 인프라를 관리하면 배포할 리소스의 구성 집합은 Project와 Stack을 통해 이루어집니다. Project는 소스 코드의 집합이고, Stack은 하나의 배포 단위입니다.

Project와 Stack 구조를 구성하는데는 크게 다음과 같이 있습니다.

  • Monolithic
  • Micro-Stack

Monolithic 구조

처음 Pulumi를 적용하게 되면 보통 Monolithic 구조로 구성할 것입니다. 전체 인프라를 하나의 Project로 코드 관리를 하고, Stack으로 배포 환경을 다르게 하여 구성할 것입니다.

다음은 하나의 프로젝트 레포지토리에서 관리할 경우 예시입니다.

├─ infrastructure
├── __main__.py
├── Pulumi.yaml
├── Pulumi.dev.yaml
└── Pulumi.prod.yaml

단순하지만 인프라 규모가 늘어나게 되면 한번에 배포되는 리소스의 양이 너무 많아지게 됩니다. Pulumi는 첫 배포 이후에 코드가 수정되면 현재의 State에서 바뀐 부분을 비교하여 달라진 리소스만 Create/Update/Delete를 실행합니다. 하나의 Project내에서 관리되는 리소스가 많다면 매번 코드가 수정되어 배포할 때마다 시간이 오래 걸리게 됩니다.

Micro-Stack 구조

이와 다르게 Micro-Stack 구조는 독립적인 Project를 구성하고자 합니다. 전체 인프라를 작은 규모로 쪼개서 별개의 Project로 관리합니다.

마찬가지로 하나의 프로젝트 레포지토리에서 관리할 경우 예시입니다. 이 경우는 Pulumi Service를 사용함을 전제로 합니다.

├── infrastructure
│ ├── __main__.py
│ ├── Pulumi.yaml
│ ├── Pulumi.dev.yaml
│ └── Pulumi.prod.yaml
├── myApp
│ ├── __main__.py
│ ├── Pulumi.yaml
│ ├── Pulumi.dev.yaml
│ └── Pulumi.prod.yaml
└── ...

Pulumi Service를 사용하지 않는다면 같은 backend에서 서로 다른 Project은 같은 Stack 이름을 가질 수 없으므로 다음과 같이 구성해야 합니다.

├── infrastructure
│ ├── __main__.py
│ ├── Pulumi.yaml
│ ├── Pulumi.dev.yaml
│ └── Pulumi.prod.yaml
├── myApp
│ ├── __main__.py
│ ├── Pulumi.yaml
│ ├── Pulumi.app-dev.yaml
│ └── Pulumi.app-prod.yaml
└── ...

각 Project에서 배포되는 리소스 양이 작아지므로 변경 사항에 대한 추적이 빨라서 빠른 배포가 가능합니다. 또한 조직의 규모가 크다면 접근할 수 있는 리소스를 분리하여 각 팀마다 Project를 관리하는 것이 보안상 유리해집니다.

Pulumi에서는 Stack간에 Resource 참조가 가능하기에 Project간에 리소스 dependency 관리가 가능합니다. Micro-Stack 구조로 구성해도 다른 Stack의 리소스를 활용할 수 있기에 전체적인 관점에서 유기적으로 연결될 수 있습니다.

import pulumi

config = pulumi.Config()
stack = pulumi.get_stack()

stack_ref = pulumi.StackReference({STACK_NAME})
pulumi.export("shopUrl", stack_ref.get_output("url"))

References

--

--