cloudwithbass

[Terraform] 공부 내용 정리 본문

Terraform

[Terraform] 공부 내용 정리

여영클 2024. 8. 22. 18:21

 

목차


     

    테라폼이란?

    • Terraform은 HashiCorp사에서 공개한 IaC (Infra as a Code) 도구입니다. 
    • IaC를 이용해 인프라 구성/관리를 자동화할 수 있습니다.
    • 따라서 인프라 배포 시간이 단축되고, 휴먼 에러를 줄일 수 있습니다.
    • Terraform 외 IaC 도구는 Ansible, CloudFormation 등이 있습니다.

    Terraform 상태 파일

    • Terraform은 상태 파일(terraform.tfstate)을 사용해 인프라의 현재 상태를 추적합니다.
    • 이 상태 파일은 JSON 형식으로 저장되며, Terraform이 관리하는 모든 리소스의 정보를 담고 있습니다.
    • terraform apply 명령으로 인프라를 프로비저닝하면, 상태 파일인 terraform.tfstate를 생성합니다.
    • 새로운 terraform.tfstate 파일이 생성될 때마다 기존 파일을  terraform.tfstate.backup 파일로 자동으로 백업합니다.

    예를 들어보겠습니다.

     

     

    Terraform으로 aws ec2 인스턴스만을 프로비저닝 하면, terraform.tfstate 파일에는 해당 인스턴스의 정보가 기록됩니다.

     

    이후 테라폼 코드에 vpc를 추가한 후 terraform apply 명령을 실행하면, 테라폼은 현재 코드와 상태 파일을 비교하여 VPC가 현재 인프라에 없는 것을 인지하고 vpc를 생성합니다.

     

    이때, terraform.tfstate는 EC2와 VPC가 모두 있는 상태로 업데이트되며, 이전에 EC2만 있던 terraform.tfsate 파일은 terraform.tfstate.back 파이로 백업됩니다.


    Backend

    백엔드(backend)는 Terraform의 상태 파일(terraform.tfstate)을 저장하는 위치를 정의하는 기능입니다.

    기본적으로 로컬의 terraform.tfstate를 사용하지만, 협업 환경에선 원격 저장소에서 관리하는 것이 더 안전하고 효율적입니다.

     

    예를 들어 상태 파일을 AWS S3에 저장하는 경우는 다음과 같습니다.

    terraform{
      backend "s3" {
        bucket = "mybucket" #bucket name
        key = "terraform/myproject/state_file_name.tfstate" #상태 파일이 저장될 경로
        region = "ap-northeast-2"
      }
    }

     


    state manipulation

    Terraform의 terraform.tfstate 파일을 조작할 수 있습니다.

     

    • 예를 들어, terraform state rm 명령을 사용하여 특정 리소스를 상태 파일에서 제거할 수 있습니다.
    • Terraform은 상태 파일에서 제거된 리소스를 더 이상 추적하지 않습니다.
    • 그 상태에서 terraform destroy 명령을 실행하면, 상태 파일에 없는 리소스는 모르는 것으로 간주되므로 삭제되지 않고 클라우드 공급자에 남아 있게 됩니다.

    예를 들어, 사용 가능한 state manipulation 명령은 다음과 같습니다.

    • terraform state list: 현재 상태 파일에 있는 모든 리소스를 나열합니다.
    • terraform state show [RESOURCE]: 특정 리소스의 상태를 자세히 출력합니다.
    • terraform state rm [RESOURCE]: 특정 리소스를 상태 파일에서 제거합니다.
    • terraform state mv [SOURCE] [DESTINATION]: 리소스의 이름이나 위치를 변경합니다.
      •  
      • 리눅스의 mv 명령어처럼 사용합니다
    • 등등 

    Datasources

    • data 블록은 테라폼으로 정의되지 않은 외부 리소스를 테라폼 내에서 참조할 때 사용합니다.

     

    Datasource 예시 1: AMI

    # Find the latest available AMI that is tagged with Component = web
    data "aws_ami" "web" {
      filter {
        name   = "state"
        values = ["available"]
      }
    
      filter {
        name   = "tag:Component"
        values = ["web"]
      }
    
      most_recent = true
    }

    코드 출처: https://developer.hashicorp.com/terraform/language/data-sources   

     

    위 코드는 state가 available이고, Component 태그가 web이며, 가장 최신 버전의 ami를 찾습니다.

    즉, 외부 리소스를 찾아옵니다.

     

    이제 위 데이터 소스를 아래와 같이, 테라폼 내부에서 활용할 수 있습니다.

    resource "aws_instance" "example" {
      ami           = data.aws_ami.web.id
      instance_type = "t2.micro"
      ...
    }

     

    Datasource 예시 2: aws_ip_ranges

    data "aws_ip_ranges" "european_ec2" {
      regions  = ["eu-west-1", "eu-central-1"]
      services = ["ec2"]
    }
    
    resource "aws_security_group" "from_europe" {
      name = "from_europe"
    
      ingress {
        from_port   = "443"
        to_port     = "443"
        protocol    = "tcp"
        cidr_blocks = slice(data.aws_ip_ranges.european_ec2.cidr_blocks, 0, 50)
      }
      tags = {
        CreateDate = data.aws_ip_ranges.european_ec2.create_date
        SyncToken  = data.aws_ip_ranges.european_ec2.sync_token
      }
    }

    코드 출처: Udemy 강의, Devops: 테라폼을 이용한 인프라 자동화

     

    AWS에선 ip-ranges.json 파일을 제공하는데요, 이 파일에는 다양한 AWS 서비스들의 IP 주소 범위가 기록되어 있습니다.

    (참고 문서: https://docs.aws.amazon.com/ko_kr/vpc/latest/userguide/aws-ip-ranges.html, ip-ranges.json 문서 확인)

     

    aws_ip_ranges 데이터 리소스는 지정한 AWS 리전과 서비스의 ip 주소 범위를 가져옵니다.

    이 데이터 리소스를 보안 그룹에 사용하면, 지정한 리전의 지정한 서비스와 통신할 수 있습니다.

     

    Q. data sources의 종류는 어디서 확인할 수 있나요?

    A. 테라폼 공식 문서의 aws provider에서 좌측에 Data Sources를 검색하면 됩니다.


    Lockfile

    https://developer.hashicorp.com/terraform/language/files/dependency-lock#dependency-lock-file

    terraform init 명령을 실행하면 terraform.lock.hcl 파일이 생성됩니다.

    이 파일은 테라폼을 협업해서 사용할 때 프로바이더 버전을 고정하는 역할을 합니다.

    파일을 열어보면 아래와 같이 provider, version, constraints, hash가 존재합니다.

     

    • provider: Terraform이 사용하는 프로바이더의 이름과 소스 정보를 나타냅니다.
    • version: 프로바이더의 특정 버전이 명시됩니다.
      이 버전은 Terraform이 해당 프로바이더를 사용할 때 항상 고정된 버전을 사용하도록 보장합니다.
    • constraints: 프로바이더의 버전에 대해 적용된 제약 조건을 나타냅니다.
      예를 들어, 최소 버전, 최대 버전 등이 여기에 포함될 수 있습니다.
      테라폼은 이 정보를 사용하지 않고, 사람이 읽기 위해 있는 항목입니다.
    • hash: 프로바이더 패키지의 무결성을 확인하기 위한 해시 값입니다.
      각 해시의 prefix에 대한 정보는 이 문서에서 확인할 수 있습니다.

     

     

     


    테라폼 기초 문법

    조건문

    CONDITION ? TRUEVAL : FALSEVAL

    resource "aws_instance" "myinstance" {
      ...
      count = ${var.env == "pord" ? 2 : 1}
    }

     


    반복문: for_each와 count

    기본적으로 하나의 리소스 블록은 하나의 오브젝트를 프로비저닝합니다.

    따라서 여러 오브젝트를 프로비저닝 하려면 여러 리소스 블록이 필요한데, 추가 블록 없이 유사한 오브젝트를 프로비저닝 할 경우 반복문을 사용합니다.

     

    For_each

    variable "ports" {
      type = map(list(string))
      default = {
        "22" = [ "127.0.0.1/32", "192.168.0.0/24" ]
        "443" = [ "0.0.0.0/0" ]
      }
    }
    
    resource "aws_security_group" "example" {
      name = "example" # can use expressions here
    
      dynamic "ingress" {
        for_each = var.ports
        content {
          from_port   = ingress.key
          to_port     = ingress.key
          cidr_blocks = ingress.value
          protocol    = "tcp"
        }
      }
    }
    • dynamic 블록은 일반적으로 for_each와 함께 쓰이며, 반복적으로 생성할 블록을 정의할 수 있습니다.
    • resource 블록 내에선 for_each를 이용해 map type인 var.ports를 참조해서 var.ports의 길이만큼 리소스를 생성합니다.
    • 따라서 위 코드는 아래 사진처럼, 보안 그룹의 ingress로 22번 포트(SSH)의 127.0.0.1/32, 192.168.0.0/24와 443 포트(HTTPS)의 0.0.0.0/0을 허용합니다.

     

    Count

    resource "aws_instance" "server" {
      count = 4 # create four similar EC2 instances
    
      ami           = "ami-a1b2c3d4"
      instance_type = "t2.micro"
    
      tags = {
        Name = "Server ${count.index}"
      }
    }
    • count는 반복할 횟수를 나타내며, 0부터 시작합니다.
    • 따라서 위 코드는 4개의 ec2 인스턴스를 생성하며, 이름은 각각 Server 0, Server 1, Server 2, Server 3입니다.

     



    테라폼 내장 함수

    는  공식 문서를 참고바랍니다.


    Map

    variable "AWS_REGION" {
      type    = string
      default = "eu-west-1"
    }
    variable "project_tags" {
      type          = map(string)
      default       = {
        Component   = "Frontend"
        Environment = "Production"
      }
    }
    
    resource "aws_ebs_volume" "example" {
      availability_zone = "eu-west-1a"
      size              = 8
    
      tags = {for k, v in merge({ Name = "Myvolume" }, var.project_tags): k => lower(v)}
    }

    { Name = "Myvolume" }와 var.project_tags map을 merge해서 key와 소문자 value를 tags로 사용

    map에선 k => v 꼴로 key와 value를 사용할 수 있습니다.