Before 2022/AWS & DevOps

Terraform을 활용한 IaC 맛보기

Eljoe 2021. 3. 21. 18:21

Terraform

테라폼은 하시코프에서 Go 언어로 개발되고 있는 오픈소스 IaC(Infrastructure as Code) 도구이다.

HCL(Hashcorp Configuration Language)을 사용해 클라우드 리소스를 선언하며 AWS, GCP, Azure와 같은 주요 클라우드 서비스를 비롯한 다양한 클라우드 서비스들을 프로바이더 방식으로 제공하고있다.

 

설치(Ubuntu 20.04.1 LTS)

공식 다운로드 페이지에서 리눅스 64bit 바이너리 링크를 복사하고 wget 명령어로 다운로드한다.

wget https://releases.hashicorp.com/terraform/0.14.8/terraform_0.14.8_linux_amd64.zip


다운받은 테라폼 압축파일을 푼다. unzip 패키지가 없다면 설치한다.

yum install unzip
unzip terraform_0.14.8_linux_amd64.zip d /usr/bin/

 

설치된 테라폼 버전을 확인한다.

terraform -v
Terraform v0.14.8

이처럼 테라폼은 실행 툴도 없는 매우 쉽고 최소화된 설치단계를 제공한다.

 

Terraform 구조

테라폼은 확장자가 .tf이며 HCL이라 불리는 특별한 언어로 작성된다.

 

 

프로바이더(Provider)라 불리우는 항목은 테라폼과 외부 서비스를 연결해주는 기능을 하는 모듈로써, AWS 서비스의 리소스를 관리하기 위해서는 aws provider를 먼저 셋업해야한다.

AWS 리소스를 관리하기 위해선 해당 사용자의 인증정보가 필요하므로 'access_key', 'secret_key'가 필요하며, 해당 값은 IAM > 해당 사용자 > 보안 자격 증명 > 액세스 키 항목에 있다.

 

region은 리소스를 관리할 AWS 리전을 설정한다. 여기서 사용한 ap-northeast-2는 서울 리전을 의미한다.

 

resource는 사용할 리소스 타입의 이름으로써, 프로바이더에서 제공하는 리소스 타입의 이름을 입력한다.

'aws_instance'는 EC2의 가상 머신 리소스를 관리하는 리소스 타입을 의미한다.

 

두 번째 문자열 'ec2'는 이 리소스에 임의로 붙이는 이름으로써, 테라폼 코드의 다른 곳에서 이 리소스를 참조하기 위해서 사용하는 변수와 같은 역할을 수행한다.

 

그 뒤의 중괄호 내의 내용은 리소스 속성으로써 ami 및 instance_type은 따로 설명을 하지않아도 파악할 수 있을 것이다.

 

클라우드포메이션을 테라폼으로 대체하기

이전에 작업했던 CloudFormation & troposphere를 활용한 IaC 맛보기를 테라폼으로 대체해보겠다.

 

먼저 아래처럼 작업 디렉터리와 확장자가 .tf인 테라폼 파일을 생성하고 vim으로 파일을 연다.

mkdir terraform
cd terraform
touch main.tf
sudo vim main.tf

 

작성자의 경우 WSL 기반 Ubuntu로 작업을 진행하기 때문에 테라폼 파일을 아래와 같이 생성한다.

cd /mnt/c
mkdir terraform
cd terraform
touch main.tf
sudo vim main.tf

 

다음과 같이 HCL로 프로바이더와 리소스를 관리하는 내용을 입력한다.

 

 

* 작성자의 경우 WSL 기반이기 때문에 윈도우에서 Visual Studio Code를 실행 후 Terraform extension을 설치하여 아래와 같이 수월하게 작성할 수 있다.

 

 

이제 프로바이더 선언 하단의 각 리소스에 대한 설명을 해보겠다.

resource "aws_security_group" "node" {
  name          = "allow_node_js_and_ssh"
  description   = "Allow SSH and nodejs port from all"
  ingress {
    cidr_blocks = ["0.0.0.0/0"]
    protocol    = "tcp"
    from_port   = 22
    to_port     = 22
  }
  ingress {
    cidr_blocks = ["0.0.0.0/0"]
    protocol    = "tcp"
    from_port   = 3000
    to_port     = 3000
  }
}

'aws_security_group'은 Inbound/OutBound를 관리하는 보안그룹 리소스 타입이며, 여기선 인바운드 트래픽을 정의하는 속성인 'ingress'에 중괄호를 사용하는 블록 형태로 CIDR, Protocol, Port를 지정하는 것을 확인할 수 있다.

 

data "aws_security_group" "default" {
  name = "default"
}

'data'는 이미 클라우드 상에 정의되어 있는 리소스를 불러오는 기능을 제공하며, 기존 보안그룹인 'default'를 불러오는 것을 확인할 수 있다.

 

resource "aws_instance" "example" {
    ami             = "ami-0e17ad9abf7e5c818"
    instance_type   = "t2.micro"
    key_name        = "your_key_name"

    vpc_security_group_ids = [
      aws_security_group.node.id,
      data.aws_security_group.default.id
    ]

    provisioner "remote-exec" {
      connection {
        user        = "ec2-user"
        private_key = file("your/pem/key")
        host        = aws_instance.example.public_ip
      }

      inline = [
        "sudo amazon-linux-extras install epel -y",
        "sudo yum install --enablerepo=epel -y nodejs",
        "sudo wget https://your.helloworld.js.link -O /home/ec2-user/helloworld.js",
        "sudo wget https://your.helloworld.service.link -O /etc/systemd/system/helloworld.service",
        "sudo systemctl enable helloworld",
        "sudo systemctl start helloworld",
      ]
  }
}

'aws_instance'는 EC2 가상 머신 리소스를 관리하는 리소스이며 AMI와 Instance Type은 지난 글에서 작성한 내용을 그대로 입력한다.

 

'key_name' 속성은 보유중인 키 페어의 이름을 입력한다.

 

'vpc_security_group_ids'의 경우 배열로 지정하는데 첫 번째 값은 앞서 작성한 'node' 보안 그룹의 id 속성을 참조하고 두 번째 값도 역시 앞서 작성한 'default' 데이터의 id 속성을 참조한다. data를 참조하는 방법은 앞에 'data.'을 붙여줘야한다.

 

'provisioner'는 리소스를 생성하거나 제거할 때 로컬(local-exec)이나 원격(remote-exec)에서 스크립트를 실행할 수 있는 기능이다. 기본적으로 생성할 때만 한번 실행된다.

 

'remote-exec' 프로비저너는 리소스를 생성한 후 설치된 인스턴스에서 'connection' 속성에 입력한 접속 정보를 토대로 SSH 접속 뒤 'inline'에 입력한 명령어들을 차례대로 실행한다.

 

* 명령어를 실행하는 방식에는 'inline', 'script', 'scripts'가 있으며 반드시 셋 중에 하나만 사용해야한다.

 

공식 Terraform 설명

 

'terraform init' 명령어를 실행하여 작업 디렉터리 아래에 선언된 프로바이더 플러그인을 설치해준다.

 

 

해당 테라폼 파일에 오탈자나 누락된 문자열을 검증해주는 'terraform validate' 명령어를 입력해보자

 

 

오류가 생겼을 땐 Error 내용과 함께 오류가 생긴 라인수 및 오류 내용을 반환한다.

작성자의 경우 file 내용을 반환하는 file 함수의 경로가 올바르지 않아서 생긴 오류이다.

문법적인 오류가 존재하지 않는다면 아무런 출력 값이 없을 것이다.

 

작업 디렉터리 아래의 모든 테라폼 파일의 내용을 실제로 적용 가능한지 확인하는 'terraform plan' 명령어를 실행한다.

 

생성될 리소스와 속성 목록과 작업을 수행할 리소스에 대한 개수가 출력되는 것을 확인할 수 있다.

 

이제 이러한 계획을 실제 AWS 리소스에 적용하는 단계인 'terraform apply' 명령어를 입력해보자.

 

적용할지 한번 더 확인하는 과정인 'Enter a value' 입력 란에 'yes'를 입력한다.

 

 

그럼 아래와 같이 작업 과정과 provisioner에 입력한 명령어의 실행결과가 실시간으로 출력되는 것을 확인할 수 있으며 AWS EC2 콘솔에서도 실시간으로 인스턴스가 작업을 수행중인 것을 확인할 수 있다.

 

 

작업이 정상적으로 진행이 되었다면 'Apply complete!'가 출력이 되고 EC2의 퍼블릭 도메인의 3000 포트로 접속하여 아래와 같은 결과를 확인한다.

 

 

정상적으로 진행된 것을 확인한 후 관련된 모든 리소스를 제거하고 싶다면 'terraform destroy'를 입력하면 된다.