Search

Terraform Cloud(TFC) 맛보기

드디어 스터디에서 Terraform Cloud(TFC)를 다룬다. 어떤 기능이 있을까  또 free tier cap을 얼마나 낮을까 . 이 글에선 state를 관리할 수 있는 백엔드로써 TFC 사용에 대해 설명한다. 그리고 그것을 활용한 스터디 실습과 도전과제 풀이를 한다.

TFC 워크스페이스 구성

TFC에 가입한다. 첫 조직(Organization)을 생성한다.
TFC를 백엔드로 사용하려는, 기존에 로컬에 있는 테라폼 프로젝트에서 로그인을 시도한다.
tf login
Shell
복사
yes 프롬프트가 뜨고 yes를 입력하면 로그인 할 수 있는 토큰 생성 페이지로 브라우저 리다이렉션한다.
경고문처럼 토큰은 다시 볼 수 없으니, 바로 복사해서 다시 터미널로 돌아가 붙여 넣자. 토큰 입력을 기다리는 프롬프트가 떠 있다.
그리고 다음 terraform.cloud 블록을 추가하고 프로젝트를 다시 초기화한다.
terraform { cloud { organization = "flavonoyeelleesam" # 조직명 workspaces { name = "terraform-edu-part1-assessment" # 워크스페이스명 } } required_providers { ... } }
Ruby
복사
tf init
Shell
복사
TFC 웹 콘솔에서 워크스페이스가 생겼음을 확인한다. 프로젝트는 조직의 기본(default) 프로젝트가 된다.
Workspace Settings > General > Execution mode > Custom.Local 을 선택한다. 이렇게 하면 plan / apply 의 실행과 출력이, 기존 로컬 테라폼 프로젝트처럼, 실행한 터미널에서 이뤄진다. default는 Remote, TFC에서 원격으로 실행, 출력하지만, 실습 편의상 이렇게 구성한 것 같다.
문득 이런 생각이 들었다.
1.
IaC 하려고 테라폼의 클라우드 리소스를 콘솔로 만들고 있네. 이것도 IaC 가능한가?
2.
그걸 테라폼 ‘자체’로 할 수 있을까?(e.g. ArgoCD가 스스로를 관리하는 패턴)
2번은 아직 해법이나 사례를 모르겠다. 하지만 1번은 가능하다. 테라폼 tfe 프로바이더를 써서.
resource "tfe_organization" "flavonoyeelleesam" { # 조직 name = "flavonoyeelleesam" email = "flavono123@gmail.com" } resource "tfe_workspace" "terraform_edu_part1_assessment" { # 워크스페이스 name = "terraform-edu-part1-assessment" organization = tfe_organization.flavonoyeelleesam.name execution_mode = "local" # 실행 모드 설정 }
Ruby
복사
지금까지 콘솔로 한 작업은 위 구성으로 표현할 수 있다.
아무튼 이렇게 구성하면 state(.tfstate 파일)을 TFC에 생성, 관리된다. 워크스페이스 > States에서 확인할 수 있다.
우측 상단 버튼으로 Lock/Unlock도 가능하다. AWS 백엔드 사용 시 S3 버킷의 버저닝 활성화 그리고 DynamoDB를 통한 lock 기능이 TFC hosted로 구현돼 있다. 아마 뒤에선 AWS(같은 서비스?)를 쓰고 있지 않을까 예상해본다.

실습  →

목표 : 아래 깃허브 저장소를 복제해 아래 조건에 만족하는 코드를 작성
조건
1.
Terraform Cloud를 State 백엔드로 구성
Workspace 이름 : terraform-edu-part1-assessment
실행 모드는 local
2.
AWS 공통 Tag : Project = “workshop”
3.
aws_instance는 반복문을 사용해 3개 구성
4.
EIP를 제거하고 EC2에서 public ip를 자체 사용하도록 구성
5.
placeholder 변수는 아래 3가지가 각각의 aws_instance에 적용되도록 구성
placekitten.com placebear.com placedog.net
Bash
복사
풀이 예제는 ‘example’ 브랜치에 있다. 조건에 맞게 작성한 코드와 비교해보고 더 나은 방안을 찾아보자!
반복문에 count와 for_each를 활용할 수 있다
module을 활용하는 방안도 있다
문제로 내어준 조건은 위와 같다. 따라서 앞서 terraform.cloud 블록은 문제의 포크한 레포에서 구성했고, 1번에 대한 풀이를 한 것이다.
2번은 provider.aws.default_tags 에 값만 바꿈으로써 쉽게 풀 수 있다.
provider "aws" { region = var.region default_tags { tags = { Project = "workshop" } } }
Ruby
복사
3~5번은 세개의 인스턴스를 각각 로 띄우기 위한 요구사항이다. 난 모듈로 만들기로 했다. 모듈이 되어야 하는 부분은 aws_instance 와 안에서 프로비저닝을 위한 null_resource 두개 뿐이지만, 이런거 모듈로 감싸지 않으면 코드가 엉망이 되더라… 그리고 연습이기도 하니깐 좀 굳이? 라는 선택을 했다.
위 리소스 두개만 모듈화하려면, 4번의 조건, EIP를 제거해야 한다. aws_eip.hashicataws_eip_association.hashicat 을 제거하고, aws_eip.hashicat.public_ip 참조를 aws_instance.hashicat.public_ip 로 바꾼다. aws_instance.hashicat 가 이미 퍼블릭 서브넷에 있다.
9291c66beee6835b9efae473b1bda0a41a608c91
commit
그 다음은 모듈을 만들자.
1.
$GIT_ROOT/modules/hashicat 디렉토리 밑에 다음 파일 생성
main.tf
variables.tf
outputs.tf
2.
main.tf에 모듈에 포함할 리소스를 옮기고
aws_instance.hashicataws_instance.this
null_resource.configure-cat-app
3.
variables.tf는 다음과 같이 구성한다:
루트 모듈 vars 중 모듈에서 참조가 필요한 것은 그대로 넘겨준다.
prefix
instance_type
height
width
placeholder
그리고 루트 모듈의 리소스 중 모듈에서 참조가 필요한 vars를 새로 만든다. 크게 두 부분으로 나뉜다.
네트워크
subnet_id
vpc_segurity_group_id
(프로비저닝을 위한) SSH
key_name
private_key
4.
outputs.tf는 루트 모듈것을 그대로 옮긴다. 원래도 aws_instance.hashicat 의 attribute만 출력했기 때문
간단하게 설명했지만, 조금씩 옮기면서 validate , plan 심지어 apply 까지 돌려가며 검증했다. 운영 중인 서비스가 아니기 때문에. 복붙 후 크게 두 부분만 다르게 했다:
aws_instance.hashicataws_instance.this
리소스 attribute 직접 참조를 변수 참조로 변경
e.g. aws_key_pair.hashicat.key_namevar.key_name
그리고 data.aws_ami.ubuntu 도 같이 모듈에 넣었는데, 이 부분은 루트 모듈에 선언하고 hashicat 모듈엔 .id 만 변수로 넘겨주어도 될 것 같다.
모듈을 만든 후 반복문을 써서 호출도 위 커밋에서 한꺼번에 했다.
모듈 이름은 hashicats 로 선언하고
루트 var.placeholdervar.placeholders 로 변경
string → list
기본 값을 5번 요구사항으로 변경
variable "placeholders" { default = [ "placekitten.com", "placebear.com", "placedog.net" ] ... }
Ruby
복사
module.hashicatsvar.placeholders 길이만큼 반복문 선언 후 모듈 placeholder 에 인덱스 접근으로 하나씩 넣어 줌
module "hashicats" { source = "./modules/hashicat" count = length(var.placeholders) ... placeholder = var.placeholders[count.index] ... }
Ruby
복사
루트 모듈 outputs.tf 에서 module.hashicatscatapp_url/catapp_ip 를 순회하며 출력
output "catapp_url" { value = [ for hashicat in module.hashicats : hashicat.catapp_url ] } output "catapp_ip" { value = [ for instance in module.hashicats : instance.catapp_ip ] }
Ruby
복사
apply 후 나온 url이나 ip로 각각 접속하면 을 볼 수 있다.