Terraform Settings (feat. AWS)

kimchigood·2023년 8월 29일
0
post-thumbnail
post-custom-banner

작년에 이어 Cloudnet@의 Terraform 스터디에 참여하게 되었다. 올해는 실무에 Terraform 도입을 했는데, 이번 스터디를 통해 복습도 할 겸, 그동안 새롭게 바뀐 부분도 알아보는 시간이 되면 좋을 것 같다.

Terraform?

Infrastructure as a Code(IaC) 의 표준이라고 할 수 있다. 인프라가 클라우드로 이동하면서 많은 사람들이 사용하고 있는 기술이기도 하다.

IaC가 필요한 이유는 CLI나 GUI를 통해 클라우드 리소스를 생성/수정/삭제 할 경우, 업무 담당자가 아닌 이상, 변경된 부분을 추적하거나 알아내기 힘들다.

뭐 간단한 아키텍처는 상관이 없겠지만, 실무에서는 큰 규모의 아키텍처를 다루므로, IaC를 통해 인프라를 코드로 관리한다.

  • 변경 히스토리 관리
  • 인프라 변경 전 코드리뷰
  • 형상관리

위와 같은 이점을 갖게 되므로, IaC는 클라우드에서 중요한 부분이라고 할 수 있다. CSP에서도 자신들만의 IaC를 제공하는데, AWS의 CloudFormation, Azure의 Bicep 등이 있다. Bicep을 잠깐 접한 적이있는데, Terraform의 HCL 문법과 매우 유사하다.

[Terraform]

# Create Azure Storage Account required for Function App
resource azurerm_storage_account "primary" {
  name                     = "b59storage"
  resource_group_name      = azurerm_resource_group.primary.name
  location                 = azurerm_resource_group.primary.location
  account_kine             = "StorageV2"
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

[Bicep]

param location string = resourceGroup().location
param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}

개인적으로는 범용으로 쓰이는 Terraform을 사용하는 것이 좋을 것 같다. 다만, Bicep과 같이 CSP 특화된 IaC를 사용할 경우, CSP의 신규 서비스에 대해 호환이 먼저 가능한 장점이 있다.

Terraform Cloud 관련된 정보도 있으니 참고하자. 참고로 소규모로 사용할 경우 무료로 사용이 가능하다.

1. Terraform Settings

자, 이제 terraform을 본인의 컴퓨터에 세팅해보자. 기존에는 바로 terraform을 설치해서 사용했는데, 이번에는 tfenv를 통해 설치해보도록 하겠다.

참고로 윈도우에서 terraform은 바로 설치가 되지 않으므로, wsl을 설치하도록 하자. wsl 설치는 매우 간단하니 검색을 통해 설치하자.

tfenv?
Terraform version manager로 terraform의 버전을 바꿔가며 사용하고 싶을 때 유용한 툴이다.

https://github.com/tfutils/tfenv 공식링크를 통해 가이드대로 따라하면 설치가 가능하다. wsl 관련 설명도 잘 나와있다.

$ git clone --depth=1 https://github.com/tfutils/tfenv.git ~/.tfenv
$ echo 'export PATH=$PATH:$HOME/.tfenv/bin' >> ~/.bashrc
$ ln -s ~/.tfenv/bin/* /usr/local/bin

설치확인

$ tfenv -v
tfenv 3.0.0

terraform 설치
tfenv로 terraform 설치를 할 수 있다.

$ tfenv list-remote # 설치 가능한 버전 목록 확인
$ sudo apt install unzip # wsl의 경우 unzip 패키지 설치를 해줘야한다
$ tfenv install 1.5.6
$ tfenv list # 설치 버전이 여러개일 경우 list로 나온다.
  1.5.6
  
$ tfenv use 1.5.6
$ terraform version
Terraform v1.5.6
on linux_amd64

2. AWS 연동

terraform 실습을 위해 aws와 연동해보자. 먼저 필요한 것은 aws access key이다. root 계정으로 접속 후 IAM 메뉴에서 User 생성 후 CLI용 Access 키를 생성할 수 있다.

aws cli 설치

$ sudo apt  install awscli

aws access key 연동

$ aws configure

$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************FR7G shared-credentials-file    
secret_key     ****************TXzn shared-credentials-file    
    region           ap-northeast-2      config-file    ~/.aws/config
 
# 페이저 사용 비활성화
export AWS_PAGER=""

# aws cli 사용 시도, s3가 없으면 아무것도 조회되지 않는다.
aws s3 ls


# Linux 편리한 툴 설치
$ sudo apt install -y tree jq

위와 같이 나오면 성공이다.

3. EC2 배포하기

그럼 바로 실습에 들어가보자.

#aws ec2 describe-images --owners self amazon
aws ec2 describe-images --owners self amazon --query 'Images[*].[ImageId]' --output text

aws ssm get-parameters-by-path --path /aws/service/ami-amazon-linux-latest
aws ssm get-parameters-by-path --path /aws/service/ami-amazon-linux-latest --query "Parameters[].Name"
aws ssm get-parameters-by-path --path /aws/service/ami-amazon-linux-latest --query "Parameters[].Value"

위 커맨드를 통해 aws에서 제공하는 ami를 검색할 수 있다.

terraform 코드 작성

  • provider : Terraform으로 정의할 Infrastructure Provider를 의미 - Docs
  • resource : 실제로 생성할 인프라 자원을 의미 - Docs
# VS Code 터미널2
cat <<EOT > main.tf
provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_instance" "example" {
  ami           = "ami-084e92d3e117f7692"
  instance_type = "t2.micro"
}
EOT

terraform 실행

# EC2 리소스 실시간 확인 
$ 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

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

  # aws_instance.example will be created
  + resource "aws_instance" "example" {
      + ami                                  = "ami-084e92d3e117f7692"
      + 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)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (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
      + spot_instance_request_id             = (known after apply)
      + 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)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)
    }

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.
$ terraform apply

결과화면
위에서 while로 걸어논 cli가 아래와 같이 나오면 실제로 리소스가 생성된 것이다.

------------------------------
------------------------------
------------------------------
None    43.201.105.183  running
------------------------------
None    43.201.105.183  running
------------------------------
None    43.201.105.183  running

기본적인 실습이라 매우 간단하다. 실제로 terraform은 그렇게 진입장벽이 매우 높지는 않은 것 같다. CSP별로 서비스가 다르고, terraform에서 제공하는 naming이 다르기 때문에, 문서를 보면서 잘 찾다보면 답이 나온다.

막히는 부분은 chatgpt에게 물어보면 꽤나 잘 답변해주므로 활용해봐도 좋을 것 같다.

리소스 정리

$ terraform destroy

4. web server 배포하기(도전과제)

EC2 웹 서버 배포 : Ubuntu 에 apache(httpd) 를 설치하고 index.html 생성(닉네임 출력)하는 user_data 를 작성해서 설정 배포, 포트는 TCP 80 후 curl 접속 → 해당 테라폼 코드(파일)를 작성

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

resource "aws_instance" "example" {
  ami                    = "ami-0c9c942bd7bf113a2"
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.instance.id]

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

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

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

  ingress {
    from_port   = 80
    to_port     = 80
    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"
}
$ terraform plan
$ terraform apply -auto-approve
$ PIP=$(terraform output -raw public_ip)

while true; do curl --connect-timeout 1  http://$PIP:80/ ; echo "------------------------------"
; date; sleep 1; done
Hello, Kimchigood Study
------------------------------
Tue Aug 29 22:50:00 KST 2023

5. 종속성

기본적으로 다른 리소스에서 값을 참조해 불러올 경우 생성 선후 관계에 따라 작업자가 의도하지는 않았지만 자동으로 연관 관계가 정의되는 암시적 종속성을 갖게 되고, 강제로 리소스 간 명시적 종속성을 부여할 경우에는 메타인수인 depends_on을 활용한다. - [참고: Docs]

이건 몰랐던 사실인데, 다른 리소스를 참조해올 경우, depends_on을 사용하지 않아도, 암시적 종속성 관계가 유지된다는 것이다.

vsCode에 graphviz 플러그인 설치 후 확인해보자.
main.tf

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

resource "local_file" "dev" {
  content  = local_file.abc.content    # 123! 
  filename = "${path.module}/def.txt"
}
terraform graph > graph-1.dot

profile
Shout out to Kubernetes⎈
post-custom-banner

0개의 댓글