[Terraform] 테라폼 개요

728x90

공식 문서: https://www.terraform.io/

CentOS/RHEL 에 테라폼 설치하기

$ sudo yum install -y yum-utils
$ sudo yum-config-manager --add-repo <https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo>
$ sudo yum -y install terraform

AWS CLI 설치

아마존 문서: htps://docs.aws.amazon.com/ko_kr/cli/latest/userguide/getting-started-install.html

aws configure 명령어로 본인 AWS 계정의 Access key 와 Secret key 를 등록한다.

aws sts get-caller-identity 명령어를 입력했을 때 사용자 계정 정보가 나타나면 올바르게 작동하고 있는 것이다.

[vagrant@controller ~]$ aws configure
AWS Access Key ID [****************CMOE]: AKIXXXXXXXXXXXX
AWS Secret Access Key [****************o0tR]: WLAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Default region name [ap-northeast-2]:
Default output format [None]:
[vagrant@controller ~]$ aws sts get-caller-identity
{
    "UserId": "AIDXXXXXXXXXXXX",
    "Account": "00XXXXXXXXXXXX",
    "Arn": "arn:aws:iam::00XXXXXXXXXXXX:user/choi"
}

Terraform 개요

HCL: Hashicorp Configuration Language

DSL: Domain Specific Language

구성파일

Terraform Configure File

  • .tf
  • .tf.json: json 형식

인코딩

Unicode

디렉토리

현재 작업 디렉토리 위치에 따라서 해당 디렉토리의 .tf, .tf.json 모두 읽어서 실행

구성 파일

<BLOCK TYPE> <BLOCK LABEL> {
	ARGUMENT
	KEY
}

테라폼 블록

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.27"
    }
  }

  required_version = ">= 0.14.9"
}
  • aws : 프로바이더의 이름
  • source : 프로바이더 종류
  • version : 프로바이더의 버전
    • 4.10 : 특정 버전
    • ~> 3.12: 특정 버전 이상
    • > 3.12 : 최소 버전

프로바이더 블록(필수)

provider "aws" {
  profile = "default"
  region  = "ap-northeast-2"
}

  • provider “aws”: terraform 블록 이름 매칭
    • profile : aws 자격증명 파일의 프로필
    • region

리소스 블록

resource "RESOURCE_TYPE" "NAME" {
  ARGUMENT = VALUE
}
  • RESOURCE_TYPE : 리소스 종류
  • NAME : 리소스 이름(테라폼에서 구분하기 위한 이름)
  • ARGUMENT : 인자 / 속성
resource "aws_instance" "app_server" {
  ami           = "ami-02de72c5dc79358c9"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}

똑같은 이름의 이미지라도 리전이 다르면 이미지의 ID 가 다르다!!!

실행 순서

초기화

메인이 되는 tf 파일을 생성한다.

# main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.27"
    }
  }

  required_version = ">= 0.14.9"
}

provider "aws" {
  profile = "default"
  region  = "ap-northeast-2"
}

resource "aws_instance" "app_server" {
  ami           = "ami-02de72c5dc79358c9"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}

terraform init 명령어로 프로바이더를 다운로드 받는다.

[vagrant@controller 01]$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 3.27"...
- Installing hashicorp/aws v3.75.1...
- Installed hashicorp/aws v3.75.1 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

아래처럼 .terraform 디렉토리가 생성되는데 프로바이더가 다운로드 된 것이다.

즉, aws api 를 테라폼에서 사용하도록 구성해놓은 실행 파일로 수정해서는 안된다.! terraform-provider-aws_v3.75.1_x5 해당 파일이 없으면 안된다!

[vagrant@controller 01]$ tree .terraform
.terraform
└── providers
    └── registry.terraform.io
        └── hashicorp
            └── aws
                └── 3.75.1
                    └── linux_amd64
                        └── terraform-provider-aws_v3.75.1_x5

6 directories, 1 file

init 을 하는 이유는 프로바이더와 백엔드를 세팅하기 위해서이다! 또한, terraform-provider-aws_v3.75.1_x5 에는 내 aws 계정에 대한 정보가 들어있기 때문에 외부에 노출시켜서는 안된다.

init 을 사용하는 경우는 보통 아래 두 가지이다.

  • 최초로 프로바이더 설치 시
  • 프로바이더 버전 업데이트 시

포맷팅

[vagrant@controller 01]$ terraform fmt

말 그대로 코드를 동일하게 포맷팅해준다.

구글이나 에어비앤비의 Javascript 스타일 가이드 같은 것으로 코드 컨벤션이라고 생각하면 된다.

유효성 검증

[vagrant@controller 01]$ terraform validate
Success! The configuration is valid.

계획

[vagrant@controller 01]$ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

.
.
.

Plan: 1 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

적용

[vagrant@controller 01]$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

.
.
.

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: yes

aws_instance.app_server: Creating...
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Still creating... [20s elapsed]
aws_instance.app_server: Still creating... [30s elapsed]
aws_instance.app_server: Creation complete after 34s [id=i-048219c13e821a8a8]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

삭제

[vagrant@controller 01]$ terraform destroy
aws_instance.app_server: Refreshing state... [id=i-048219c13e821a8a8]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

.
.
.

Plan: 0 to add, 0 to change, 1 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_instance.app_server: Destroying... [id=i-048219c13e821a8a8]
aws_instance.app_server: Still destroying... [id=i-048219c13e821a8a8, 10s elapsed]
aws_instance.app_server: Still destroying... [id=i-048219c13e821a8a8, 20s elapsed]
aws_instance.app_server: Still destroying... [id=i-048219c13e821a8a8, 30s elapsed]
aws_instance.app_server: Still destroying... [id=i-048219c13e821a8a8, 40s elapsed]
aws_instance.app_server: Destruction complete after 40s

Destroy complete! Resources: 1 destroyed.

상태 확인

terraform.tfstate: 현재 상태

terraform .tfstate.backup: 이전 상태

[vagrant@controller 01]$ terraform show
[vagrant@controller 01]$ terraform state show aws_instance.app_server

상태 재 동기화

[vagrant@controller 01]$ terraform refresh

리소스 목록 확인

[vagrant@controller 01]$ terraform state list
aws_instance.app_server

이미지 교체 시

결론적으로 기존에 있던 인스턴스를 지우고 새로운 인스턴스를 만들어서 교체한다.

[vagrant@controller 01]$ terraform fmt
[vagrant@controller 01]$ terraform validate
Success! The configuration is valid.

[vagrant@controller 01]$ terraform plan
aws_instance.app_server: Refreshing state... [id=i-0c9c8382b9b77d91e]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

.
.
.

Plan: 1 to add, 0 to change, 1 to destroy.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

틸드(물결) 표시로 된 것은 교체되는 것을 의미한다.

[vagrant@controller 01]$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

.
.
.

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: yes

aws_instance.app_server: Creating...
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Still creating... [20s elapsed]
aws_instance.app_server: Still creating... [30s elapsed]
aws_instance.app_server: Creation complete after 33s [id=i-02a52ecb67bda7851]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

리소스 생성 순서

  • 의존 관계가 없는 리소스는 병렬로 실행
  • 의존 관계가 있는 경우 의존 관계에 따라서 순서가 정해지게 됨

명시적 의존성

resource "aws_instance" "app_server" {
	ami = "ami-..."
	instance_type = "t2.micro"

	tags = {
		Nmae = "Example"
	}
	depends_on = [
		aws_se_bucker.app_bucket
	]
}

resource "aws_s3_bucket" "app_bucket" {
	bucket = "csw-test-bucket"
	alc = "private"
}

리소스가 생성되는 순서는 의존성이 걸려있는 녀석부터 생성된다. 즉, 여기서는 버킷이 먼저 생성되고 그 후에 인스턴스가 생성되는 식이다.

입력 변수

공식 문서: https://www.terraform.io/language/values/variables

variable "image_id" {
  type = string
}

variable "availability_zone_names" {
  type    = list(string)
  default = ["us-west-1a"]
}

variable "docker_ports" {
  type = list(object({
    internal = number
    external = number
    protocol = string
  }))
  default = [
    {
      internal = 8300
      external = 8300
      protocol = "tcp"
    }
  ]
}
  • type:
    • string
      • “app_server”
    • number
      • 1
      • 1.0
    • bool
      • true
      • false
    • 복합 타입
      • list / tuple
        • [a, b, c]
      • map / object
        • {a=abc, b=xyz}
  • defualt: 기본 값
  • description: 설명
variable abc {
	type = object({
    name = string
    type = string
  })
  default = {
    name = "test"
    type = "t2.micro"
  }
}

실제로 작업을 구성해보자.

main.tf

	# main.tf
resource "aws_instance" "app_server" {
  ami           = "ami-02de72c5dc79358c9"
  instance_type = "t2.micro"

  tags = {
    Name = var.instance_name
  }

  # 명시적 의존성
  depends_on = [
    aws_s3_bucket.b
  ]
}

resource "aws_eip" "lb" {
  # 암시적 의존성
  instance = aws_instance.app_server.id
  vpc      = true
}

resource "aws_s3_bucket" "b" {
  bucket = "csw-test-bucker"

  tags = {
    Name        = "test bucket"
    Environment = "Dev"
  }
}

resource "aws_s3_bucket_acl" "example" {
  bucket = aws_s3_bucket.b.id
  acl    = "private"
}

variable.tf

# variable.tf
variable "instance_name" {
  type        = string
  description = "Instance Name"
  default     = "App Instance"
}

provider.tf

# provider.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.27"
    }
  }

  required_version = ">= 0.14.9"
}

provider "aws" {
  profile = "default"
  region  = "ap-northeast-2"
}

변수 값 할당

  1. -var 옵션 사용
$ terraform plan -var "instance_name=abc"

위와 같은 방법으로 변수를 지정할 수 있다.

  1. terraform.tfvars 파일 생성하여 변수 할당

파일 이름이 정확하게 terraform.tfvars 이거나 terraform.tfvars.json 이어야 한다.

$ cat terraform.tfvars
# terraform.tfvars
ami = "ami-02de72c5dc79358c9"
instance_name = "var_name"
$ terraform plan
728x90