본문 바로가기

Newb/Terraform

Terraform 기본 명령어 & Flow

반응형
CloudNet@ T101 스터디 진행 후 정리한 글 입니다.

Terraform

 

먼저 아래와 같이 aws에서 EC2를 생성 후 busybox로 http를 실행하는 테라폼 코드를 생성 합니다.

## main.tf
provider "aws" {
  region = "ap-northeast-2"
}

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

  user_data = <<-EOF
              #!/bin/bash
              echo "Hello, T101 Study" > index.html
              nohup busybox httpd -f -p 8080 &
              EOF

  tags = {
    Name = "terraform-Study-101"
  }
}

Terraform init (준비)

Terraform 바이너리에는 테라폼의 기본 기능은 포함되어 있지만, AWS, 구글 클라우드 등에 대한 코드는 기본으로 포함되어 있지 않아 init 명령어로 테라폼 코드를 스캔하고, 테라폼 코드에 있는 프로바이더의 필요한 코드를 .terraform 폴더에 다운 받아 작성한 Terraform 코드의 구성을 실행 할 수 있도록 작업 디렉토리를 준비하게 됩니다.

아래를 보면 init 명령어를 한 후 .terraform 디렉토리와 .terraform.lock.hcl 파일이 생성 된 것을 확인 할 수 있으며,

.terraform 디렉토리 안에는 코드에서 사용하겠다고 지정한 aws를 사용할 수 있도록 프로바이더 플로그인을 다운하여 준비한 것을 볼 수 있습니다.

 

## init 명령어 전 main.tf 파일만 있는 상태

hong@test MINGW64 /d/hong/git/test
$ ll -al
total 1
drwxr-xr-x 1 hong 197121   0 11월  8 23:42 ./
drwxr-xr-x 1 hong 197121   0 11월  8 23:33 ../
-rw-r--r-- 1 hong 197121 389 11월  8 23:33 main.tf

 

## terraform init 명령어

hong@test MINGW64 /d/hong/git/test
$ terraform.exe init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v4.38.0...
- Installed hashicorp/aws v4.38.0 (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.

 

## init 명령어 이후 .terraform, .terraform.lock.hcl 파일 생성

.terraform.lock.hcl 파일은 종속성 잠금을 담당하는 파일입니다. 테라폼 0.13 이전의 버전들은 init 명령어 시 관련된 최신 버전의 프로바이더를 가져와 설치되었기 때문에 init 시 프로바이더 버전이 변경되어 문제가 발생하자, 테라폼 0.14 버전에서는 잠금 파일인 .terraform.lock.hcl 파일에 있는 프로바이더 종속 버전만을 기억하여 설치하므로써 이러한 문제를 해결하였습니다.

hong@test MINGW64 /d/hong/git/test
$ ll -al
total 5
drwxr-xr-x 1 hong 197121    0 11월  8 23:42 ./
drwxr-xr-x 1 hong 197121    0 11월  8 23:33 ../
drwxr-xr-x 1 hong 197121    0 11월  8 23:42 .terraform/
-rw-r--r-- 1 hong 197121 1152 11월  8 23:42 .terraform.lock.hcl
-rw-r--r-- 1 hong 197121  389 11월  8 23:33 main.tf

 

## init 명령어 이후 .terraform 디렉토리의 구조 확인

.terraform 디렉토리 안에는 코드에서 사용하겠다고 지정한 aws를 사용할 수 있도록 프로바이더 플로그인들이 다운된 것을 볼 수 있습니다.

hong@test MINGW64 /d/hong/git/test
$ tree .terraform
.terraform
`-- providers
    `-- registry.terraform.io
        `-- hashicorp
            `-- aws
                `-- 4.38.0
                    `-- windows_amd64
                        `-- terraform-provider-aws_v4.38.0_x5.exe

Terraform plan (확인)

plan 명령어는 코드가 적용되기 전 테라폼이 수행할 작업을 확인 할 수 있습니다.

아래와 같이 추가되는 항목은 +로, 빠지는 항목은 -로, 변경되는 항목은 ~로 표기됩니다.

hong@test MINGW64 /d/hong/git/test
$ terraform.exe 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:

  # aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                                  = "ami-0e9bfdb247cc8de84"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "terraform-Study-101"
        }
      + tags_all                             = {
          + "Name" = "terraform-Study-101"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "d91ca31904077f0b641b5dd5a783401396ffbf3f"
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id                 = (known after apply)
              + capacity_reservation_resource_group_arn = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + maintenance_options {
          + auto_recovery = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
          + instance_metadata_tags      = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_card_index    = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + private_dns_name_options {
          + enable_resource_name_dns_a_record    = (known after apply)
          + enable_resource_name_dns_aaaa_record = (known after apply)
          + hostname_type                        = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

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

terraform apply (생성)

apply 명령어 시 보여주는 내용은 plan 명령어와 같지만,

plan 명령어는 확인만 가능한 반면에 apply 명령어는 실제로 해당 코드를 적용할 수 있습니다.

apply 명령어 시 작업을 수행할 것인지에 대한 물음을 하는데 -auto-approve 옵션을 주게되면 물음 없이 바로 진행도 가능합니다.

hong@test MINGW64 /d/hong/git/test
$ terraform.exe 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:

  # aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                                  = "ami-0e9bfdb247cc8de84"
      + arn                                  = (known after apply)
      + associate_public_ip_address          = (known after apply)
      + availability_zone                    = (known after apply)
      + cpu_core_count                       = (known after apply)
      + cpu_threads_per_core                 = (known after apply)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t2.micro"
      + ipv6_address_count                   = (known after apply)
      + ipv6_addresses                       = (known after apply)
      + key_name                             = (known after apply)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (known after apply)
      + primary_network_interface_id         = (known after apply)
      + private_dns                          = (known after apply)
      + private_ip                           = (known after apply)
      + public_dns                           = (known after apply)
      + public_ip                            = (known after apply)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "terraform-Study-101"
        }
      + tags_all                             = {
          + "Name" = "terraform-Study-101"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "d91ca31904077f0b641b5dd5a783401396ffbf3f"
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id                 = (known after apply)
              + capacity_reservation_resource_group_arn = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + maintenance_options {
          + auto_recovery = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
          + instance_metadata_tags      = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_card_index    = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + private_dns_name_options {
          + enable_resource_name_dns_a_record    = (known after apply)
          + enable_resource_name_dns_aaaa_record = (known after apply)
          + hostname_type                        = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

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.example: Creating...
aws_instance.example: Still creating... [10s elapsed]
aws_instance.example: Still creating... [20s elapsed]
aws_instance.example: Creation complete after 21s [id=i-xxxxxxxxxxxxxxx]

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

terraform.tfstate 파일

Terraform apply 시 기존에는 없던 terraform.tfstate 파일이 생성 된 것을 확인할 수 있습니다.

hong@test MINGW64 /d/hong/git/test
$ ll
total 13
-rw-r--r-- 1 hong 197121  389 11월 10 12:48 main.tf
-rw-r--r-- 1 hong 197121  178 11월 10 12:55 terraform.tfstate
-rw-r--r-- 1 hong 197121 4516 11월 10 12:55 terraform.tfstate.backup

terraform.tfstate 파일은 json 형태로 테라폼으로 구성 된 인프라의 현재 상태를 저장하고 있는 파일입니다.

  • 상태 파일 충돌? 테스트
    • main.tf 파일 삭제 후 terraform apply
      • 리소스 삭제
    • terraform.tfstate 파일 삭제 후 terraform apply 
      • 리소스 생성 But 리소스가 있으므로 에러 발생
      • 이럴 때에는 import 명령어로 terraform.tfstate 파일을 다시 생성 가능

Terraform 내용 변경 (plan, apply)

테라폼의 내용을 변경 후 plan, apply 명령어를 사용하면 아래와 같이 ~ 표시로 변경되는 부분을 확인 할 수 있습니다.

  ~ resource "aws_instance" "example" {
        id                                   = "i-0f7f030e5fcf1e3d8"
      ~ instance_type                        = "t2.micro" -> "t3.medieum"
        tags                                 = {
            "Name" = "terraform-Study-101"
        }

hong@test MINGW64 /d/hong/git/test
$ terraform.exe plan
aws_instance.example: Refreshing state... [id=i-xxxxxxxxxxxxxxx]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_instance.example will be updated in-place
  ~ resource "aws_instance" "example" {
        id                                   = "i-xxxxxxxxxxxxxxx"
      ~ instance_type                        = "t2.micro" -> "t3.medieum"
        tags                                 = {
            "Name" = "terraform-Study-101"
        }
        # (30 unchanged attributes hidden)

        # (7 unchanged blocks hidden)
    }

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

terraform destroy (삭제)

terraform destroy는 생성한 리소스들을 삭제하는 명령어 입니다.

destroy 명령어 시에도 apply 명령어와 같이 작업을 수행할 것이지에 대한 물음을하며 -auto-approve 옵션을 주게되면 물음 없이 진행이 가능합니다.

hong@test MINGW64 /d/hong/git/test
$ terraform.exe destroy
aws_instance.example: Refreshing state... [id=i-xxxxxxxxxxxxxxx]

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:

  # aws_instance.example will be destroyed
  - resource "aws_instance" "example" {
      - ami                                  = "ami-0e9bfdb247cc8de84" -> null
      - arn                                  = "arn:aws:ec2:ap-northeast-2:xxxxxxxxxxxxxxx:instance/i-0f7f030e5fcf1e3d8" -> null
      - associate_public_ip_address          = true -> null
      - availability_zone                    = "ap-northeast-2a" -> null
      - cpu_core_count                       = 1 -> null
      - cpu_threads_per_core                 = 1 -> null
      - disable_api_stop                     = false -> null
      - disable_api_termination              = false -> null
      - ebs_optimized                        = false -> null
      - get_password_data                    = false -> null
      - hibernation                          = false -> null
      - id                                   = "i-0f7f030e5fcf1e3d8" -> null
      - instance_initiated_shutdown_behavior = "stop" -> null
      - instance_state                       = "running" -> null
      - instance_type                        = "t2.micro" -> null
      - ipv6_address_count                   = 0 -> null
      - ipv6_addresses                       = [] -> null
      - monitoring                           = false -> null
      - primary_network_interface_id         = "eni-xxxxxxxxxxxxxxx" -> null
      - private_dns                          = "ip-172-31-13-226.ap-northeast-2.compute.internal" -> null
      - private_ip                           = "172.31.13.226" -> null
      - public_dns                           = "ec2-1-1-1-1.ap-northeast-2.compute.amazonaws.com" -> null
      - public_ip                            = "1.1.1.1" -> null
      - secondary_private_ips                = [] -> null
      - security_groups                      = [
          - "default",
        ] -> null
      - source_dest_check                    = true -> null
      - subnet_id                            = "subnet-xxxxxxxxxxxxxxx" -> null
      - tags                                 = {
          - "Name" = "terraform-Study-101"
        } -> null
      - tags_all                             = {
          - "Name" = "terraform-Study-101"
        } -> null
      - tenancy                              = "default" -> null
      - user_data                            = "d91ca31904077f0b641b5dd5a783401396ffbf3f" -> null
      - user_data_replace_on_change          = false -> null
      - vpc_security_group_ids               = [
          - "sg-xxxxxxxxxxxxxxx",
        ] -> null

      - capacity_reservation_specification {
          - capacity_reservation_preference = "open" -> null
        }

      - credit_specification {
          - cpu_credits = "standard" -> null
        }

      - enclave_options {
          - enabled = false -> null
        }

      - maintenance_options {
          - auto_recovery = "default" -> null
        }

      - metadata_options {
          - http_endpoint               = "enabled" -> null
          - http_put_response_hop_limit = 1 -> null
          - http_tokens                 = "optional" -> null
          - instance_metadata_tags      = "disabled" -> null
        }

      - private_dns_name_options {
          - enable_resource_name_dns_a_record    = false -> null
          - enable_resource_name_dns_aaaa_record = false -> null
          - hostname_type                        = "ip-name" -> null
        }

      - root_block_device {
          - delete_on_termination = true -> null
          - device_name           = "/dev/sda1" -> null
          - encrypted             = false -> null
          - iops                  = 100 -> null
          - tags                  = {} -> null
          - throughput            = 0 -> null
          - volume_id             = "vol-xxxxxxxxxxxxxxx" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp2" -> null
        }
    }

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.example: Destroying... [id=i-xxxxxxxxxxxxxxx]
aws_instance.example: Still destroying... [id=i-xxxxxxxxxxxxxxx, 10s elapsed]
aws_instance.example: Still destroying... [id=i-xxxxxxxxxxxxxxx, 20s elapsed]
aws_instance.example: Destruction complete after 30s

Destroy complete! Resources: 1 destroyed.

 

Terraform help (위의 명령어 외 추가 명령어들)

$ terraform.exe -help
Usage: terraform [global options] <subcommand> [args]

The available commands for execution are listed below.
The primary workflow commands are given first, followed by
less common or more advanced commands.

Main commands:
  init          Prepare your working directory for other commands
  validate      Check whether the configuration is valid
  plan          Show changes required by the current configuration
  apply         Create or update infrastructure
  destroy       Destroy previously-created infrastructure

All other commands:
  console       Try Terraform expressions at an interactive command prompt
  fmt           Reformat your configuration in the standard style
  force-unlock  Release a stuck lock on the current workspace
  get           Install or upgrade remote Terraform modules
  graph         Generate a Graphviz graph of the steps in an operation
  import        Associate existing infrastructure with a Terraform resource
  login         Obtain and save credentials for a remote host
  logout        Remove locally-stored credentials for a remote host
  output        Show output values from your root module
  providers     Show the providers required for this configuration
  refresh       Update the state to match remote systems
  show          Show the current state or a saved plan
  state         Advanced state management
  taint         Mark a resource instance as not fully functional
  test          Experimental support for module integration testing
  untaint       Remove the 'tainted' state from a resource instance
  version       Show the current Terraform version
  workspace     Workspace management

Global options (use these before the subcommand, if any):
  -chdir=DIR    Switch to a different working directory before executing the
                given subcommand.
  -help         Show this help output, or the help for a specified subcommand.
  -version      An alias for the "version" subcommand.


참고자료

반응형