관리 메뉴

근묵자흑

workflow 본문

IaC/terraform

workflow

Luuuuu 2024. 11. 5. 19:56

규모에 따른 워크플로우

개인의 workflow

  1. write
  2. plan
  3. apply

다중 작업자 / 다수 팀 workflow

  1. write
  2. plan
  3. apply

git Action을 사용한 workflow

Example with git action

name: Example Service Release

on:
  workflow_dispatch:
  push:
    branches: [main]
    paths: ["terraform/**"]

  pull_request:
    branches: [main]
    paths: ["terraform/**"]

jobs:
  plan:
    name: Terraform plan
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js 14.x
        uses: actions/setup-node@v1
        with:
          node-version: 14.x
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID}}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: eu-west-2
      - name: Initialise project and view terraform plan
        run: |
          cd terraform 
          cd qa
          terraform fmt
          terraform init 
          terraform plan -var='example_api_key=${{ secrets.EXAMPLE_API_KEY }}'

  deploy:
    name: Terraform Deploy
    needs: plan
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-20.04
    steps:
      - uses: actions/checkout@v3
      - name: Use Node.js 14.x
        uses: actions/setup-node@v1
        with:
          node-version: 14.x
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: eu-west-2
      - name: Initialise project and deploy terraform
        run: |
          cd terraform
          cd qa
          terraform fmt
          terraform init
          terraform apply -var='example_api_key=${{ secrets.EXAMPLE_API_KEY }}' --auto-approve=true

테스트 프레임워크

테라폼 코드와 테라폼으로 구성되는 인프라를 테스트하기 위한 테스트 프레임워크를 사용하면 프로비저닝이 실행되기 전 단계부터 실제 인프라를 만드는 전 과정 (end to end)에 걸쳐 견고한 IaC 를 구현 할 수 있다.

Check block

테라폼 1.5버전에서 추가된 check block은 테라폼 수행 이후 적용된 내용을 검증하여 사용자와 실제 형상 간의 격차를 줄이는 데 목적이 있다.

(https://developer.hashicorp.com/terraform/language/checks)

check "health_check" {
  data "http" "terraform_io" {
    url = "https://www.terraform.io"
  }

  assert {
    condition = data.http.terraform_io.status_code == 200
    error_message = "${data.http.terraform_io.url} returned an unhealthy status code"
  }
}

health_check라는 이름을 갖는 check 블록은 http 요청에 대한 응답을 검증하는 예제이다.

test 명령

$ terraform test -verbose
  • tests 가 디렉터리로 생성 돼 있어야 기본값으로 파일 테스트 파일 위치를 가리킨다.
    • -test-directory 옵션으로 변경 가능

variables 에 설정된 값은 루트 모듈의 입력 변수를 덮어쓰는 의미로, 테스트 위한 프로비저닝과 실제 원하는 형상의 프로비저닝에 대한 입력 변수를 다르게 구성할 수 있다.


PS D:\git\terraform-aws-ec2-test-module> terraform test -verbose
tests\public_ip_check.tftest.hcl... in progress
  run "public_ip_check"... pass

# data.aws_ami.default:
data "aws_ami" "default" {
    architecture          = "x86_64"
    arn                   = "arn:aws:ec2:ap-southeast-1::image/ami-0a8a03611fc5fbdac"
    block_device_mappings = [
        {
            device_name  = "/dev/xvda"
            ebs          = {
                "delete_on_termination" = "true"
                "encrypted"             = "false"
                "iops"                  = "0"
                "snapshot_id"           = "snap-035fb8629b88f63d9"
                "throughput"            = "0"
                "volume_size"           = "8"
                "volume_type"           = "gp2"
            }
            no_device    = null
            virtual_name = null
        },
    ]
    boot_mode             = null
    creation_date         = "2024-10-14T21:50:56.000Z"
    deprecation_time      = "2025-07-01T00:00:00.000Z"
    description           = "Amazon Linux 2 AMI 2.0.20241014.0 x86_64 HVM gp2"
    ena_support           = true
    hypervisor            = "xen"
    id                    = "ami-0a8a03611fc5fbdac"
    image_id              = "ami-0a8a03611fc5fbdac"
    image_location        = "amazon/amzn2-ami-hvm-2.0.20241014.0-x86_64-gp2"
    image_owner_alias     = "amazon"
    image_type            = "machine"
    imds_support          = null
    include_deprecated    = false
    kernel_id             = null
    most_recent           = true
    name                  = "amzn2-ami-hvm-2.0.20241014.0-x86_64-gp2"
    owner_id              = "137112412989"
    owners                = [
        "amazon",
    ]
    platform              = null
    platform_details      = "Linux/UNIX"
    product_codes         = []
    public                = true
    ramdisk_id            = null
    root_device_name      = "/dev/xvda"
    root_device_type      = "ebs"
    root_snapshot_id      = "snap-035fb8629b88f63d9"
    sriov_net_support     = "simple"
    state                 = "available"
    state_reason          = {
        "code"    = "UNSET"
        "message" = "UNSET"
    }
    tags                  = {}
    tpm_support           = null
    usage_operation       = "RunInstances"
    virtualization_type   = "hvm"

    filter {
        name   = "architecture"
        values = [
            "x86_64",
        ]
    }
    filter {
        name   = "name"
        values = [
            "amzn2-ami-hvm*",
        ]
    }
    filter {
        name   = "owner-alias"
        values = [
            "amazon",
        ]
    }
}

# aws_default_vpc.default:
resource "aws_default_vpc" "default" {
    arn                                  = "arn:aws:ec2:ap-southeast-1:939204296150:vpc/vpc-02d709e335a468f18"
    assign_generated_ipv6_cidr_block     = false
    cidr_block                           = "172.31.0.0/16"
    default_network_acl_id               = "acl-0c10b603838427e4c"
    default_route_table_id               = "rtb-0671bd26e205e27db"
    default_security_group_id            = "sg-069338c89edf101dc"
    dhcp_options_id                      = "dopt-39b7265d"
    enable_dns_hostnames                 = true
    enable_dns_support                   = true
    enable_network_address_usage_metrics = false
    existing_default_vpc                 = false
    force_destroy                        = false
    id                                   = "vpc-02d709e335a468f18"
    instance_tenancy                     = "default"
    ipv6_association_id                  = null
    ipv6_cidr_block                      = null
    ipv6_cidr_block_network_border_group = null
    ipv6_ipam_pool_id                    = null
    ipv6_netmask_length                  = 0
    main_route_table_id                  = "rtb-0671bd26e205e27db"
    owner_id                             = "939204296150"
    tags_all                             = {}
}

# aws_instance.default:
resource "aws_instance" "default" {
    ami                                  = "ami-0a8a03611fc5fbdac"
    arn                                  = "arn:aws:ec2:ap-southeast-1:939204296150:instance/i-046c81b5b5c170f66"
    associate_public_ip_address          = true
    availability_zone                    = "ap-southeast-1b"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 2
    disable_api_stop                     = false
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    host_id                              = null
    iam_instance_profile                 = null
    id                                   = "i-046c81b5b5c170f66"
    instance_initiated_shutdown_behavior = "stop"
    instance_lifecycle                   = null
    instance_state                       = "running"
    instance_type                        = "t3.nano"
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    key_name                             = null
    monitoring                           = false
    outpost_arn                          = null
    password_data                        = null
    placement_group                      = null
    placement_partition_number           = 0
    primary_network_interface_id         = "eni-02c510e7bbf9b9e79"
    private_dns                          = "ip-172-31-32-84.ap-southeast-1.compute.internal"
    private_ip                           = "172.31.32.84"
    public_dns                           = "ec2-54-179-169-76.ap-southeast-1.compute.amazonaws.com"
    public_ip                            = "54.179.169.76"
    secondary_private_ips                = []
    security_groups                      = [
        "default",
    ]
    source_dest_check                    = true
    spot_instance_request_id             = null
    subnet_id                            = "subnet-097a9d93997b97b10"
    tags                                 = {
        "Name" = "my_ec2"
    }
    tags_all                             = {
        "Name" = "my_ec2"
    }
    tenancy                              = "default"
    user_data_replace_on_change          = false
    vpc_security_group_ids               = [
        "sg-069338c89edf101dc",
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = "open"
    }

    cpu_options {
        amd_sev_snp      = null
        core_count       = 1
        threads_per_core = 2
    }

    credit_specification {
        cpu_credits = "unlimited"
    }

    enclave_options {
        enabled = false
    }

    maintenance_options {
        auto_recovery = "default"
    }

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

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

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/xvda"
        encrypted             = false
        iops                  = 100
        kms_key_id            = null
        tags                  = {}
        tags_all              = {}
        throughput            = 0
        volume_id             = "vol-010957e4708d8e07e"
        volume_size           = 8
        volume_type           = "gp2"
    }
}


Outputs:

private_ip = "172.31.32.84"
public_ip = "54.179.169.76"

tests\public_ip_check.tftest.hcl... tearing down
tests\public_ip_check.tftest.hcl... pass

Success! 1 passed, 0 failed.

'IaC > terraform' 카테고리의 다른 글

Terraform Module  (8) 2025.01.05
Terraform State  (3) 2024.12.29
테라폼 로드밸런서 배포  (5) 2024.12.22
왜 테라폼 인가?  (4) 2024.12.15
Terraform provider  (7) 2024.10.20