Contents

다양한 단계의 인프라 지원의 필요

서비스 인프라를 구성 할 때, 프러덕션 인프라 하나만 구성하는 경우는 없다. CICD 환경울 구성했다면 최소 두 단계, 일반적으로 3단계의 인프라가 구성된다.
  • Dev : 개발용 애플리케이션들이 올라가는 환경. 각 개발자 로컬에서 기본적인 코딩과 테스트가 끝나면, DEV 인프라에 올려서 통합 테스트를 수행한다.
  • QA : Dev 인프라 에서 기본적인 테스트가 끝나면, QA 인프라에서 통합 테스트를 수행한다.
  • Production : QA까지 끝나면 실제 배포된다. 유저가 접근하는 인프라이다.
클라우드 환경에서는 인프라도 소프트웨어 구성요소다. 개발이 여러 단계를 거치는 것처럼, 인프라도 여러 단계를 거치면서 테스트, 피드백, 개선의 작업을 거쳐야 한다. 따라서 인프라도 동일한 코드가 여러 단계를 거치면서 개발을 지원하면서, 테스트, 검증, 프러덕션 환경에 배포되도록 관리해야 한다.

각 단계마다 테라폼 프로젝트를 가질 수도 있지만, 코드 관리가 어려워지고 동일한 코드를 구성하기가 어렵기 때문에 좋은 방법이 아니다. 테라폼에서 제공하는 workspace를 이용해서 이 문제를 해결 할 수 있다.

Terraform workspace

Chef, Ansible, Puppet 대부분의 형상관리 툴들은 환경(environment)를 이용해서, 하나의 코드를 여러 단계로 배포 할 수 있도록 한다. 기본 개념은 환경에 따라 다른 변수를 설정 하도록 하는데 있다. Terraform은 동일한 개념을 workspace라는 기능으로 제공하고 있다. Terraform도 0.9 버전까지는 environment 기능이었으나, 0.10 부터 기능 이름을 workspace로 변경했다. 아래 그림을 보자.

 Terraform workspace

VPC CIDR 변수를 map 타입으로 설정했다. 이제 workspace 설정에 따라서, 그에 맞는 CIDR이 선택된다.

terraform 프로젝트는 default라는 기본 workspace에서 시작한다. terraform workspace list 로 사용 할 수 있는 workspace 목록을 확인 할 수 있다.
# terraform workspace list       
* default

new 명령으로 workspace를 추가 할 수 있다. dev, qa, prod 세 개의 workspace를 추가해보자.
# terraform workspace new dev
Created and switched to workspace "dev"!

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 new qa 
# terraform workspace new prod 
 terraform workspace list
  default
  dev
* prod
  qa

select명령으로 workspace를 변경할 수 있다. dev로 변경해보자.
# terraform workspace select dev
Switched to workspace "dev".

# terraform workspace  list      
  default
* dev
  prod
  qa

workspace 사용

workspace를 이용해서 하나의 테라폼 코드로 dev, qa, product에 적용하는 예제를 만들어보자. 인프라는 구성은 아래와 같다.

 VPC 네트워크 구성

Private subnet, Public subnet 그리고 2개의 가용영역으로 구성된 일반적인 구성이다. 나는 이 구성을 joinc.co.kr서비스에 사용하려 한다. 또한 소프트웨어와 마찬가지로 Dev, QA, Production의 과정을 거칠 계획이다. Dev, QA, Prouction은 단계라고 표현하겠다.

나는 아래와 같은 인프라 계획을 수립했다.
  • 하나의 테라폼 코드로 Dev, QA, Production을 전개한다.
  • VPC CIDR : 10.100.0.0/16, 10.101.0.0/16, 10.102.0.0/16 네트워크를 구성한다.
  • VPC Subnet : Subnet크기를 자유롭게 설정 할 수 있어야 한다.
  • 태킹 : 태그에 해당 리소스의 위치,역할,사용 팀에 대한 정보를 저장한다. 이 정보는 자원 사용, 빌링 모니터링 및 레포팅에 사용한다.
3개의 workspace를 만들었다.
# terraform workspace  list      
* default
  dev
  prod
  qa

Workspace는 보간문map 두 가지 방법으로 사용 할 수 있다. 아래는 보간문을 사용한 예제다.

Map을 사용한 예제다. 보간문 보다는 map을 사용하는게 관리나 가독성 측면에서 더 나은 것 같다.

프로파일 관리

테라폼 프로젝트를 두 개 이상의 어카운트에서 사용해야 할 수도 있다. dev와 qa는 공통 어카운트를 사용하지만, production 레벨 어카운트는 보안과 관리상의 이슈로 다른 어카운트를 사용 하는 경우다. aws credential의 profile 이름을 workspace 이름과 일치시키는 방법이 있다.
[dev]
aws_access_key_id=AKIyyyyyyyyyyyyyyyyyyy
aws_secret_access_key=wJalxxxxxxxxxxxxxxxxxxxxxxxxxxxx

[prod]
aws_access_key_id=AKIzzzzzzzzzzzzzzzzzzzzz
aws_secret_access_key=je7kkkkkkkkkkkkkkkkkkkkkkkkkkkkkk

그리고 aws provider 블럭을 아래와 같이 설정하면 된다.

workspace를 적용한 테라폼 코드 만들기

이전에 만들어 놓은 terraform_multiaz을 수정하기로 했다.

variables.tf 에서 vpc_cidr 변수를 수정하기로 했다.

변수를 map으로 변경했다. 이에 맞춰 네트워크 리소스(vpc 및 subnet)의 테라폼 코드를 수정했다. workspace를 prod로 변경 한다음 terraform plan 명령을 실행하자.
# terraform workspace select prod
Switched to workspace "prod".
# terraform plan
plan 결과를 검토해보자.
terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

Error: Error running plan: 1 error(s) occurred:

* provider.aws: error validating provider credentials: error calling sts:GetCallerIdentity: NoCredentialProviders: no valid providers in chain. Deprecated.
	For verbose messaging see aws.Config.CredentialsChainVerboseErrors
prod credential 설정이 없다고 에러가 떨어진다. ~/.aws/config와 ~/.aws/credentials에 prod credential을 추가했다.
# cat ~/.aws/config
[profile prod]
region = ap-northeast-1
output = json

# cat ~/.aws/credentials
[joinc]
aws_access_key_id = AKxxxxxxxxxxxxxxxxxxxxxxxxxxxx
aws_secret_access_key = OAIzzzzzzzzzzzzzzzzzzzzzzzzzzzz

terraform plan을 실행한 결과다. 중요한 내용들만 간추렸다.
  + aws_vpc.default
      id:                                          <computed>
      arn:                                         <computed>
      assign_generated_ipv6_cidr_block:            "false"
      cidr_block:                                  "10.3.0.0/16"
      enable_dns_hostnames:                        "true"
      enable_dns_support:                          "true"
      instance_tenancy:                            "default"
      tags.%:                                      "1"
      tags.Name:                                   "VPC - prod"

  + aws_subnet.public[0]
      id:                                          <computed>
      arn:                                         <computed>
      assign_ipv6_address_on_creation:             "false"
      cidr_block:                                  "10.3.0.0/24"
      map_public_ip_on_launch:                     "false"
      tags.%:                                      "1"
      tags.Name:                                   "Public Subnet-prod-ap-northeast-2a"
      vpc_id:                                      "${aws_vpc.default.id}"
  + aws_subnet.public[1]
      id:                                          <computed>
      arn:                                         <computed>
      assign_ipv6_address_on_creation:             "false"
      cidr_block:                                  "10.3.1.0/24"
      map_public_ip_on_launch:                     "false"
      tags.%:                                      "1"
      tags.Name:                                   "Public Subnet-prod-ap-northeast-2b"
      vpc_id:                                      "${aws_vpc.default.id}"
prod 환경에 맞게 설정된 걸 확인 할 수 있다.
  • cidr_block : 10.3.0.0/16 네트워크로 설정됐다.
  • Tag : 태그 이름에 prod가 반영됐다. 지금은 테스트가 목적이라서, 태그이름을 대충 설정했다. 실제 개발환경에서 주의깊게 태그정책을 만들어야 할 것이다.
plan을 성공적으로 호출하면 아래와 같이 workspace 디렉토리가 만들어진다.
.
├── README.md
├── provider.tf
├── terraform.tfstate.backup
├── terraform.tfstate.d
│   ├── dev
│   ├── prod
│   └── qa
├── variables.tf
└── vpc.tf
테라폼 프로젝트마다 독립적인 워크스페이스를 관리할 수 있음을 의미한다.

정리

  1. workspace를 이용하면 하나의 코드로 여러 단계의 형상을 구성 할 수 있다.
  2. 아예 성격이 다른 프로젝트도 workspace를 이용해서 단일 코드로 관리 할 수 있을까 ? 여기에 대한 내 생각은 이렇다. "가능 할 지도 모르겠는데, 그렇게 하지 말자. 그냥 기존 테라폼코드 참고해서 새로 만들자". workspace는 단일 프로젝트에서 여러 단계의 형상을 관리하는 목적으로 하자. 코딩하는데, 서로 다른 프로젝트에서 코드를 그대로 재사용 하는 경우가 있던가 ? 새로 만들고, 몇 개 참고하지.