Terraform으로 인프라스트럭처를 관리하면 기존보다 훨씬 체계적으로 관리할 수 있고 히스토리를 추적하기도 좋아지지만, 실제 인프라스트럭처를 직접 다루기 때문에 실수에 대한 걱정이 있는 것이 사실이다. 물론 이를 방지하기 위해 plan
으로 미리 확인해 볼 수 있지만 그래도 잘못 생각하고 apply를 해서 리소스가 제거된다거나 잘못 변경되어 장애가 난다거나 하는 가능성이 충분히 있다. 그리고 이게 애플리케이션이 아니라 인프라스트럭처의 설정이므로 일부 설정은 적용을 해봐야 동작 여부를 확인 가능한 것들이 있다. 그래서 항상 프로덕션에서 apply를 할 때는 두려움이 생겨서 2~3번씩 확인해 보게 된다.
특히 인프라스터럭처의 경우 소소한 변경은 다시 적용하면 되지만 리소스를 잘못 제거하면 장애가 크게 발생하거나 최악으로는 원래 상태로 롤백하기 어려운(혹은 오래 걸리는) 상황이 발생할 수 있다. 100% Terraform으로 관리하고 있다면 롤백 걱정이 줄어들겠지만 복잡한 회사 인프라스트럭처에서 100% 관리하에 두는 것은 쉽지 않다.
이렇게 Terraform을 사용하다 보니 인프라에서 프로덕션 외에 스테이징이나 테스트환경이 있으면 좋겠다는 생각이 자연히 들게 되었다. Infrastructure as code를 하다 보면 소프트웨어 개발에서 오랫동안 쌓아온 패턴을 거의 비슷하게 활용할 수 있다는 것을 알게 되는데 서버 애플리케이션을 배포할 때 코드를 배포판으로 만들어서 테스트 서버나 스테이징 서버에서 테스트하고 이상이 없으면 똑같은 코드를 프로덕션에도 배포하도록 배포 절차를 만드는 것이 일반적이다. 이를 통해 테스트한 소프트웨어가 프로덕션에 배포될 수 있게 보장하는 것인데 Terraform으로도 똑같이 하고 싶어졌다.
프로덕션 인프라스트럭처를 직접 조작하는 것이 부담되고 실수 가능성이 있으므로(특히, 민감한 설정 부분이라면 더욱...) 아예 VPC 레벨이나 계정 차원에서 테스트나 스테이징용 인프라스트럭처가 있고 이쪽에서 설정하고 설정이 이상 없음을 확인하면 같은 설정을 그대로 프로덕션 인프라스트럭처에 적용해서 안심하고 작업할 수 있게 하고 싶었다.(물론 제대로 되려면 여기서 프로덕션 적용은 자동화가 이루어져야 할 것이다.)
워크스페이스
Terraform에는 워크스페이스라는 기능이 있다. 이 기능은 Terraform 0.9 버전에서는 environment
라는 이름으로 존재했는데 environment
라는 단어의 의미가 모호하다는 이유로 0.10부터는 workspace
로 바뀌었다.
이 기능이 존재를 알았을 때부터 위에서 말한 문제를 해결할 수 있을지 확인해 보고 싶었다. 사실 테스트는 지난 9월 정도에 했지만, 블로그에 정리는 이제야 하게 된다.(어느새 2달이!)
Terraform을 사용할 때 인지할 수는 없지만 이미 워크스페이스 내에서 작업을 하고 있다. 기본 워크스페이스는 default
라는 이름을 가지는데 이 워크스페이스가 기본 이름이고 제거할 수 없다. 그래서 명시적으로 워크스페이스를 지정하지 않으면 default
워크스페이스를 사용하게 된다.
사용방법
terraform workspace
명령어를 사용하면 관련 명령어를 볼 수 있다.(여기서 사용하는 버전은 Terraform 0.11.0이다.)
$ terraform workspace
Usage: terraform workspace
Create, change and delete Terraform workspaces.
Subcommands:
show Show the current workspace name.
list List workspaces.
select Select a workspace.
new Create a new workspace.
delete Delete an existing workspace.
terraform workspace show
로 현재 워크스페이스가 default
임을 볼 수 있다.
$ terraform workspace show
default
terraform workspace list
를 입력하면 전체 워크스페이스의 목록을 볼 수 있고 현재 사용 중인 워크스페이스에 *
표시가 있음을 볼 수 있다.
$ terraform workspace list
* default
terraform workspace new WORKSPACE_NAME
으로 새로운 워크스페이스를 생성할 수 있다.
$ terraform workspace new demo
Created and switched to workspace "demo"!
You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
$ terraform workspace list
default
* demo
여기에 나온 대로 워크스페이스를 새로 생성하면 상태 파일(.tfstate
)이 분리된다. 같은 구성 파일(.tf
)을 사용하지만 상태 파일은 분리가 되므로 별도로 관리할 수 있게 된다.
$ terraform workspace select default
Switched to workspace "default".
terraform workspace select WORKSPACE_NAME
로 git에서 브랜치를 바꾸듯이 워크스페이스를 변경할 수 있다.
워크스페이스의 활용
앞에서 말한 문제를 해결하려고 어떻게 사용 가능한지를 간단히 테스트해보자.
resource "aws_s3_bucket" "main" {
bucket = "outsider-test${terraform.workspace == "default" ? "-stage" : "-${terraform.workspace}"}"
acl = "private"
versioning = {
enabled = true
}
}
위는 S3 버킷을 만드는 간단한 Terraform 구성 파일이다. 워크스페이스 개념 자체는 간단하므로 예시로 너무 복잡한 구성을 사용하면 이해하기가 어려울 것 같아서 다른 의존성이 별로 없는 S3 버킷을 예제로 선택했다. VPC나 EC2 등에서 사용하려면 Terraform 구성파일을 잘 작성하는 것만이 남은 작업이 될 것이다.
여기서는 S3 버킷을 만드는데 중요한 부분은 다음 부분이다.
outsider-tf-demo${terraform.workspace == "default" ? "-test" : "-${terraform.workspace}"}
terraform.workspace
는 현재의 워크스페이스 이름을 담고 있는 변수다. 이 값을 비교해서 여기서처럼 워크스페이스에 따라 다른 이름을 줄 수 있다. 다른 경우라면 워크스페이스 이름을 보고 다른 Security Group을 지정하거나 VPC를 다르게 지정하거나 할 수 있다.
아무런 작업을 하지 않으면 default
워크스페이스를 사용하므로 실수를 방지하기 위해서 default
를 테스트 용도로 사용하고 프로덕션 등 다른 환경을 위해서는 워크스페이스를 명시적으로 변경해서 하도록 했다. 그래서 여기서 버킷 이름이 outsider-tf-demo
를 접두사로 쓰는데 기본 워크스페이스에서는 outsider-tf-demo-test
가 버킷 이름이 되고 production
워크스페이스라면 outsider-tf-demo-production
이 버킷 이름이 된다.
$ terraform workspace list
* default
demo
$ terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ aws_s3_bucket.main
id: <computed>
acceleration_status: <computed>
acl: "private"
arn: <computed>
bucket: "outsider-test-stage"
bucket_domain_name: <computed>
force_destroy: "false"
hosted_zone_id: <computed>
region: <computed>
request_payer: <computed>
versioning.#: "1"
versioning.0.enabled: "true"
versioning.0.mfa_delete: "false"
website_domain: <computed>
website_endpoint: <computed>
Plan: 1 to add, 0 to change, 0 to destroy.
default
워크스페이스인 상태에서 terrafom plan
을 하면 S3 버킷 이름이 outsider-test-stage
가 된 것을 볼 수 있다. 당연히 apply
하면 이 이름 그래도 적용이 되므로 여기서는 plan
까지만 했다.
$ terraform workspace new production
Created and switched to workspace "production"!
You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
$ terraform workspace list
default
demo
* production
$ An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ aws_s3_bucket.main
id: <computed>
acceleration_status: <computed>
acl: "private"
arn: <computed>
bucket: "outsider-test-production"
bucket_domain_name: <computed>
force_destroy: "false"
hosted_zone_id: <computed>
region: <computed>
request_payer: <computed>
versioning.#: "1"
versioning.0.enabled: "true"
versioning.0.mfa_delete: "false"
website_domain: <computed>
website_endpoint: <computed>
Plan: 1 to add, 0 to change, 0 to destroy.
이번에는 production
이라는 워크스페이스를 만든 뒤에 plan
을 하면 S3 버킷 이름이 outsider-test-production
로 바뀐 것을 볼 수 있다.
구성 파일은 하나도 바꾸지 않은 상태에서 워크스페이스의 변경만으로 상태를 별도로 관리하면서 워크스페이스에 따라 달라지는 값을 다르게 줄 수 있게 되었다. 하나의 구성파일을 잘 만들어 놓고 S3 버킷에 원하는 정책이랑 설정을 하고 스페이징에서 테스트를 마친 뒤에 이상이 없다는 게 확인되면 워크스페이스를 production으로 변경해서 프로덕션 인프라스트럭처에 적용할 수 있다.
이렇게 하면 구성파일을 하나로 관리할 수 있으니 스테이징과 프로덕션의 인프라를 완전히 같게 맞춰놓을 수 있고 스테이징에서 테스트를 마친 뒤에 프로덕션에 적용할 수 있으므로 좀 더 적극적으로 인프라스트럭처를 개선하면서도 프로덕션에서 장애가 발생할 확률을 줄일 수 있다.
일단 워크스페이스를 쓰면 내가 고민했던 문제를 해결할 수 있다는 것은 알았지만 실제 구성 파일은 S3보다 훨씬 더 복잡하므로 구성파일을 작성하는데 초기에는 좀 더 큰 노력이 들 것 같다. 그리고 프로덕션 적용을 자동화해야 더 의미가 있는데 이 부분까지 구축하는 것은 꽤 큰 작업이기는 하다.
Comments