Terraform으로 재사용가능한 AWS 인프라 코드 만들기

Key Kim
13 min readOct 25, 2020

--

이번 포스팅에서 다룰 AWS 클라우드 아키텍처 및 전체 개관

클라우드 관련 프로젝트를 진행하면서 terraform을 사용하고 있습니다.

terraform을 사용할 때 한 개의 파일에 모든 기능을 다 넣어도 되지만, 기능을 모듈별로 분리하여 재사용 가능한 구조로 terraform을 사용하면 더 효율적으로 코드를 작성할 수 있습니다.

Workspace, Module을 활용해 재활용 가능한 테라폼 보일러플레이트를 만들어보겠습니다.

개발 환경

  • 사용된 소스코드
  • vscode
  • ubuntu 18.04 (WSL2, microsoft kernel)
  • docker-compose

terraform은 따로 설치하지 않고, docker를 사용해 구동합니다.

terraform을 설치해서 사용하셔도 무관합니다. 단 , Docker-compose에 기재된 /infra를 기준으로 절대경로가 고정되어 있어서 , terraform을 설치해서 사용하실 경우 모듈 경로를 모두 바꿔주셔야 합니다.

terraform-boilerplate를 아래 명령어를 이용해 clone 받으시거나

$ git clone https://github.com/KimKiHyuk/terraform-boilerplate.git

프로젝트 루트폴더에 아래와 같이 docker-compose 파일을 생성합니다.

docker-compose.yml

version: '3.7'services:  tf:    image: hashicorp/terraform:0.13.3    volumes:    - .:/infra    working_dir: /infra

프로젝트 구조

  • terraform/

— 루트 디렉토리

  • arch/

— 아키텍처를 모은 디렉토리

  • modules/

— 아키텍처에 사용될 서브모듈

  • scripts/

— 설치, 셋팅 스크립트

  • utility/

— 키페어 생성 등 유틸리티 모음

  • terraform.tfstate.d

— 현재 인프라 상태를 추적하기 위해 .tfstate 파일들을 모아둔 곳 입니다.

workspace 별로 각기 다른 인프라를 관리할 수 있습니다.

아키텍처

2개의 EC2 A, B를 만듭니다. A는 public subnet을, B는 Private subnet을 물려줍니다.

A에는 Nginx를 설치하고 80포트를 열어 웹 서버를 구축합니다.

B는 A에서만 접근 가능하고, 인터넷에서 B에 접근할 수 없지만, B는 인터넷에 접근할 수 있는 아키텍처를 Terraform으로 생성해보겠습니다.

Key Pair 생성하기

먼저 EC2에 접근할 수 있는 private key를 생성해보겠습니다.

프로젝트 루트 디렉토리에서 키페어를 위한 workspace를 생성합니다.

docker-compose run --rm tf workspace new keypair

workspace를 생성하면 방금 생성한 workspace로 자동 스위칭 됩니다.

list 명령어를 이용해서 확인해봅시다.

docker-compose run --rm tf workspace list

앞으로 작업하는 모든 변경 이력들은 terraform.tfstate.d/keypair/terraform.tfstate 에 저장됩니다.

이제 key pair를 생성해봅시다.

terraform/utility/aws/generate_key/main.tf

var.* 라고 기재된 부분들은 외부에서 입력되는 매개변수입니다.

매개변수로 access_key, secret_key, region, name을 입력받습니다.

terraform/utility/aws/generate_key/variables.tf

위에서 사용할 매개변수를 선언하는 코드입니다.

만약 매개변수가 들어오지 않는다면 default 키워드를 이용해 기본값을 설정할 수 있습니다.

terraform/utility/aws/generate_key/output.tf

테라폼이 실행된 후 결과값을 출력하는 코드입니다.

키 이름, private, public 키값을 출력해줍니다.

모든 코드 작성이 끝났으므로, 테라폼을 실행시켜 봅시다.

테라폼은 아래와 같이 크게 4단계로 동작합니다.

출처 : https://www.google.com/url?sa=i&url=https%3A%2F%2Fgeekflare.com%2Fterraform-for-beginners%2F&psig=AOvVaw3aXqp_EmXA3MiWIMP_KmXK&ust=1603700347251000&source=images&cd=vfe&ved=0CAIQjRxqFwoTCICTpMKnz-wCFQAAAAAdAAAAABAL
  1. init 에서 테라폼 설정파일을 생성하고, 필요한 플러그인을 다운로드 받습니다.

2. plan에서는 어떤 인프라가 생성/삭제 될 지, 또 이에 대한 설정값을 확인할 수 있습니다.

3. Apply는 현재 계획한 인프라를 AWS, Azure 등 클라우드에 실제로 배포하는 명령어입니다.

4. Destroy는 현재 계획한 인프라를 삭제하는 명령어입니다.

이 모든 명령어는 tfstate라는 파일에 의존적입니다. 따라서 tfstate를 억지로 수정하거나, 변경하시면 안됩니다.

또한 전혀 다른 인프라를 생성 및 관리하시려면 workspace를 새로 만드셔서 새로운 tfstate를 생성하셔야 합니다.

init 명령어를 사용해서 초기 설정을 해줍니다.

docker-compose run --rm tf init \
terraform/utility/aws/generate_keypair

apply 명령어를 이용해 키페어를 생성합니다.

apply 명령어를 실행하면 plan의 결과도 함께 출력됩니다.

docker-compose run --rm tf apply \
-var "region=us-east-2" \
-var "access_key=***********" \
-var "secret_key=***********" \
terraform/utility/aws/generate_keypair

어떤 리소스가 생성되는지 확인하고, 마지막으로 이 명령을 승인할 것 인지 물어봅니다. 이 때 yes를 입력합니다.

--auto-approve 명령어를 이용해 마지막 승인을 묻는 과정을 생략할 수 있습니다.

성공적으로 작업이 끝나면, output.tf에서 작성한 private, public key와 key 이름을 출력할 수 있습니다.

이 중 ssh_private_key_pem 출력문으로 private key를 파일로 만듭니다.

docker-compose run --rm tf output ssh_private_key_pem > test-key.pem

만든 key 파일이 실행될 수 있도록 권한을 설정해줍니다.

chmod 700 test-key.pem

EC2에 접근하기 위한 key pair를 생성했습니다.

아키텍처 생성하기

docker-compose run --rm tf workspace new infra

infra라는 새로운 workspace를 생성합니다.

테라폼 코드를 재사용하기 위해선 Module 기능을 활용해야 합니다.

module은 미리 정의한 테라폼 코드를 다시 사용할 수 있는 함수와 같은 기능입니다.

아래는 아키텍처를 생성하는 메인 프로그램입니다.

terraform/arch/ec2_with_nginx/dev/main.tf

아래 그림을 구성하는 소스코드이며, module 키워드를 통해 다른 디렉토리에 위치한 리소스들을 가져다가 재사용할 수 있습니다.

네트워크 설정

module은 source 에 명시된 위치의 *.tf 파일들을 실행합니다.

docker-compose에서 정의한 디렉토리에서 테라폼을 실행하므로 모든 source의 시작 디렉토리는 /infra를 가르킵니다.

먼저 VPC를 생성하고, 생성한 VPC id를 public, private 서브넷과 인터넷 게이트웨이를 생성할 때 사용합니다.

생성된 vpc는 vpc_id를 리턴(출력)하도록 output 파일을 만들어줍니다.

또한 vpc를 생성하기 위한 variable을 정의해줍니다.

vpc를 생성하면,

module.aws_vpc.vpc_id 

위와 같이 생성된 vpc 정보 output에 접근할 수 있습니다.

이제 vpc_id를 이용해 NAT, 인터넷 게이트웨이를 생성합니다.

vpc_id를 사용해 인터넷 게이트웨이를 생성합니다.

eip를 생성하고, 이를 NAT에 물려줍니다.

public, private 서브넷을 각각 하나씩 생성합니다.

라우팅 설정

위 네트워크 설정에서 만든 서브넷들에 라우팅 테이블을 만들어줍니다.

private-route 에 NAT를 물려주어 내부에서 인터넷으로 통신이 가능하도록 설정합니다.

public-route에 인터넷 게이트웨이를 물려주어 인터넷과 연결이 가능하도록 구성합니다.

EC2

이제 EC2를 생성해보겠습니다.

동일한 sg 그룹에 2개의 EC2를 생성합니다.

aws_ec2_public은 인터넷에서 접속 가능한 인스턴스입니다.

인스턴스를 배포할 때 nginx 도커 웹서버를 생성하도록 구성합니다.

docker_image 매개변수에 도커 이미지 이름인 nginx를 주고, port를 설정해줍니다.

실제 EC2를 생성시키는 코드는 아래와 같습니다.

provisioner “file” {
source = "스크립트 파일 위치"
}
provisioner "remote-exec" {
...
inline = [ commands ]
}

EC2가 생성될 때 실행할 스크립트를 file로 던져주고, 이를 실행하는 커맨드를 remote-exec inline에서 지정해줍니다.

위에서 file 매개변수로 던져줄 스크립트입니다.

docker를 설치하고, 전달된 NGINX docker image를 pull 받고 실행하는 쉘 스크립트입니다.

위와 같은 인프라 구성을 마쳤고, A 인스턴스 생성 시 Nginx가 실행되도록 스크립트를 넣어주었습니다.

init 명령어로 테라폼 초기설정을 구성합니다.

docker-compose run --rm tf init terraform/arch/ec2_with_nginx/dev/

Apply 명령어를 이용해 배포해봅시다.

docker-compose run --rm tf apply \
-var "region=us-east-2" \
-var "access_key=*********" \
-var "secret_key=*********" \
terraform/arch/ec2_with_nginx/dev/

Nginx에 잘 붙는것을 확인할 수 있습니다.

이제 인스턴스에 SSH로 접근해보겠습니다.

ssh -i test-key.pem ubuntu@<public_ip>

ip 확인이 안되시면 아래 명령어로 확인 가능합니다

docker-compose run --rm tf output public_ip
docker-compose run --rm tf output private_ip

private 인스턴스에 접근하기 위해서 public 인스턴스안에도 pem키를 전송해주어야 합니다.

scp를 이용해서 로컬머신에서 public 인스턴스로 pem키를 전송해줍니다.

scp -i test-key.pem test-key.pem ubuntu@<public_ip>:~

10.10.20.0/24 대역의 public 인스턴스에서

10.10.21.0/24 대역에 있는 private 인스턴스에 핑을 날려봅니다.

public 인스턴스에서 .pem키를 사용해 private 인스턴스에 접속합니다.

ssh -i test-key.pem ubuntu@<private_ip>

접속한 인스턴스는 외부 인터넷에서 직접적인 접근이 불가능합니다.

하지만 NAT 덕분에 외부 인터넷으로의 접근은 가능합니다.

--

--

No responses yet