코드로 인프라 관리하기 IaC - Terraform으로 EKS 클러스터 만들기

rogiry
29CM TEAM
Published in
10 min readAug 10, 2021

Infrastructure as Code (IaC) 라는 단어를 들어보신 적 있나요 ?
IaC 란 “코드형 인프라” 라고 볼 수 있는데 인프라 구성을 코드화 시켜두어 구축, 관리 하는 것을 말합니다.

29CM에서는 코드를 이용해 인프라를 구성하고 관리하고 있습니다.
코드를 이용해 인프라를 구성하고 관리하면 어떤 이점이 있을까요 ?

현재는 클라우드가 많이 활성화 되어 AWS, Azure, GCP, NCP 등등의 다양한 클라우드를 선택해 인프라를 쉽게 구성할 수 있습니다. 하지만 클라우드를 사용하더라도 서비스 운영을 위한 인프라 구성시에는 단순하고 지겨운 반복 과정들이 많이 있습니다.

예를들어 클라우드를 활용하여 특정 환경을 구성하더라도 컴퓨팅 노드를 준비하고 스토리지 용량을 설정하고 네트워크 방화벽과 로드밸런서에 프록시 타겟 서버를 준비해야 하는 과정은 필요합니다. 이런 환경을 매번 수동으로 설정한다면 인프라를 관리하는 측면에서는 아무래도 부담이 될 수 있습니다

하지만 IaC 개념에 따라 인프라의 구성 스펙을 코드화 시켜놓으면, 이후에는 반복적인 인프라 구성을 정확하고 빠르게 진행할 수 있습니다. 인프라 구성을 코드로 관리하기 때문에 VCS (Git) 을 이용한 인프라의 버전 컨트롤이 가능한 장점도 있습니다

명령형, 선언형의 비교

IaC를 지원해주는 툴은 꽤 다양하게 존재합니다.
(Ansible, Puppet, Terraform, Chef, Saltstack, CloudFormation… 등등)

IaC 는 명령형 혹은 선언형 두 가지로 나뉘는데, 언급된 모든 툴들이 두 가지 중 하나의 접근방식을 특징으로 가지고 있습니다. 목적은 인프라를 구성할 때 원하는 구성을 만드는 것입니다.

명령형
원하는 구성을 만들기 위한 명령들을 정의합니다.

선언형
원하는 구성 자체를 정의합니다.

각각의 접근 방식에 대한 비교를 위해 접근 방식별로 실제 인프라 구성을 진행해보겠습니다

아래 예시는 이해를 돕기 위한 의사 코드(pseudo-code)입니다.

명령형

t3.micro 타입의 EC2 리소스를 3대 시작.

AWS.EC2.Start(type = "t3.micro")
AWS.EC2.Start(type = "t3.micro")
AWS.EC2.Start(type = "t3.micro")

선언형

t3.micro 타입의 EC2 리소스가3대

AWS:
EC2:
type: t3.micro
count: 3

3개의 동일한 타입인 EC2가 를 시작합니다. 지금은 차이가 보이지 않습니다. 각 방식에 대한 차이는 두번째 실행부터 나타나기 시작합니다.

명령형

현재 구성: EC2 t3.micro * 3

AWS.EC2.Start(type = "t3.micro")
AWS.EC2.Start(type = "t3.micro")
AWS.EC2.Start(type = "t3.micro")

선언형

현재 구성: EC2 t3.micro * 3

AWS:
EC2:
type: t3.micro
replica: 3

명령형: EC2 리소스가 3개가 있는 상태에서 EC2 리소스 3개를 추가로 더 시작했고, 최종 상태는 EC2 리소스가 6개가 되었습니다.

선언형: 최종 상태를 EC2 리소스 3대로 정의해두었고 현재도 EC2 리소스가 3대이니, 변경을 위한 액션은 발생하지 않습니다

29CM의 Terraform

29CM에는 EKS 전환 당시 기존에 구성 되어 있던 클러스터가 있었습니다. 여러가지 이유로 인해 EKS 전환 의사결정이 되었고 EKS 클러스터를 새로 구축해야하는 상황이었습니다.

29CM 의 EKS 클러스터 구성 당시 선택 후보군은 Ansible, Terraform, eksctl(CloudFormation 기반) 이었습니다.

eksctl 제외

인프라 구성 시 Vendor Lock-in 을 최대한 피하려고 노력하고 있습니다. eksctl 을 이용한다면 AWS 라는 Vendor Lock-in 이 강하게 걸린다는 점에서 제외했습니다.

다른 툴을 이용해도 모듈의 변경 등으로 인해 코드 자체를 그대로 재사용하긴 어렵지만 기본적으로 사용되는 변수등은 그대로 이용 가능하며 툴의 사용 경험까지 해치지는 않기 때문에 eksctl 를 제외했습니다.

Ansible 제외

Ansible과 Terraform 사이에서 어떤 툴을 사용해야할지 많은 고민이 있었습니다. 두가지 모두 비슷한 기능들을 지원하고 있고 둘 중 어떤걸 사용해도 구성이 가능했습니다.

Ansible 은 명령형 방식과 선언형 방식 두가지 모두 지원하는 하이브리드 형태이지만 Configuration Management 에 특화되어 있습니다.

반면에 Terraform 은 불변성에 맞춰 설계가 되어있고 이런 점이 불변 인프라(Immutable Infrastructure) 에 가장 잘 맞는다고 판단 했습니다. 또한 선언형 방식으로 인프라 구성을 직관적으로 파악할 수 있다는 장점이 있습니다.

위 특성으로 인해 각각의 장점을 살려 두가지를 혼용 사용하는 경우도 많습니다. 하지만 29CM의 대부분의 서비스들은 쿠버네티스 환경 위에 동작되고 있습니다. 그래서 대부분의 서비스가 컨테이너화 되어 동작되고 있고 EKS 클러스터를 이용하기 때문에 각각의 노드에 별도의 Configuration이 필요하지 않았습니다.

위 이유로 29CM 은 Terraform 을 이용해 인프라를 구성하고있습니다.

Terraform 맛보기

Hashicorp 에서 개발한 Terraform 은 hcl 이라는 자체 문법을 가지고 있습니다. 기본적인 Syntax는 아래와 같습니다.

<BLOCK TYPE> "<BLOCK LABEL>" "<BLOCK LABEL>" {
# Block body
<IDENTIFIER> = <EXPRESSION> # Argument
}

다양한 Block Type 이 존재하는데, 가장 기본적인 키워드는 크게 세가지로 구분됩니다.

  • Resource
    프로비저닝 하려는 대상 리소스를 명시합니다.
  • Data
    외부에서 생성 되었거나 Terraform 구성에 의해 정의 되거나 기능에 의해 수정된 정보의 리소스를 가져옵니다.
  • Module
    여러 리소스의 묶음을 컨테이너화 시켜 제공 해줍니다.

이 외에 provider나 local, variable 등 여러가지 Block Type 이 존재합니다.

EC2 구성 예시

Terraform 사용 전에 awscli 의 설치와 설정이 필요합니다. 해당 과정은 본 글에서는 다루지 않겠습니다. Terraform 의 설치 과정도 다루지 않겠습니다.

먼저 aws provider를 설정합니다. 해당 선언을 통해 패키지를 다운받을 수 있습니다.

terraform {  
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.27"
}
}
required_version = ">= 0.14.9"
}
provider "aws" {
region = "ap-northeast-2"
}

다음 명령어를 통해 패키지를 다운받습니다.
(.terraform 디렉터리 하위에서 다운받은 리소스를 확인할 수 있습니다.)

$ terraform init

이제 간단하게 EC2 인스턴스를 한대 만들어 보도록 하겠습니다.
EC2 인스턴스를 만들때에는 여러가지의 리소스가 필요합니다.

  • VPC, Subnet
  • SecurityGroup
  • AMI
  • EBS

필요 시 더 많은 옵션을 지정할 수도 있습니다.

AMI를 지정하여 EC2 인스턴스를 만들도록 구성해보겠습니다.
예시 코드는 테라폼 공식 홈페이지에서 발췌했습니다. (링크)

data "aws_ami" "ubuntu" {
most_recent = true

filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}

filter {
name = "virtualization-type"
values = ["hvm"]
}

owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"

tags = {
Name = "HelloWorld"
}
}

위 예시 코드를 해석해보면 “aws_ami” 리소스를 data로 불러오고 있습니다.
이름과 가상화 지원 타입으로 필터를 거쳐 조회한 리소스를 ubuntu라고 라벨링 합니다. 선언된 이후에는 “data.aws_ami.ubuntu” 로 해당 리소스의 Output을 참조 가능합니다.

위와 같이 설정한뒤 후에 “terraform plan” 명령어를 실행하면 실행계획을 확인할 수 있습니다. “terraform apply” 명령어를 실행하면 설정에 대한 실행 계획을 보여주고 이 후 커멘드에서 Yes 를 입력하면 해당 실행 계획에 맞춰 변경 사항을 적용하게 됩니다

Terraform은 선언형 방식을 사용하고 있어서 여러번 적용하더라도 정의한 스펙 자체를 그대로 구성해주어 매우 직관적입니다.

EKS 클러스터 만들기

간단히 EC2 만 프로비저닝 해도 정의하고 가져와야할 리소스가 굉장히 많은데 EKS 의 경우는 필요한 리소스 정의가 더 많습니다. 이때 모듈을 이용하면 불필요한 작업을 생략하고 보다 쉽게 구성이 가능합니다.

저희는 EKS 모듈 을 이용해 EKS 클러스터를 만들어 보겠습니다.
이전과 마찬가지로 모듈의 페이지에 제공되는 예시를 이용합니다. (링크)

module "my-cluster" {
source = "terraform-aws-modules/eks/aws"
cluster_name = "my-cluster"
cluster_version = "1.20"
subnets = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"]
vpc_id = "vpc-1234556abcdef"

worker_groups = [
{
instance_type = "m4.large"
asg_max_size = 5
}
]
}

모듈은 Resource들의 컨테이너로 내부에서 여러가지 Resource를 정의하고 있습니다. 구성 스펙에서 VPC와 Subnets 의 id 들은 각각에 맞게 변경하여 사용이 가능하고 data 선언을 통해서도 id들을 획득할 수 있습니다.

worker_groups는 EKS에서 Unmanaged NodeGroup이며, AutoScaleGroup을 통해 클러스터에 Join 하는 m4.large 타입의 EC2인스턴스 5대를 구성합니다.

Managed NodeGroup을 이용하는 경우는 “node_groups” 키를 사용하며, 구성 시 EKS 웹 콘솔에서 컴퓨팅 리소스를 확인할 수 있습니다.

모듈의 모든 옵션은 모듈 페이지에서 확인 가능합니다.

위와 같이 간단한 코드만으로 Terraform을 이용해 클러스터를 손쉽게 구축할 수 있고 관리 또한 손쉽게 가능합니다.

함께 성장할 동료를 찾습니다

29CM ((주)무신사)는 3년 연속 거래액 2배의 성장을 이루었습니다.
이제 더 큰 성장을 위해 기존 모놀리틱 서비스 구조를 마이크로서비스 구조로 전환하고, 앵귤러 기반 프론트엔드 코드를 리액트로 전환하는 등의 기술적인 시도를 진행하고 있습니다. 모바일 앱 내부 구조도 모듈러 아키텍처로 개선하는 과정에 있습니다. 함께 성장하고 유저 가치를 만들어낼 동료 개발자분들을 찾습니다.

🚀 29CM 채용 페이지 : https://www.29cmcareers.co.kr/

--

--