T101-1주차 [Terraform 101 Study]

테라폼이란?

  • 테라폼Terraform은 하시코프Hashicorp에서 오픈소스로 개발중인 클라우드 인프라스트럭처 자동화를 지향하는 코드로서의 인프라스트럭처Infrastructure as Code, IaC 도구입니다.
  • 테라폼음은 대상 인프라와 서비스를 테라폼으로 작업하기 위해서는 대상의 제공자, 프로바이더가 둘 사이에서 인터페이싱해야 하며, 각 인프라와 서비스는 고유의 api를 가지고 있고 프로바이더는 각 API 명세를 테라폼 코드로 호출해 동작 합니다.

https://nemne.tistory.com/36

Provisioner -Provisioner는 Terraform으로 리소스를 생성하거나 제거할 때 로컬이나 원격에서 스크립트를 실행할 수 있는 기능으로 0.8부터 추가되었다

Provider -특정 벤더에 대해 접근할 수 있도록 도와주는 역할을 한다. -리소스에 대한 간단한 CRUD API 호출을 담당한다. -인프라 제공자를 통한 인증을 한다.

실습 환경 설정

*테라폼 버전은 1.5.2 입니다.

*사용하는 툴은 비주얼 스튜디오 코드 입니다.

  • 테라폼으로 시작하는 IaC 책을 기준으로 작성하였습니다.

  1. AWS 콘솔에서 IAM을 통하여 권한을 생성을 해주며 해당 USER에게 AdministratorAccess 권한을 부여합니다. (아래에서 추가설명 합니다.)

2. 자신의 OS의 맞는 환경에 맞춰 테라폼을 설치하여 줍니다. (여기선 윈도우 환경이므로 윈도우만 설명합니다)

  1. 윈도우에 WSL2 설치
  2. WSL2 실행(Shell 접속)
  3. 테라폼 설치 및 확인 – 링크 (Linux → Ubuntu/Debian 선택)
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

# 테라폼 버전 정보 확인
terraform version

IDE 구성

비주얼 스튜디오 코드에서 아래와 같은 통합 개발 환경을 설치하여 줍니다.

  • Extentions (확장) 설치
  • HashiCorp HCL : syntax highlighting for HCL files – 링크
  • HashiCorp Terraform : Highlighting syntax from Terraform 등 – 링크

AWS CLI 설치 및 자격증명

# Linux 설치 방법
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install


# aws cli 버전 확인
aws --version
aws-cli/2.7.31 Python/3.10.7 Darwin/21.6.0 source/x86_64 prompt/off

# aws cli 사용 시도
aws s3 ls

---
# aws configure 로 자격증명 설정 : 방안1
aws configure
... >> 입력

aws configure list
Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************X4H7 shared-credentials-file    
secret_key     ****************jnZu shared-credentials-file    
    region           ap-northeast-2      config-file    ~/.aws/config

EC2 배포

  • provider : Terraform으로 정의할 Infrastructure Provider를 의미
  • resource : 실제로 생성할 인프라 자원을 의미

터미널 1에서 파일생성 합니다.

cat <<EOT > main.tf
provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "example" {
  ami           = "ami-0a0064415cdedc552"
  instance_type = "t2.micro"
}
EOT

resource “<PROVIDER>_<TYPE>” “<NAME>” { [CONFIG …] }

PROVIDER : ‘aws’ 같은 공급자의 이름

TYPE : ‘security_group’ 같은 리소스의 유형

NAME : 리소스의 이름

CONFIG : 한개 이상 arguments

배포 실행 : 터미널2에서 실행 합니다.

# 초기화
terraform init
ls -al
tree .terraform

# plan 확인
# 배포되기전 확인이 가능합니다. 
terraform plan

위 그림과 같이 EC2 1대가 생성 된것이 확인 가능 합니다.

하지만 위 그림을 보면 태그가 없는것을 알수가 있습니다.

코드를 수정해 봅니다.

cat <<EOT > main.tf
provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "example" {
  ami           = "ami-0a0064415cdedc552"
  instance_type = "t2.micro"

  tags = {
    Name = "minho-study"
  }

}
EOT
# plan 실행 시 아래와 같은 정보가 출력
terraform plan
# aws_instance.example will be updated in-place
  ~ resource "aws_instance" "example" {
        id                                   = "ami-0a0064415cdedc552"
      ~ tags                                 = {
          + "Name" = "minho-study"
        }
      ~ tags_all                             = {
          + "Name" = "minho-study"
        }
        # (29 unchanged attributes hidden)

        # (7 unchanged blocks hidden)
    }
# apply 실행
terraform apply
 Enter a value: yes 입력

위와 같이 Name 이 변경된것이 확인 가능 합니다.

확인을 하였으니 삭제를 해봅시다

# 리소스 삭제
terraform destroy
 Enter a value: yes 입력

혹은
#yes 생략합니다.
terraform destroy -auto-approve

EC2 1대 배포 & 웹 서버 설정

cat <<EOT > main.tf
provider "aws" {
  region = "ap-northeast-2"
}
# aws 환경에 배포하고 리전은 서울이다.
resource "aws_instance" "example" {
  ami                    = "ami-0c9c942bd7bf113a2"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.instance.id]

#유저데이타 ec2 최초 프로비저닝시 실행할 명령어 
  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, T101 Study 9090" > index.html
              nohup busybox httpd -f -p 9090 &
              EOF

#유저데이타 변경되면 기존꺼 날리고 새롭게 생성한다
  user_data_replace_on_change = true

  tags = {
    Name = "Single-WebSrv"
  }
}

resource "aws_security_group" "instance" {
  name = var.security_group_name

  ingress {
    from_port   = 9090
    to_port     = 9090
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

variable "security_group_name" {
  description = "The name of the security group"
  type        = string
  default     = "terraform-example-instance"
}

output "public_ip" {
  value       = aws_instance.example.public_ip
  description = "The public IP of the Instance"
}
EOT

배포실행

# 모니터링
while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------" ; sleep 1; done

# plan
terraform plan
# aws_instance.example must be replaced
-/+ resource "aws_instance" "example" {
...
      ~ user_data                            = "d91ca31904077f0b641b5dd5a783401396ffbf3f" -> "f1a1c16060740d7be18475c067c120a0eed366da"
        # forces replacement
...
Changes to Outputs:
  ~ public_ip = "43.201.8.225" -> (known after apply)

# apply
terraform apply -auto-approve

# 웹 서버 접속 시도 : 터미널3에서 실행
# process 올라오는데 시간이 1~2분 정도 소요되어서, ec2 생성되면 1~2분 정도 후에 curl 접속이 가능하다
PIP=<각자 자신의 EC2 IP>
while true; do curl --connect-timeout 1  http://$PIP:9090/ ; echo "------------------------------"; date; sleep 1; done
#IP조회
terraform output
#퍼블릭 IP만 출력
terraform output public_ip
# "" 음표 날라가고 IP만 남음
terraform output -raw public_ip
#IP변수로 넣음
PIP=$(terraform output -raw public_ip)
#IP넣음
echo $PIP
#조회
curl $PIP:9090

확인이 완료 되었으면 삭제 합니다

# 리소스 삭제
terraform destroy -auto-approve

테라폼 블록

– 테라폼 블록은 테라폼 구성을 명시하는 데 사용 하며 이를 통하여 몇년 후에도 동일한 결과를 얻을 수 있도록 도와줍니다.

– 테라폼 버전이나 프로바이더 버전과 같은 값들은 자동으로 설정되지만, 함께 작업할 때는 버전을 명시적으로 선언하고 필요한 조건을 입력하여 실행 오류를 최소화 할 것을 권장하고 있습니다.

테라폼 버전

테라폼 버전이 다르면 어떤 결과를 불러오는지 봐봅시다.

# 현재 버전 정보 확인
terraform version
Terraform v1.5.2

코드 파일 수정 main.tf

vi main.tf
==
terraform {
  required_version = "< 1.0.0"
}

resource "local_file" "abc" {
  content  = "abc!"
  filename = "${path.module}/abc.txt"
}
==

init 실행

terraform init

ㄴ정상 작동이 안되는 것을 알수가 있습니다.

코드 파일 수정

terraform {
  required_version = ">= 1.0.0"
}

resource "local_file" "abc" {
  content  = "abc!"
  filename = "${path.module}/abc.txt"
}

init 실행

terraform init

리소스

리소스 구성 resource

  • 리소스 블록은 resource로 시작한다. 이후 리소스 블록이 생성할 ‘리소스 유형’을 정의합니다.
  • 리소스 선언 : 리소스 유형(프로바이더이름_제공리소스유형), 동일한 유형에 대한 식별자 역할로 고유한 이름, 구성 인수들이 이름 뒤에 중괄호 내에 선언됩니다.
resource "<리소스 유형>" "<테라폼이 구분하는 이름(중복되면 안됨)>" {
  <인수> = <값>
}

resource "local_file" "abc" {
  content  = "123"
  filename = "${path.module}/abc.txt"
}

위와 같이 작성후  terraform init  명령어를 실행할 경우 local_file 작동하기위한 라이브러리를
자동적으로 설치하여 줍니다.

종속성

– 테라폼 종속성은 resource, module 선언으로 프로비저인되는 각 요소의 생성 순서를 구분짓습니다.

[해당실습을 위하여 VS Code 확장 graphviz 설치가 필요합니다.]

resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

resource "local_file" "def" {
  content  = "456!"
  filename = "${path.module}/def.txt"
}

#
terraform apply -auto-approve
...
Plan: 2 to add, 0 to change, 0 to destroy.
local_file.def: Creating...
local_file.abc: Creating...
local_file.abc: Creation complete after 0s [id=5f30576af23a25b7f44fa7f5fdf70325ee389155]
local_file.def: Creation complete after 0s [id=b9fbde4d33ab9c450a7ce303fb4788c9d2db9aed]

# 리소스 확인
ls *.txt
terraform state list
local_file.abc
local_file.def

# graph 확인 > graph-1.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph
terraform graph > graph-1.dot
# 모든 리소스 제거
terraform destroy -auto-approve
ls *.txt
terraform state list

리소스 참조값을 설정해 두 개의 리소스 간 암시적 종속성 부여

resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

resource "local_file" "def" {
                            # 123!을 참조한다
  content  = local_file.abc.content
  filename = "${path.module}/def.txt"
}

apply : 커맨드 생성에 순서가 발생한 종속성 있는 두 개의 리소스

#
terraform apply -auto-approve
...
Plan: 2 to add, 0 to change, 0 to destroy.
local_file.abc: Creating... <- 먼저 만들고
local_file.abc: Creation complete after 0s [id=5f30576af23a25b7f44fa7f5fdf70325ee389155]
local_file.def: Creating... <- 그 다음 만듬
local_file.def: Creation complete after 0s [id=5f30576af23a25b7f44fa7f5fdf70325ee389155]

ls *.txt
terraform state list
cat abc.txt
cat def.txt
diff abc.txt def.txt

# graph 확인 > graph-2.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph
terraform graph > graph-2.dot

위와 같은 방법이 아니라 depends_on 도 가능합니다.

-AWS 클라우드포메이션에서 사용하는 방법입니다.

resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

#depends_on => 위에꺼 만들고 아래꺼를 만들어라
resource "local_file" "def" {
  depends_on = [
    local_file.abc
  ]

  content  = "456!"
  filename = "${path.module}/def.txt"
}
위로 스크롤