티스토리 뷰

728x90
반응형

개요

Cloud 환경은 복잡한 인프라로 구성되어 있어 그 일관성을 항상 유지하는 것은 어려운 일이다. 특히 확장성있게 증가하는 인프라 환경을 사람의 힘으로 관리하는 것은 민첩성과 안정성을 저해하는 요소가 된다. 이에 인프라를 코드로 관리하는 '코드형 인프라(IaC)'가 등장하게 되었고, 이를 통해 일관된 클라우드 인프라를 관리할 수 있게 되었다. 대표적인 IaC로는 Terraform이 있으며, AWS에는 CloudFormation이 있다.

이번 포스팅부터 Terraform 활용에 대해서는 별도 목차를 구분하여 작성하고자 한다. 그 첫 시간으로 Terraform을 사용하여 EC2 인스턴스를 생성하는 과정에 대해 알아보도록 하자.


Terraform 설치

아래와 같이 yum package manager를 통해 쉽게 설치가 가능하다. repository는 OS별로 각각 서로 다른 Repository를 추가한다.

[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# yum install -y yum-utils
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Package yum-utils-1.1.31-46.amzn2.0.1.noarch already installed and latest version
Nothing to do
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
adding repo from: https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
grabbing file https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo to /etc/yum.repos.d/hashicorp.repo
repo saved to /etc/yum.repos.d/hashicorp.repo
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# yum -y install terraform
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Resolving Dependencies
--> Running transaction check
---> Package terraform.x86_64 0:1.1.8-1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=======================================================================================================================================================================================================
 Package                                          Arch                                          Version                                         Repository                                        Size
=======================================================================================================================================================================================================
Installing:
 terraform                                        x86_64                                        1.1.8-1                                         hashicorp                                         12 M

Transaction Summary
=======================================================================================================================================================================================================
Install  1 Package

Total download size: 12 M
Installed size: 60 M
Downloading packages:
terraform-1.1.8-1.x86_64.rpm                                                                                                                                                    |  12 MB  00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : terraform-1.1.8-1.x86_64                                                                                                                                                            1/1
  Verifying  : terraform-1.1.8-1.x86_64                                                                                                                                                            1/1

Installed:
  terraform.x86_64 0:1.1.8-1

Complete!
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# which terraform
/usr/bin/terraform
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform version
Terraform v1.1.8
on linux_amd64
[root@ip-192-168-78-195 ~ (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

Terraform Script 작성

다음으로 Terraform Script(main.tf)를 작성한다. Terraform Script는 default로 main.tf를 참조한다.

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# cat 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" "ec2" {
  ami                    = "ami-xxxxxxxxxxxxxxxxx"
  instance_type          = "t3.xlarge"
}
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#
  • terraform : provider, version에 대한 정보를 명확히 기입하여 현재 리소스를 생성하고자 하는 환경에 대한 정보 정의
  • provider : terraform 필드에서 정의한 provider에 접근하기 위한 정보 정의
  • resource : 생성하고자 하는 리소스 정보 정의 resource "module" "resource_name" 형태로 정의 (ex - aws_instance를 ec2라는 이름으로 생성. 하부 태그는 module에 대한 상세 정보.)

Terraform 실행

1. terraform init (terraform 실행 초기화)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# 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.
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

2. terraform fmt (terraform 설정파일 수정)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform fmt
main.tf
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

3. terraform validate (terraform 설정파일 검증)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform validate
Success! The configuration is valid.

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

4. aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId" (현재 생성되어 있는 ec2 인스턴스)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId"
[
    "i-0667fadc7d193112d",
    "i-07647537570c72296"
]

5. terraform apply (terraform resource 생성)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# 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:

  # aws_instance.ec2 will be created
  + resource "aws_instance" "ec2" {
      + ami                                  = "ami-0d3f686a76ad0de18"
      + 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_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_state                       = (known after apply)
      + instance_type                        = "t3.xlarge"
      + 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_all                             = (known after apply)
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + 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)
            }
        }

      + 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)
        }

      + 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_interface_id  = (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.ec2: Creating...
aws_instance.ec2: Still creating... [10s elapsed]
aws_instance.ec2: Creation complete after 12s [id=i-09357bb8a63838d3c]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

6. terraform show (terraform으로 생성한 리소스 정보 출력)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform show
# aws_instance.ec2:
resource "aws_instance" "ec2" {
    ami                                  = "ami-0d3f686a76ad0de18"
    arn                                  = "arn:aws:ec2:ap-northeast-2:104818303680:instance/i-09357bb8a63838d3c"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-2d"
    cpu_core_count                       = 2
    cpu_threads_per_core                 = 2
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = "i-09357bb8a63838d3c"
    instance_initiated_shutdown_behavior = "stop"
    instance_state                       = "running"
    instance_type                        = "t3.xlarge"
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    monitoring                           = false
    primary_network_interface_id         = "eni-0b6f70ee1be02ab9e"
    private_dns                          = "ip-172-31-51-221.ap-northeast-2.compute.internal"
    private_ip                           = "172.31.51.221"
    public_dns                           = "ec2-3-37-15-65.ap-northeast-2.compute.amazonaws.com"
    public_ip                            = "3.37.15.65"
    secondary_private_ips                = []
    security_groups                      = [
        "default",
    ]
    source_dest_check                    = true
    subnet_id                            = "subnet-0aae81bee94e876cd"
    tags_all                             = {}
    tenancy                              = "default"
    vpc_security_group_ids               = [
        "sg-016d5d1659dfc56cd",
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = "open"
    }

    credit_specification {
        cpu_credits = "unlimited"
    }

    enclave_options {
        enabled = false
    }

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

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/xvda"
        encrypted             = false
        iops                  = 192
        tags                  = {}
        throughput            = 0
        volume_id             = "vol-01a8e901e3a88a529"
        volume_size           = 64
        volume_type           = "gp2"
    }
}
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

7. aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId" (현재 생성되어 있는 ec2 인스턴스)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId"
[
    "i-0667fadc7d193112d",
    "i-07647537570c72296",
    "i-09357bb8a63838d3c"
]
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

8. terraform destroy (terraform으로 생성한 리소스 삭제)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# terraform destroy
aws_instance.ec2: Refreshing state... [id=i-09357bb8a63838d3c]

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.ec2 will be destroyed
  - resource "aws_instance" "ec2" {
      - ami                                  = "ami-0d3f686a76ad0de18" -> null
      - arn                                  = "arn:aws:ec2:ap-northeast-2:104818303680:instance/i-09357bb8a63838d3c" -> null
      - associate_public_ip_address          = true -> null
      - availability_zone                    = "ap-northeast-2d" -> null
      - cpu_core_count                       = 2 -> null
      - cpu_threads_per_core                 = 2 -> null
      - disable_api_termination              = false -> null
      - ebs_optimized                        = false -> null
      - get_password_data                    = false -> null
      - hibernation                          = false -> null
      - id                                   = "i-09357bb8a63838d3c" -> null
      - instance_initiated_shutdown_behavior = "stop" -> null
      - instance_state                       = "running" -> null
      - instance_type                        = "t3.xlarge" -> null
      - ipv6_address_count                   = 0 -> null
      - ipv6_addresses                       = [] -> null
      - monitoring                           = false -> null
      - primary_network_interface_id         = "eni-0b6f70ee1be02ab9e" -> null
      - private_dns                          = "ip-172-31-51-221.ap-northeast-2.compute.internal" -> null
      - private_ip                           = "172.31.51.221" -> null
      - public_dns                           = "ec2-3-37-15-65.ap-northeast-2.compute.amazonaws.com" -> null
      - public_ip                            = "3.37.15.65" -> null
      - secondary_private_ips                = [] -> null
      - security_groups                      = [
          - "default",
        ] -> null
      - source_dest_check                    = true -> null
      - subnet_id                            = "subnet-0aae81bee94e876cd" -> null
      - tags                                 = {} -> null
      - tags_all                             = {} -> null
      - tenancy                              = "default" -> null
      - vpc_security_group_ids               = [
          - "sg-016d5d1659dfc56cd",
        ] -> null

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

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

      - enclave_options {
          - enabled = false -> null
        }

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

      - root_block_device {
          - delete_on_termination = true -> null
          - device_name           = "/dev/xvda" -> null
          - encrypted             = false -> null
          - iops                  = 192 -> null
          - tags                  = {} -> null
          - throughput            = 0 -> null
          - volume_id             = "vol-01a8e901e3a88a529" -> null
          - volume_size           = 64 -> 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.ec2: Destroying... [id=i-09357bb8a63838d3c]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 10s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 20s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 30s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 40s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 50s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 1m0s elapsed]
aws_instance.ec2: Still destroying... [id=i-09357bb8a63838d3c, 1m10s elapsed]
aws_instance.ec2: Destruction complete after 1m20s

Destroy complete! Resources: 1 destroyed.
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

9. aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId" (현재 생성되어 있는 ec2 인스턴스)

[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]# aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId"
[
    "i-0667fadc7d193112d",
    "i-07647537570c72296"
]
[root@ip-192-168-78-195 terraform (iam-root-account@NRSON-EKS-CLUSTER.ap-northeast-2.eksctl.io:kuberhealthy)]#

결론

이번 시간에는 Terraform 설치 및 ec2 instance를 생성하는 과정에 대해 Quick하게 알아보았다. Terraform은 Provider에 대한 제약이 없는 IaC로 다양한 환경에서 각광받고 있다. 이는 Public/Private Cloud 가리지 않고 여러 클라우드 인프라를 관리하는 주용 기술로써 활용되고 있다. 특히 사용하지 않는 인프라를 삭제하고 필요 시 일관성있게 생성하는 등 비용적인 이점도 가져갈 수 있다.

728x90
반응형