본문 바로가기!

Terraform

[Terraform] Moved Block을 통한 코드 리팩터링 & Provider alias

728x90
반응형

Terraform 0.13부터 moved 블록을 사용하여 리소스를 안전하게 이동하고 리팩터링할 수 있습니다. 이를 통해 리소스 이름이나 경로를 변경할 때 상태 파일을 안전하게 업데이트할 수 있습니다.

 

Terraform Provider alias는 같은 Provider의 여러 인스턴스를 설정할 수 있도록 합니다. 이를 통해 서로 다른 설정을 가진 여러 Provider를 사용할 수 있습니다.

 

 

1. moved Block을 통한 코드 리팩터링

moved block은 테라폼 코드에서 리소스의 이름은 변경되지만 이미 테라폼으로 프로비저닝 환경을 그대로 유지하고자 하는 경우 사용합니다.

 

moved Block의 기본 문법

moved {
  from = aws_instance.old_name
  to   = aws_instance.new_name
}

 

 

 

 

1-1) moved block 예시

1. moved block을 사용한 테라폼 코드 작성

resource "aws_vpc" "vpc" {
  cidr_block           = var.vpc_cidr
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "${var.env}-vpc"
  }
}

resource "aws_subnet" "pub_subnet3" {
  vpc_id            = aws_vpc.vpc.id
  cidr_block        = var.pub_cidr[0]
  availability_zone = data.aws_availability_zones.az.names[0]
  tags = {
    Name = "${var.env}-pub-${data.aws_availability_zones.az.names[0]}"
  }
}

resource "aws_subnet" "pub_subnet4" {
  vpc_id            = aws_vpc.vpc.id
  cidr_block        = var.pub_cidr[1]
  availability_zone = data.aws_availability_zones.az.names[2]
  tags = {
    Name = "${var.env}-pub-${data.aws_availability_zones.az.names[2]}"
  }
}

moved {
  from = aws_subnet.pub_subnet1
  to = aws_subnet.pub_subnet3
}

moved {
  from  = aws_subnet.pub_subnet2
  to = aws_subnet.pub_subnet4
}

 

 

 

 

2. 코드 설명

  • 기존 subnet 생성 리소스의 이름은 pub_subnet1과 pub_subnet2로 생성한 상태에서 진행
  • aws_subnet 리소스 블럭의 이름을 각각 pub_subnet3, pub_subnet4로 변경
  • moved 블럭을 사용하여 pub_subnet1이름은 pub_subnet3으로, pub_subnet2이름은 pub_subnet4로 변경

 

 

3. 결과 확인

> terraform apply -auto-approve
data.aws_availability_zones.az: Reading...
aws_vpc.vpc: Refreshing state... [id=vpc-0226ffc7069cc5471]
data.aws_availability_zones.az: Read complete after 0s [id=ap-northeast-2]
aws_subnet.pub_subnet3: Refreshing state... [id=subnet-061b4b028737002da]
aws_subnet.pub_subnet4: Refreshing state... [id=subnet-0002f8ffdf6295d89]

Terraform will perform the following actions:

  # aws_subnet.pub_subnet1 has moved to aws_subnet.pub_subnet3
    resource "aws_subnet" "pub_subnet3" {
        id                                             = "subnet-061b4b028737002da"
        tags                                           = {
            "Name" = "test-pub-ap-northeast-2a"
        }
        # (16 unchanged attributes hidden)
    }

  # aws_subnet.pub_subnet2 has moved to aws_subnet.pub_subnet4
    resource "aws_subnet" "pub_subnet4" {
        id                                             = "subnet-0002f8ffdf6295d89"
        tags                                           = {
            "Name" = "test-pub-ap-northeast-2c"
        }
        # (16 unchanged attributes hidden)
    }

Plan: 0 to add, 0 to change, 0 to destroy.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

 

 

 

 

 

2. Terraform Provider alias

aws를 사용할 때 특정 리소스만 리전을 따로 설정하고 사용할 때 terraform의 provider에서 alias를 지정하여 사용합니다.

 

 

2-1) Provider alias 예시

1. AWS의 S3 버킷을 2개의 리전에서 동작하는 테라폼 코드 작성

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

provider "aws" {
  region = "ap-northeast-1"
  alias  = "tokyo_region"
}

variable "name" {
  default = "ljh"
}

resource "aws_s3_bucket" "seoul_s3_bucket" {
  provider = aws.seoul_region
  bucket   = "${var.name}-seoul-s3"
}

resource "aws_s3_bucket" "tokyo_s3_bucket" {
  provider = aws.tokyo_region
  bucket   = "${var.name}-tokyo-s3"
}

 

 

 

2. 코드설명

  • provider block을 2개 생성하되, alias를 각각 seoul_region와 tokyo_region으로 설정합니다.
  • s3를 생성하기 위한 aws_s3_bucket에 각각 provider를 원하는 리전의 alias로 지정합니다.

 

 

3. Azure Provider 사용 예시 

1. Azure 프로바이더를 사용하여 인스턴스 배포

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.0.0"
    }
  }
}

provider "azurerm" {
  features {}
#   client_id = ""
#   client_secret = ""
#   tenant_id = ""
#   subscription_id = ""
}

# Create resource group
resource "azurerm_resource_group" "sldt_rg" {
  name     = "${var.prefix}-rg"
  location = "${var.region}"
}

# Create virtual network
resource "azurerm_virtual_network" "vnet" {
  name                = "${var.prefix}-vnet"
  location            = azurerm_resource_group.sldt_rg.location
  address_space       = [var.address_space]
  resource_group_name = azurerm_resource_group.sldt_rg.name
}

# Create subnet
resource "azurerm_subnet" "public_subnet" {
  name                 = "${var.prefix}-pub-subnet"
  virtual_network_name = azurerm_virtual_network.vnet.name
  resource_group_name  = azurerm_resource_group.sldt_rg.name
  address_prefixes     = [var.pub_subnet_prefix]

  service_endpoints = ["Microsoft.KeyVault", "Microsoft.Storage"]
}

# Create Network Security Group and rule(bastion)
resource "azurerm_network_security_group" "bastion_nsg" {
  name                = "${var.prefix}-bastion-nsg"
  location            = azurerm_resource_group.sldt_rg.location
  resource_group_name = azurerm_resource_group.sldt_rg.name

  security_rule {
    name                       = "SSH"
    priority                   = 1001
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

# Create network interface(bastion)
resource "azurerm_network_interface" "bastion_nic" {
  name                = "${var.prefix}-bastion-nic"
  location            = azurerm_resource_group.sldt_rg.location
  resource_group_name = azurerm_resource_group.sldt_rg.name

  ip_configuration {
    name                          = "${var.prefix}-nic-configuration"
    subnet_id                     = azurerm_subnet.public_subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.bastion_pip.id
  }
}

# Connect the security group to the network interface(bastion)
resource "azurerm_network_interface_security_group_association" "bastion_nic_sg_asso" {
  network_interface_id      = azurerm_network_interface.bastion_nic.id
  network_security_group_id = azurerm_network_security_group.bastion_nsg.id
}

# Create public ip(bastion)
resource "azurerm_public_ip" "bastion_pip" {
  name                = "${var.prefix}-pip"
  location            = azurerm_resource_group.sldt_rg.location
  resource_group_name = azurerm_resource_group.sldt_rg.name
  allocation_method   = "Static"
  domain_name_label   = "${var.prefix}-bastion-pip-${random_id.bastion_pip.hex}"
}

# Create virtual machine(bastion)
resource "azurerm_linux_virtual_machine" "bastion" {
  name                = "${var.prefix}-bastion-vm"
  location            = azurerm_resource_group.sldt_rg.location
  resource_group_name = azurerm_resource_group.sldt_rg.name
  network_interface_ids = [azurerm_network_interface.bastion_nic.id]
  size                = var.vm_size[0]
  
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
    disk_size_gb         = "30"
  }

  source_image_reference {
    publisher = var.image_publisher
    offer     = var.image_offer
    sku       = var.image_sku
    version   = var.image_version
  }

  admin_username      = var.vm_username
  computer_name       = "bastion"

  admin_ssh_key {
    username   = var.vm_username
    public_key = file("sshkey/sldt_rsa.pub")
  }

  tags = {
    Name        = "${var.prefix}-bastion-vm"
    environment = var.environment
  }

  depends_on = [azurerm_network_interface_security_group_association.bastion_nic_sg_asso]
}
728x90
반응형