[Terraform@CloudNet] Terraform Provider

2024. 7. 6. 11:55EKS@Terraform

- CloudNet에서 주관하는 Terraform 스터디 내용입니다

- 내용은 위 책 테라폼으로 시작하는 IaC 를 기준으로 정리하였습니다.

- 실습은 M1 macbook air 에서 진행했습니다.

- 매번 좋은 스터디를 진행해 주시는 CloudNet 팀 감사드립니다

- 잘못된 점, 업데이트된 지식, 다른 코멘트 언제나 환영입니다!

 

 

Provider

테라폼의 프로바이더는 내가 쓴 코드와 대상(AWS, GCP, K8S...) 을 연결시켜 주는 역할을 한다.

테라폼은 인프라 파트너와 워크플로 파트너로 나눌 수 있다.

- 워크플로 파트너: GitHub, GitLab, Azar Devops, bitbucket 등으로 테라폼 실행 및 코드를 관리하는 부분

- 인프라 파트너: 사용자가 테라폼으로 대상 플랫폼의 API로 상호작용 가능한 리소스를 관리할 수 있도록 한다

    - 퍼블릭 클라우드

    - 컨테이너 오케스트레이션
    - IaaS

    - 보안/인증
    - CI/CD, 모니터링

등 다양한 기능을 지원한다.

 

 

 

아래 코드는 이전 실습에서 사용한 AWS 에서 VPC 를 배포하는 코드인데, Provider를 aws 로 지정하고 프로바이더가 필요로 하는 정보(연결과 인증) 를 제공해서 배포가 정상적으로 이뤄질 수 있도록 한다.

provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_vpc" "myvpc" {
  cidr_block       = "10.10.0.0/16"

  tags = {
    Name = "t101-study"
  }
}

 

https://malwareanalysis.tistory.com/619

실행과정을 순서대로 짚어보면

0. 테라폼 코드를 쓴다

1. 테라폼 코어에서 코드 실행순서를 설정한다

2. 1.의 순서대로 테라폼 코어 -> 플러그인(프로바이더, 프로비저너) 에게 RPC로 실행을 요청한다

3. 2.가 요청받은 클라이언트 라이브러리를 찾는다

4. 요청받은 대상에 요청받은 기능이 실행된다

 

 

프로바이더 목록은 링크에서 확인할 수 있다. 해시코프가 직접 소유 및 관리하는 official provider 외에도 partner, community provider로 나눠진다 (종류가 굉장히 많다...)

 

 

 

그런데 같은 프로바이더를 쓰더라도 조건을 다르게 지정해야 하는 경우가 있다.

AWS 를 사용하는데 같은 리소스를 다른 리전에 배포하는 경우가 대표적이다.

 

아래 테라폼 코드는 같은 t2.micro 인스턴스를 ap-southeast-1 / 2 리전에 각각 배포한다.

ap-southeast-1 은 싱가포르, ap-northeast-2는 서울이다.

같은 이미지이더라도 리전별로 ami-id 는 다르기 때문에 명시해줘야 한다

 

+ 실습 코드를 그대로 따라 배포하면 인스턴스에 이름이 없어서 tag 로 이름을 추가해줬다.

provider "aws" {
  region = "ap-southeast-1"
}

provider "aws" {
  alias = "seoul"
  region = "ap-northeast-2"
}

resource "aws_instance" "app_server1" {
  ami           = "ami-06b79cf2aee0d5c92"
  instance_type = "t2.micro"
  tags = {
    Name        = "singapore_ec2"
  }
}

resource "aws_instance" "app_server2" {
  provider      = aws.seoul
  ami           = "ami-0ea4d4b8dc1e46212"
  instance_type = "t2.micro"
  tags = {
    Name        = "seoul_ec2"
  }
}

 

테라폼 콘솔에서 배포가 잘 된 것을 확인한다.

테라폼 웹 콘솔에서도 리전별로 배포가 잘 된 것을 볼 수 있다(웹 콘솔에서는 리전 통합 조회가 어려운 듯 하다)

 

aws cli 에서도 아래 명령어로 현재 인스턴스들을 조회할 수 있다

aws ec2 describe-instances --filters Name=instance-state-name,Values=running --output table

 

 

 

 

프로바이더의 요구사항은 아래와 같이 정의할 수 있다.

프로바이더에 요구사항으로 넘겨줄 수 있는 정보에는 프로바이더 버전, 인증정보, 리전, 권한, 네트워크 등이 있다.

 

프로바이더는 terraform init 명령어로 실행(?) 된다. 따라서 프로바이더에 변화가 생겼다면 init 을 꼭 다시 해줘야한다.

terraform {
  required_providers {
    <프로바이더 로컬 이름> = {
      source = [<호스트 주소>/]<네임스페이스>/<유형>
      version = <버전 제약>
    }
    ...
  }
}

 

 

 

이번에는 보다 다양한 프로바이더를 직접 지정해서 다시한번 2개 리전에 ec2를 배포해보자.

사실상 위 코드와 같은 내용이지만 provider를 분리하고, 프로바이더에서 가져오는 정보를 한번 더 래핑해서 사용하는 것이 유지보수나 코드의 가독성에 유익한 것 같다. 사실 지난주 업무중에 실험용 스크립트를 날림으로 짰다가 디버깅에 엄청난... 시간을 써버려서 더 그래보이는 것 같기도 하다ㅠㅠ

 

단, 프로바이더 사용 시 주의해야 할 점은 

- 프로덕션 수준의 멀티리전은 쉽지 않다 : 지역간 지연시간, ID, 최종일관성을 고려해야 하기 때문에 완전 환경 격리가 권장됨.

- alias 를 사용해 단일 모듈을 두 리전에 배포하면 한 리전이 다운되었을 때 다른 리전에서도 plan/apply 가 모두 실패하므로 주의 필요.

 

우선 프로바이더 정보만 저장하는 provider.tf 를 저장한다.

provider "aws" {
  region = "ap-northeast-2"
  alias  = "region_1"
}

provider "aws" {
  region = "ap-southeast-1"
  alias  = "region_2"
}

data "aws_region" "region_1" {
  provider = aws.region_1
}

data "aws_region" "region_2" {
  provider = aws.region_2
}

data "aws_ami" "ubuntu_region_1" {
  provider = aws.region_1

  most_recent = true
  owners      = ["099720109477"] # Canonical

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

data "aws_ami" "ubuntu_region_2" {
  provider = aws.region_2

  most_recent = true
  owners      = ["099720109477"] # Canonical

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

 

그리고 위 provider를 사용해서 실제 리소스를 생성하는 ec2.tf 를 저장한다.

resource "aws_instance" "region_1" {
  provider = aws.region_1

  ami           = data.aws_ami.ubuntu_region_1.id
  instance_type = "t2.micro"
}

resource "aws_instance" "region_2" {
  provider = aws.region_2

  ami           = data.aws_ami.ubuntu_region_2.id
  instance_type = "t2.micro"
}

 

plan & apply 를 적용할 때 별도의 터미널에서 모니터링 코드를 띄워놓으면 각 리전에서 ec2가 배포되는 것을 확인할 수 있다.

# 배포
terraform init
terraform plan 
terraform apply -auto-approve

# [터미널1] ap-northeast-2
while true; do aws ec2 describe-instances --region ap-northeast-2  \
--query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" \
--filters Name=instance-state-name,Values=running 
--output text ; echo "------------------------------" ; sleep 1; done

# [터미널2] ap-southeast-1
while true; do aws ec2 describe-instances --region ap-southeast-1 \
--query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" \
--filters Name=instance-state-name,Values=running 
--output text ; echo "------------------------------" ; sleep 1; done

 

아래와 같이 서울/싱가폴 리전에 배포가 성공했을을 볼 수 있다.

 

 

 

graph 로 찍어보면 이렇게 프로바이더를 참조해서 ec2 가 배포되었음을 볼 수 있다.