지난번 포스팅에서 테라폼에 대한 전반적인 개념에 대해 다뤄봤다.
이번 포스팅에서는 AWS 리소스를 테라폼을 사용해서 프로비저닝 하는 법을 알아보겠다.
STEP 1 - AWS 계정 설정
위 페이지에서 AWS 계정을 생성한다. 처음에 계정을 생성하게 되면 Root(루트)계정이 생성된다.
루트 계정에서 액세스 키를 발급받고 이후 과정을 진행해도 되지만,
루트 계정에서 엑세스 키를 발급받아 직접 사용하는것은 권장하지 않는다.
권장방법으로 IAM 사용자를 생성하고 권한을 부여하여 진행하는 것을 추천한다.
STEP2 - AWS 프로비저닝 (EC2, RDS)
이제 Terraform을 사용해 필요한 리소스를 설정해보자 해당과정은 3개의 작은 과정으로 나뉘어져있으며 설정하는 리소스에 별로 반복해 나간다.
과정1 - 인프라스트럭처를 HCL언어를 사용하여 리소스를 정의한다.
과정2 - 정의된 리소스들이 생성가능한지 Plan을 실행한다.
과정3 - 정의된 리소스들을 aws에 적용한다.
EC2와 RDS를 프로비저닝 하는 것을 목표로 위 과정을 반복한다.
EC2, RDS를 생성하기위해 필요한 리소스들은
'IAM의 키페어' , '보안그룹', 'EC2 인스턴스 타입', 'DB 인스턴스 타입' 이 있다.
필요한 리소스들을 아래와 같은 방법으로 설정해준다.
먼저 테라폼의 .tf 파일을 관리할 프로젝트 디렉터리를 만들어주고 파일을 생성한다.
$ mkdir aws_web_infra
$ cd aws_web_infra
$ touch provider.tf aws_web_infra_setting.tf
디렉터리와 파일이름을 지을때는 따로 원칙이 있는 것이 아니다.
테라폼은 사용하는 디렉터리에 있는 .tf확장자를 가진 파일 전부를 읽어들인 후
리소스생성, 수정, 삭제 작업을 진행한다.
때문에 파일명을 목적에 따라 적절하게 잘 나누어줄 필요가 있다.
먼저 provider를 설정해주는 파일을 만들어준다. 위에서 touch provider.tf를 통해 파일을 만들어준 후 아래와 같이 프로바이더로 aws를 설정해준다.
provider "aws" {
access_key = "<AWS_ACCESS_KEY>"
secret_key = "<AWS_SECRET_KEY>"
region = "ap-northeast-2"
}
STEP3 - 테라폼 초기화 및 리소스 설정
테라폼 버전을 0.10 이상을 사용하고 있다면 별도의 초기화가 필요하다.
이유는 버전 0.10 부터 프로바이더가 플러그인으로 분리되면서 초기화를 통해 새로 설정한 리소스들을 반영하고 필요한 플러그인을 설치해야 하기 때문이다.
aws_web_infra 디렉터리로 이동 후 terraform init 명령어를 실핸한다.
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.53.0...
...
Terraform has been successfully initialized!
step 3 - 1 : HCL로 필요한 리소스를 정의한다.
HCL 를 사용하여 리소스를 정의하는 방법은 프로바이더를 설정했던 방법과 비슷하다.
aws_web_infra_setting.tf 파일에 다음 내용을 추가해준다.
resource "aws_key_pair" "web_admin" {
key_name = "web_admin"
public_key = "<PUBLIC_KEY>"
}
resource 이후 나오는 aws_key_pair와 web_admin은 각각 리소스 타입과 리소스의 이름을 뜻한다.
즉, aws_key_pair라는 리소스를 정의할것이고 이를 web_admin이라는 이름을 붙여 관리하겠다는 것이다.
나중에 키페어 리소스를 관리할때 aws_key_pair.web_admin과 같은 형식으로 참조하게된다.
*즉 테라폼 코드에서 다른 리소스와 해당 리소스를 구별하기 위해 사용하는 이름이다.
이후 key_name은 aws상에 현재 정의하는 키 페어를 등록할 이름이다.
public_key에는 접속에 사용할 공개키의 값을 넣어야한다.
공개키 만든 후 file() 함수를 사용하여 파일 경로를 문자열로 넣어준다.
ex) public_key = file("~/.ssh/web_admin.pub")
step 3 - 2 : 설정한 리소스들이 생성가능한지 plan을 통해 확인
앞에서 aws_key_pair 에 대한 리소스를 정의 했다.
terraform plan 명령어를 통해 설정한 리소스를 실제로 aws에서 생성할 수 있는지 확인한다.
프로젝트 디렉터리에 위치 한 후 terraform plan 명령어를 실행한다.
테라폼의 plan은 .tf파일에 설정해놓은 모든 리소스를 읽어들이고 해당 리소스가 존재한다고 가정한다.
리소스가 존재한다는 가정을 이상적 상태라 생각하고 이 상태가 실제로 적용된 상황을 실제 상태라 생각하면
plan의 작동 방식을 이해하기 쉽다.
아래 그림을 보면 .tf파일에 설정해놓은 리소스를 이상적 상태에 생성한다.
❯ terraform plan
...
Terraform will perform the following actions:
# aws_key_pair.web_admin will be created
+ resource "aws_key_pair" "web_admin" {
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = "web_admin"
+ key_pair_id = (known after apply)
+ public_key = "ssh-rsa ...."
Plan: 1 to add, 0 to change, 0 to destroy.
명령어를 실행 한후 마지막 줄을 보면 Plan 부분에 1개의 Plan이 추가 된것을 확인 할 수 있다.
step 3 - 3: 설정한 리소스를 실제 AWS에 Apply
이제 Plan을 통해 확인한 내용을 실제로 프로바이더(여기서는 aws)에 적용해보자
terraform apply 명령어를 통해 적용한다.
$ terraform apply
...
Terraform will perform the following actions:
# aws_key_pair.web_admin will be created
+ resource "aws_key_pair" "web_admin" {
+ fingerprint = (known after apply)
+ id = (known after apply)
+ key_name = "web_admin"
+ key_pair_id = (known after apply)
+ public_key = "ssh-rsa ..."
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
aws_key_pair.web_admin: Creating...
aws_key_pair.web_admin: Creation complete after 0s [id=web_admin]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
여기까지의 과정을 요약하자면,
프로바이더 (ex. aws, gcp, azure) 등을 먼저 설정해주고 이후 필요한 리소스에 대한 .tf 파일을 만든 후
위의 step 3 - 1 ~ 3 을 반복하여 실제 상태로 리소스를 구현한다.
4. SSH 접속을 위한 보안그룹 설정
아래의 내용을 aws_web_infra_setting.tf 의 아래 부분에 추가해준다.
resource "aws_security_group" "ssh" {
name = "allow_ssh_from_all"
description = "Allow SSH port from all"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
내용을 요약하자면 aws_security_group의 이름을 "ssh"로 명해주고 속성을 설정한다.
name은 보안그룹 이름과 description은 보안그룹 설명이다.
ingress는 보안그룹의 인바운드 트래픽을 설정하는 부분이다.
ingress에서는 from_port, to_port, protocol, cidr_blocks 속성을 지정합니다.
from_port와 to_port는 열어줄 포트의 범위를 의미한다.
from_port = 30
to_port = 35
이면
30~35까지 6개의 포트를 열어준다는 뜻이다.
protocol은 통신에 사용할 프로토콜을 설정하는 곳이다.
cidr_block은 사이더 범위를 지정해주는 곳이다.
위처럼 리소스를 설정해주었다면
terraform plan -> terraform apply 해준다.
5. EC2 인스턴스 정의
이제는 WEB서비스를 올릴 EC2를 테라폼을 통해 프로비저닝 해보자
EC2의 리소스를 설정하기 전에 먼저 추가적으로 해줘야할 작업이 있다.
AWS EC2 콘솔창에서 EC2를 생성할때 보안그룹을 설정하게 되는데
우리는 앞서 보안 그룹 리소스를 먼저 설정해 놓았다.
때문에 해당 설정을 재사용하여 EC2 리소스가 참조할 수 있게 해주자
data "aws_security_group" "default_security" {
name = "default"
}
이제 "default_security" 라는 이름으로 설정해놓은 보안그룹을 사용할 수 있다.
이제 인스턴스 리소스를 설정해보자
resource "aws_instance" "web_service" {
ami = "ami-0a93a08544874b3b7" # amzn2-ami-hvm-2.0.20200207.1-x86_64-gp2
instance_type = "t2.micro"
key_name = aws_key_pair.web_admin.key_name
vpc_security_group_ids = [
aws_security_group.ssh.id,
data.aws_security_group.default_security.id
]
}
위의 리소스 설정에서 ami, instance_type, key_name, vpc_secrurity_group_ids 4개의 리소스를 설정한다.
ami = 어떤 머신 이미지를 사용할 것인가? (aws linux / unbuntu / window)
instance_type = ec2 인스턴스의 타입
key_name = ec2 키페어
vpc_secrurity_group_ids = 보안그룹
여기서 주의깊게 살펴봐야 할 부분은 key_name 부분에서 aws_key_pair.web_admin 이라는 변수를 사용해준것이다.
aws_key_pair.web_admin.key_name
을 보면 먼저 앞서 설정해준 aws_key_pair.web_admin리소스에서 key_name부분을 사용할 것이라는 것을 알 수 있다.
이런식으로 리소스의 속성을 참조하여 사용하는 이유는 크게 2가지가 있다.
첫번째로 어떤 리소스의 속성을 참조했는지 쉽게 확인하기 위해서이다.
두번째 이유가 중요한데, 바로 속성끼리의 의존 관계를 정의하기 위해서이다.
A리소스의 속성을을 참조하는 B리소스가 있다.
B리소스는 A리소스에 의존적이게 되고 여기서 의존관계가 형성되고 B리소스가 참조하는 A리소스의 속성은 B리소스 중에서도 먼저 생성되는것이 보장이 된다.
쉽게 말하면, aws_key_pair 부분이 aws_instance.web 부분보다 먼저 생성된다는 뜻이다.
vpc_security_group_ids 부분에서 두번째 속성값도 똑같다.
앞서 설정한 default_security 데이터 값에 id를 참조한다는 뜻이다.
이후 똑같이
terraform plan -> terraform apply 해준다.
6. RDS 인스턴스 설정
RDS 리소스를 아래와 같이 설정 해주자
resource "aws_db_instance" "web_db" {
allocated_storage = 8
engine = "mysql"
engine_version = "5.6.35"
instance_class = "db.t2.micro"
username = "admin"
password = "<DB_PASSWORD>"
skip_final_snapshot = true
}
위의 리소스를 통해 아래와 같은 설정을 할 수 있다.
* allocated_storage
할당할 용량(기가바이트 단위)
* engine
데이터베이스 엔진
* engine_version
사용할 데이터베이스 엔진 버전
* instance_class
인스턴스 타입(RDS 인스턴스 타입만 사용 가능)
* username
계정 이름
* password
암호. <DB_PASSWORD>는 자신이 사용할 값으로 적절히 변경해줍니다. 이 암호는 tfstate 파일에 저장되므로 임시로 사용할 것을 권장합니다. 데이터베이스에 접속해서 직접 실제 사용할 값을 변경해주세요.
* skip_final_snapshot
인스턴스 제거 시 최종 스냅샷을 만들지 않고 제거할 지를 결정합니다. 기본값은 false입니다. 단, 이 경우 테라폼에서 인스턴스 삭제가 어려우므로, 여기서는 true를 지정해줍니다.
내용 출처:
위와 같이 rds 리소스를 설정해주었다면
이후 똑같이
terraform plan -> terraform apply 해준다.
최종적으로 앞서 만든 2개의 파일에 아래와 같은 소스 코드가 완성되었다.
provider.tf
provider "aws" {
access_key = "<AWS_ACCESS_KEY>"
secret_key = "<AWS_SECRET_KEY>"
region = "ap-northeast-2"
}
aws_web_infra_setting.tf
resource "aws_key_pair" "web_admin" {
key_name = "web_admin"
public_key = file("~/.ssh/web_admin.pub")
}
resource "aws_security_group" "ssh" {
name = "allow_ssh_from_all"
description = "Allow SSH port from all"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
data "aws_security_group" "default" {
name = "default"
}
resource "aws_instance" "web_service" {
ami = "ami-0a93a08544874b3b7" # amzn2-ami-hvm-2.0.20200207.1-x86_64-gp2
instance_type = "t2.micro"
key_name = aws_key_pair.web_admin.key_name
vpc_security_group_ids = [
aws_security_group.ssh.id,
data.aws_security_group.default.id
]
}
resource "aws_db_instance" "web_db" {
allocated_storage = 8
engine = "mysql"
engine_version = "5.6.35"
instance_class = "db.t2.micro"
username = "admin"
password = "<DB_PASSWORD>"
skip_final_snapshot = true
}
7. 프로비저닝한 인프라를 일괄 처리
이처럼 IaC를 통해 인프라를 프로비저닝하면 얻을 수 있 는 장점이 있다.
바로 리소스들을 일괄 생성, 삭제할 수 있다는 점이다.
일단 일괄 생성에 대한 부분은 위에서 확인 했으니 일괄 삭제에 대한 부분을 살펴보겠다.
먼저 앞서 생성한 2개의 파일중 aws_web_infra_setting.tf 파일을 잠시 다른 디렉터리로 옮겨놓는다.
이후 provider.tf 파일만 있는 상태에서 terraform plan을 실행하면 구성해놓은 리소스들이 삭제 된다.
$ terraform plan
...
- resource "aws_db_instance" "web_db" {
...
- resource "aws_instance" "web" {
...
- resource "aws_key_pair" "web_admin" {
...
- resource "aws_security_group" "ssh" {
Plan: 0 to add, 0 to change, 4 to destroy.
테라폼의 원리는 plan을 통해 리소스를 이상적 상태에 올려두고 이를 apply 통해 실제 상태로 구현하는 것인데
이상적 상태에 올려 놓을 리소스가 없기 때문에 이와 실제 상태를 맞추기 위해 제거하는 것이다.
굳이 리소스를 설정해놓은 aws_web_infra_setting.tf 을 해당 디렉터리에서 삭제하지 않아도
terraform plan -destory 명령을 통해 위와 동일한 결과를 얻을 수 있다.
이후 위 상태를 적용하기위해 terraform destroy 명령어를 실행한다.
$ terraform destroy
...
- resource "aws_db_instance" "web_db" {
...
- resource "aws_instance" "web" {
...
- resource "aws_key_pair" "web_admin" {
...
- resource "aws_security_group" "ssh" {
Plan: 0 to add, 0 to change, 4 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
테라폼에 대한 개념을 잡아보는 포스팅을 해보았다.
aws 리소스에 한해서 진행해보았지만 IaC환경을 사용하여 리소스를
어떻게 프로비저닝하는지에 대해 감을 잡을 수 없었다.
하지만 직접 해보니 조금이나마 더 쉽게 이해할 수 있었다.
IaC란 인프라를 코드로 관리한다는 것이다.
이전에 IaC의 개념만 알았을때는 어떻게 인프라를 코드를 통해서 프로비저닝 할 수 있을까?
라는 생각을 했었는데 결국 직접 '테라폼'이라는 툴을 사용해보니 IaC의 실용성과 장점이 뚜렷하게 와닿았고
코드를 통해 인프라를 프로비저닝하고 관리하는 것이 얼마나 중요한지 알 수 있었다.
댓글