πŸ“’ ν…ŒλΌνΌ(Terraform) μ΄λž€?

ν…ŒλΌνΌ(Terraform)은 μΈν”„λΌμŠ€νŠΈλŸ­μ²˜λ₯Ό μ½”λ“œλ‘œ κ΄€λ¦¬ν•˜κΈ° μœ„ν•œ μ˜€ν”ˆμ†ŒμŠ€ λ„κ΅¬μž…λ‹ˆλ‹€. AWS, Google Cloud Platform, Microsoft Azure λ“± λ‹€μ–‘ν•œ ν΄λΌμš°λ“œ μ„œλΉ„μŠ€ 및 μ˜¨ν”„λ ˆλ―ΈμŠ€ 인프라λ₯Ό μ§€μ›ν•˜λ©°, μ½”λ“œλ‘œ 인프라λ₯Ό κ΅¬μ„±ν•˜κ³  변경사항을 좔적, 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

ν…ŒλΌνΌμ„ μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

μž₯점:

  • μ½”λ“œλ‘œ 인프라λ₯Ό κ΄€λ¦¬ν•˜κΈ° λ•Œλ¬Έμ—, 반볡적이고 일관성 μžˆλŠ” 인프라 ꡬ성이 κ°€λŠ₯ν•©λ‹ˆλ‹€.

  • μ½”λ“œ 관리 도ꡬ(Git λ“±)λ₯Ό μ‚¬μš©ν•˜μ—¬ λ³€κ²½ 이λ ₯을 μΆ”μ ν•˜κ³ , 이λ ₯에 따라 인프라λ₯Ό 볡원할 수 μžˆμŠ΅λ‹ˆλ‹€.

  • λ‹€μ–‘ν•œ ν΄λΌμš°λ“œ μ„œλΉ„μŠ€ 및 μ˜¨ν”„λ ˆλ―ΈμŠ€ 인프라λ₯Ό μ§€μ›ν•˜λ©°, 인프라 λ³΅μž‘λ„κ°€ 높아지더라도 μ½”λ“œλ‘œ 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

  • ν…ŒλΌνΌμ€ 인프라λ₯Ό λ³€κ²½ν•  λ•Œ μƒˆλ‘œμš΄ 인프라λ₯Ό λ§Œλ“€κ³  이전 인프라λ₯Ό μ œκ±°ν•˜λŠ” λ°©μ‹μœΌλ‘œ 변경사항을 μ μš©ν•©λ‹ˆλ‹€. 이λ₯Ό 톡해 변경사항 적용 쀑에도 μΈν”„λΌμ˜ μ•ˆμ •μ„±μ„ μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

단점:

  • ν•™μŠ΅ 곑선이 λ†’μŠ΅λ‹ˆλ‹€. ν…ŒλΌνΌμ€ λ‹€μ–‘ν•œ κΈ°λŠ₯κ³Ό ꡬ성 μš”μ†Œλ₯Ό μ œκ³΅ν•˜κΈ° λ•Œλ¬Έμ— 처음 μ ‘κ·Όν•˜λŠ” μ‚¬μš©μžμ—κ²ŒλŠ” μ΄ν•΄ν•˜κΈ° μ–΄λ €μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν…ŒλΌνΌ μ½”λ“œ μž‘μ„± μ‹œ λͺ¨λ“ˆν™”κ°€ ν•„μš”ν•œ κ²½μš°κ°€ λ§ŽμŠ΅λ‹ˆλ‹€.
  • λͺ¨λ“ˆν™”λœ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ €λ©΄, 좔가적인 ν•™μŠ΅κ³Ό κ²½ν—˜μ΄ ν•„μš”ν•©λ‹ˆλ‹€.

βš™οΈ ν…ŒλΌνΌμ˜ κΈ°λ³Έ 파일 ꡬ성 및 μ…ˆν”Œ 정리

  • main.tf νŒŒμΌμ—λŠ” 인프라λ₯Ό κ΅¬μ„±ν•˜λŠ” λ¦¬μ†ŒμŠ€μ™€ 데이터 μ†ŒμŠ€λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

    provider "aws" {
        region = var.region
    }
    
    resource "aws_instance" "example" {
        ami           = var.ami_id
        instance_type = var.instance_type
    
        tags = {
            Name = "ExampleInstance"
        }
    }
  • variables.tf νŒŒμΌμ—λŠ” μž…λ ₯ λ³€μˆ˜λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

    variable "region" {
        type        = string
        description = "AWS region to create resources in"
        default     = "us-west-2"
    }
    
    variable "ami_id" {
        type        = string
        description = "AMI ID for EC2 instance"
    }
    
    variable "instance_type" {
        type        = string
        description = "EC2 instance type"
        default     = "t2.micro"
    }
  • outputs.tf νŒŒμΌμ—λŠ” 좜λ ₯ λ³€μˆ˜λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

    output "public_ip" {
        value = aws_instance.example.public_ip
    }
    
  • backend.tf ν…ŒλΌνΌ μƒνƒœ νŒŒμΌμ„ μ €μž₯ν•˜λŠ” μœ„μΉ˜μ™€ ν˜•μ‹μ„ 지정할 수 μžˆμŠ΅λ‹ˆλ‹€.

    # S3 버킷에 μƒνƒœλ₯Ό μ €μž₯ν•˜λŠ”λ° μ‚¬μš©ν•©λ‹ˆλ‹€. 
    # λ™μ‹œμ„± 체크 및 이미 λ§Œλ“€μ–΄μ Έ μ—°κ΄€ μžˆλŠ” ꡬ쑰λ₯Ό κ°–κ³ μ˜¬ λ–„ μ‚¬μš©ν•©λ‹ˆλ‹€.
    terraform {
     backend "s3" {
            bucket = "my-terraform-state"
            key    = "terraform.tfstate"
            region = "us-west-2"
        }
    }
  • env.tfvars νŒŒμΌμ—μ„œλŠ” ν™˜κ²½ λ³€μˆ˜λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€. ν™˜κ²½ λ³€μˆ˜λŠ” ν…ŒλΌνΌ μ‹€ν–‰ μ‹œ -var-file μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ—¬ 지정할 수 μžˆμŠ΅λ‹ˆλ‹€.

    region          = "us-west-2"
    ami_id          = "ami-0c55b159cbfafe1f0"
    instance_type   = "t2.micro"

βš™οΈ ꡬ성 문법은 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • data : λ¦¬μ†ŒμŠ€κ°€ μ•„λ‹Œ 데이터 μ†ŒμŠ€(Data Source)λ₯Ό μ •μ˜ν•˜λŠ” λͺ…λ Ήμ–΄μž…λ‹ˆλ‹€.

  • module : λͺ¨λ“ˆ(Module)을 μ •μ˜ν•˜λŠ” λͺ…λ Ήμ–΄μž…λ‹ˆλ‹€. λͺ¨λ“ˆμ€ μž¬μ‚¬μš© κ°€λŠ₯ν•œ μ½”λ“œ λΈ”λ‘μœΌλ‘œ, ν…ŒλΌνΌ μ½”λ“œλ₯Ό λ”μš± λͺ¨λ“ˆν™”ν•˜μ—¬ μ½”λ“œμ˜ 가독성과 μœ μ§€λ³΄μˆ˜μ„±μ„ 높일 수 μžˆμŠ΅λ‹ˆλ‹€.

    module "vpc" {
        # source μ„ μ–Έλœ 디렉토리 메인 μ½”λ“œμ˜ ν˜ΈμΆœν•˜λŠ”λ° μ‚¬μš©λ©λ‹ˆλ‹€.
        source = "terraform-aws-modules/vpc/aws"
    
        name                 = "example-vpc"
        cidr                 = "10.0.0.0/16"
        azs                  = ["us-west-2a", "us-west-2b"]
        public_subnets       = ["10.0.1.0/24", "10.0.2.0/24"]
        private_subnets      = ["10.0.10.0/24", "10.0.20.0/24"]
        enable_nat_gateway   = true
        single_nat_gateway   = true
        enable_dns_hostnames = true
    }
  • provider : μ‚¬μš©ν•  ν΄λΌμš°λ“œ μ„œλΉ„μŠ€ κ³΅κΈ‰μž(Provider)λ₯Ό μ •μ˜ν•˜λŠ” λͺ…λ Ήμ–΄μž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, AWSλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 provider β€œaws” {}와 같이 μž‘μ„±ν•©λ‹ˆλ‹€.

    provider "aws" {
        region = "us-west-2"
    }
    
    resource "aws_instance" "example" {
        ami           = "ami-0c55b159cbfafe1f0"
        instance_type = "t2.micro"
    }
  • variable : μž…λ ₯ λ³€μˆ˜(Variable)λ₯Ό μ •μ˜ν•˜λŠ” λͺ…λ Ήμ–΄μž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, νŠΉμ • AMI IDλ₯Ό λ³€μˆ˜λ‘œ μ§€μ •ν•˜μ—¬ EC2 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 경우 variable β€œami_id” {}와 같이 μž‘μ„±ν•©λ‹ˆλ‹€.

    variable "ami_id" {
        type        = string
        description = "AMI ID for EC2 instance"
    }
    
    resource "aws_instance" "example" {
        ami           = var.ami_id
        instance_type = "t2.micro"
    }
  • output : 좜λ ₯ λ³€μˆ˜(Output)λ₯Ό μ •μ˜ν•˜λŠ” λͺ…λ Ήμ–΄μž…λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, EC2 μΈμŠ€ν„΄μŠ€μ˜ IP μ£Όμ†Œλ₯Ό 좜λ ₯ν•˜λŠ” 경우 output β€œinstance_ip” {}와 같이 μž‘μ„±ν•©λ‹ˆλ‹€.

    resource "aws_instance" "example" {
        ami           = "ami-0c55b159cbfafe1f0"
        instance_type = "t2.micro"
    
        provisioner "local-exec" {
            command = "echo ${self.public_ip} > ip_address.txt"
        }
    }
    
    output "instance_ip" {
        value = aws_instance.example.public_ip
    }

πŸ”— μ—¬λŸ¬κ°€μ§€μ˜ μ•„ν‚€ν…μ²˜ 정리

μ΄ˆμ•ˆ 1

β”œβ”€β”€ main.tf
β”œβ”€β”€ variables.tf
β”œβ”€β”€ outputs.tf
β”œβ”€β”€ backend.tf
β”œβ”€β”€ env.tfvars
β”œβ”€β”€ modules
β”‚   β”œβ”€β”€ vpc
β”‚   β”‚   β”œβ”€β”€ main.tf
β”‚   β”‚   β”œβ”€β”€ variables.tf
β”‚   β”‚   β”œβ”€β”€ outputs.tf
β”‚   β”‚   └── README.md
β”‚   β”œβ”€β”€ ec2
β”‚   β”‚   β”œβ”€β”€ main.tf
β”‚   β”‚   β”œβ”€β”€ variables.tf
β”‚   β”‚   β”œβ”€β”€ outputs.tf
β”‚   β”‚   └── README.md
β”‚   └── ...
β”œβ”€β”€ data
β”‚   β”œβ”€β”€ example.tf
β”‚   └── ...
└── README.md

μ΄ˆμ•ˆ 2

β”œβ”€β”€ infra
β”‚   β”œβ”€β”€ rds
β”‚   β”‚   β”œβ”€β”€ mariana_db
β”‚   β”‚   β”‚   β”œβ”€β”€ README.md
β”‚   β”‚   β”‚   β”œβ”€β”€ backend.tf
β”‚   β”‚   β”‚   β”œβ”€β”€ env-dev.tfvars
β”‚   β”‚   β”‚   β”œβ”€β”€ env-staging.tfvars
β”‚   β”‚   β”‚   β”œβ”€β”€ main.tf
β”‚   β”‚   β”‚   β”œβ”€β”€ terraform.tf
β”‚   β”‚   β”‚   └── variables.tf
β”‚   └── vpc
β”‚       β”œβ”€β”€ README.md
β”‚       β”œβ”€β”€ backend.tf
β”‚       β”œβ”€β”€ env-dev.tfvars
β”‚       β”œβ”€β”€ env-staging.tfvars
β”‚       β”œβ”€β”€ main.tf
β”‚       β”œβ”€β”€ terraform.tf
β”‚       └── variables.tf
β”œβ”€β”€ modules
β”‚   β”œβ”€β”€ ec2
β”‚   β”‚   β”œβ”€β”€ ec2.tf
β”‚   β”‚   β”œβ”€β”€ main.tf
β”‚   β”‚   β”œβ”€β”€ output.tf
β”‚   β”‚   └── variables.tf
β”‚   β”œβ”€β”€ loadbalancer
β”‚   β”‚   β”œβ”€β”€ main.tf
β”‚   β”‚   └── variables.tf
β”‚   └── ...
└── service
    β”œβ”€β”€ backend_example
    β”‚   β”œβ”€β”€ README.md
    β”‚   β”œβ”€β”€ alb.tf
    β”‚   β”œβ”€β”€ ec2.tf
    β”‚   β”œβ”€β”€ provider.tf
    β”‚   β”œβ”€β”€ script.sh
    β”‚   β”œβ”€β”€ terraform.tfvars
    β”‚   └── variables.tf
    β”œβ”€β”€ frontend_example
    β”‚    β”œβ”€β”€ README.md
    β”‚    β”œβ”€β”€ backend.tf
    β”‚    β”œβ”€β”€ env-dev.tfvars
    β”‚    β”œβ”€β”€ env-prod.tfvars
    β”‚    β”œβ”€β”€ env-stage.tfvars
    β”‚    β”œβ”€β”€ main.tf
    β”‚    β”œβ”€β”€ terraform.tf
    β”‚    └── variables.tf
    β”‚
    └── ...

βœ’οΈ ν…ŒλΌνΌ μ‹€ν–‰ λͺ…λ Ήμ–΄λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

terraform init      # λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•˜μ—¬ ν…ŒλΌνΌ 섀정을 μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.
terraform plan      # λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•˜μ—¬ 인프라 변경사항을 κ²€ν† ν•©λ‹ˆλ‹€.
terraform apply     # λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•˜μ—¬ 인프라 변경사항을 μ μš©ν•©λ‹ˆλ‹€.
terraform destroy   # λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•˜μ—¬ 인프라λ₯Ό μ œκ±°ν•©λ‹ˆλ‹€.

πŸ’™ μ†Œκ°

  • μ΄μƒμœΌλ‘œ ν…ŒλΌνΌ(Terraform)에 λŒ€ν•œ 기본적인 λ‚΄μš©κ³Ό ν…ŒλΌνΌ μ½”λ“œμ˜ ꡬ쑰, λͺ…λ Ήμ–΄ 등에 λŒ€ν•΄ μ•Œμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

  • ν…ŒλΌνΌμ€ ν΄λΌμš°λ“œ 인프라λ₯Ό μ½”λ“œλ‘œ κ΄€λ¦¬ν•˜κ³ , μžλ™ν™”λœ 인프라 배포λ₯Ό κ°€λŠ₯μΌ€ ν•΄μ£ΌλŠ” κ°•λ ₯ν•œ λ„κ΅¬μž…λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ ν…ŒλΌνΌκ³Ό 같이 μ“°λ©΄ 쒋은것듀 !

  • Packer: 인프라λ₯Ό μœ„ν•œ μ»€μŠ€ν…€ 이미지λ₯Ό λ§Œλ“€κΈ° μœ„ν•œ λ„κ΅¬μž…λ‹ˆλ‹€. Packerλ₯Ό μ‚¬μš©ν•˜λ©΄ 인프라 λ¦¬μ†ŒμŠ€λ₯Ό 미리 μ„€μΉ˜ν•˜κ³  κ΅¬μ„±ν•˜μ—¬ μ»€μŠ€ν…€ 이미지λ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

  • Vault: λ³΄μ•ˆ 관리 λ„κ΅¬λ‘œ, ν…ŒλΌνΌμ—μ„œ μ‚¬μš©λ˜λŠ” λΉ„λ°€ 정보λ₯Ό μ•ˆμ „ν•˜κ²Œ 관리할 수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

  • Atlantis: ν…ŒλΌνΌ μ½”λ“œμ˜ λ³€κ²½ 사항을 버전 관리 μ‹œμŠ€ν…œκ³Ό μ—°λ™ν•˜μ—¬ μžλ™ν™”λœ μ½”λ“œ κ²€ν† λ₯Ό μ œκ³΅ν•˜λŠ” λ„κ΅¬μž…λ‹ˆλ‹€.

  • Terratest: ν…ŒλΌνΌ μ½”λ“œμ˜ λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ λ„κ΅¬λ‘œ, ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ—¬ ν…ŒλΌνΌ μ½”λ“œ λ³€κ²½ 사항이 ν”„λ‘œλ•μ…˜μ— 영ν–₯을 λ―ΈμΉ˜μ§€ μ•Šλ„λ‘ 보μž₯ν•©λ‹ˆλ‹€.

이 외에도 λ‹€μ–‘ν•œ ν…ŒλΌνΌκ³Ό κ΄€λ ¨λœ 도ꡬ듀이 μžˆμŠ΅λ‹ˆλ‹€. 이듀 도ꡬ듀을 ν™œμš©ν•˜λ©΄ ν…ŒλΌνΌμ„ λ”μš± 효율적으둜 μ‚¬μš©ν•  수 있으며, μ½”λ“œμ˜ 가독성과 μœ μ§€λ³΄μˆ˜μ„±μ„ 높일 수 μžˆμŠ΅λ‹ˆλ‹€.

κ°μ‚¬ν•©λ‹ˆλ‹€!