Terraform을 사용하여 Linux 가상 머신 프로비전

완료됨

Terraform은 구성 요소의 원하는 상태를 설명하는 구성 파일을 사용하여 대상 인프라를 구현하고 제어합니다. 파일의 기본 형식과 HCL(Hashicorp Configuration Language)로 표현되는 일반 구문은 클라우드 선택에 관계없이 동일합니다. 그러나 개별 구성 요소 설명은 해당 Terraform 공급자에 의해 결정된 대로 클라우드에 따라 달라집니다.

Azure 인프라 관리를 지원하는 여러 Terraform 공급자가 있지만 AzureRM은 특히 관련성이 있습니다. AzureRM 공급자는 가상 머신, 스토리지 계정, 네트워킹 인터페이스와 같은 일반적인 Azure IaaS 리소스의 프로비전 및 구성을 용이하게 합니다. 또한 배포에 통합할 수 있는 비클라우드 관련 추가 공급자도 있습니다. 여기에는 의사 임의 문자열을 생성하여 리소스 명명 충돌을 방지하는 데 도움이 되는 임의 공급자와 Linux 인증 보안을 위한 비대칭 키 관리를 간소화하는 tls 공급자가 포함됩니다.

Terraform은 Hashicorp 웹 사이트에서 다운로드할 수 있는 단일 이진 파일로 제공됩니다. 이 이진 파일은 Terraform CLI(명령줄 인터페이스)를 구현합니다. 이 인터페이스는 셸 세션에서 호출하여 Terraform을 초기화하고 구성 파일을 처리할 수 있습니다. Azure CLI를 지원하는 모든 셸에서 Terraform CLI를 사용할 수 있습니다.

참고 항목

Azure Cloud Shell을 사용하는 경우 Bash를 사용하여 Azure Cloud Shell에서 Terraform 구성에 제공된 지침에 따라 현재 버전의 Terraform을 실행해야 합니다.

Terraform을 사용하여 Linux VM 배포

Terraform을 사용하면 공급자별 클라우드 인프라에 리소스를 정의하고 미리 보고 배포할 수 있습니다. 프로비전 프로세스는 HCL 구문을 사용하는 구성 파일을 만드는 것으로 시작하며, 이를 통해 대상 클라우드 환경(예: Azure)과 클라우드 인프라를 구성하는 리소스를 지정할 수 있습니다. 모든 관련 구성 파일이 배치된 후(일반적으로 동일한 파일 시스템 위치 내) 실제 배포 전에 결과 인프라 변경 내용을 미리 볼 수 있는 실행 계획을 생성할 수 있습니다. 이를 위해서는 Terraform을 초기화하여 클라우드 리소스를 구현하는 데 필요한 공급자 모듈을 다운로드해야 합니다. 변경 내용의 유효성을 검사한 후 실행 계획을 적용하여 인프라를 배포할 수 있습니다.

참고 항목

실행 계획을 생성하는 것은 선택 사항이지만 대상 환경에 영향을 주지 않고 계획된 배포의 영향을 식별할 수 있으므로 실행 계획을 생성하는 것이 좋습니다. Azure 리소스를 대화형으로 배포하는 경우 Terraform은 자격 증명을 다시 사용하여 대상 Azure 구독에 액세스하여 Azure CLI 인증을 투명하게 지원합니다.

Terraform을 사용하여 Linux를 실행하는 Azure VM을 프로비전하는 프로세스에는 일반적으로 다음과 같은 개략적인 단계 시퀀스가 포함됩니다.

  • 적합한 VM 이미지를 식별합니다.
  • 적합한 VM 크기를 식별합니다.
  • 종속성이 있는 Azure VM 리소스를 정의하는 구성 파일을 만듭니다.
  • Terraform을 초기화합니다.
  • Terraform 실행 계획을 생성합니다.
  • Terraform 배포를 시작합니다.

적합한 VM 이미지 및 크기를 식별하려면 이 모듈의 4단원에 설명된 단계를 수행합니다. 이 단원에서는 Terraform 관련 작업에 중점을 두고 있습니다.

구성 파일 만들기

참고 항목

Terraform 파일에 대해 선택하는 파일 이름은 임의적이지만 파일 콘텐츠나 목적을 반영하는 이름을 선택하는 것이 좋습니다. 파일 확장자로 ".tf"를 사용해야 합니다.

Terraform을 사용하여 Linux VM을 배포하려면 구성 파일을 호스팅할 디렉터리를 만드는 것부터 시작합니다. 다음으로 Terraform 버전을 적용하고 배포에 포함된 리소스를 정의할 때 사용할 공급자를 지정하는 providers.tf라는 파일을 만듭니다. 이 파일에는 다음 코드 조각에 콘텐츠가 표시되어야 합니다.

terraform {
  required_version = ">=0.12"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>2.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "~>3.0"
    }
    tls = {
      source = "hashicorp/tls"
      version = "~>4.0"
    }
  }
}

provider "azurerm" {
  features {}
}

동일한 디렉터리에서 Azure VM 구성 및 해당 종속성을 정의하는 다음 코드를 사용하여 main.tf라는 파일을 만듭니다.

resource "random_pet" "rg_name" {
  prefix = var.resource_group_name_prefix
}

resource "azurerm_resource_group" "rg" {
  location = var.resource_group_location
  name     = random_pet.rg_name.id
}

# Create virtual network
resource "azurerm_virtual_network" "terraform_network" {
  name                = "lnx-tf-vnet"
  address_space       = ["10.1.0.0/16"]
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

# Create subnet
resource "azurerm_subnet" "terraform_subnet" {
  name                 = "subnet0"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.terraform_network.name
  address_prefixes     = ["10.1.0.0/24"]
}

# Create public IPs
resource "azurerm_public_ip" "terraform_public_ip" {
  name                = "lnx-tf-pip"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  allocation_method   = "Dynamic"
}

# Create Network Security Group and rule
resource "azurerm_network_security_group" "terraform_nsg" {
  name                = "lnx-tf-nsg"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

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

# Create network interface
resource "azurerm_network_interface" "terraform_nic" {
  name                = "lnx-tf-nic"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "nic_configuration"
    subnet_id                     = azurerm_subnet.terraform_subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.terraform_public_ip.id
  }
}

# Connect the security group to the network interface
resource "azurerm_network_interface_security_group_association" "lnx-tf-nic-nsg" {
  network_interface_id      = azurerm_network_interface.terraform_nic.id
  network_security_group_id = azurerm_network_security_group.terraform_nsg.id
}

# Generate random text for a unique storage account name
resource "random_id" "random_id" {
  keepers = {
    # Generate a new ID only when a new resource group is defined
    resource_group = azurerm_resource_group.rg.name
  }

  byte_length = 8
}

# Create storage account for boot diagnostics
resource "azurerm_storage_account" "storage_account" {
  name                     = "diag${random_id.random_id.hex}"
  location                 = azurerm_resource_group.rg.location
  resource_group_name      = azurerm_resource_group.rg.name
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

# Create (and display) an SSH key
resource "tls_private_key" "lnx-tf-ssh" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

# Create virtual machine
resource "azurerm_linux_virtual_machine" "lnx-tf-vm" {
  name                  = "lnx-tf-vm"
  location              = azurerm_resource_group.rg.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.terraform_nic.id]
  size                  = "Standard_F4s"

  os_disk {
    name                 = "lnx-tf-vm-osdisk"
    caching              = "ReadWrite"
    storage_account_type = "Premium_LRS"
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "0001-com-ubuntu-server-jammy"
    sku       = "22_04-lts-gen2"
    version   = "latest"
  }

  computer_name                   = "lnx-tf-vm"
  admin_username                  = "azureuser"
  disable_password_authentication = true

  admin_ssh_key {
    username   = "azureuser"
    public_key = tls_private_key.lnx-tf-ssh.public_key_openssh
  }

  boot_diagnostics {
    storage_account_uri = azurerm_storage_account.storage_account.primary_blob_endpoint
  }
}

동일한 디렉터리에서 main.tf 파일에 나타나는 변수에 값을 할당하는 다음 코드를 사용하여 variables.tf라는 다른 파일을 만듭니다.

variable "resource_group_location" {
  default     = "eastus"
  description = "Location of the resource group"
}

variable "resource_group_name_prefix" {
  default     = "rg"
  description = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription"
}

마지막으로, 다음 코드를 사용하여 outputs.tf라는 파일을 만듭니다. 이 코드는 성공적인 배포 후 표시되는 출력을 결정합니다.

output "resource_group_name" {
  value = azurerm_resource_group.rg.name
}

output "public_ip_address" {
  value = azurerm_linux_virtual_machine.lnx-tf-vm.public_ip_address
}

output "tls_private_key" {
  value     = tls_private_key.lnx-tf-ssh.private_key_pem
  sensitive = true
}

Terraform 초기화

Terraform 배포를 초기화하려면 셸 프롬프트에서 다음 명령을 실행합니다.

terraform init

이 명령은 Azure 리소스를 프로비전하고 관리하는 데 필요한 Azure 모듈을 다운로드합니다.

실행 계획 생성

초기화 후에는 Terraform 계획을 실행하여 실행 계획을 만듭니다. 명령은 실행 계획을 만들지만 실행하지는 않습니다. 대신 구성 파일에 정의된 리소스를 만드는 데 필요한 작업을 결정합니다. 선택적 -out 매개 변수를 사용하면 실제 배포 중에 참조할 수 있는 계획의 출력 파일을 지정할 수 있습니다. 이 파일을 사용하면 검토하는 계획이 정확한 배포 결과와 일치하는지 확인할 수 있습니다. 다음 명령을 사용하여 실행 계획을 생성합니다.

terraform plan -out <terraform_plan>.tfplan

배포 시작

Azure 환경에 실행 계획을 적용할 준비가 되면 이전 단계에서 생성한 파일 이름을 포함하여 terraform apply를 실행합니다. 예상 결과를 검토할 수 있는 또 다른 기회가 있습니다. Terraform은 -auto-approve 스위치를 추가하여 프롬프트를 제거할 수 있지만 계속 진행할지 묻는 프롬프트를 표시합니다. 다음 명령을 사용하여 배포를 시작합니다.

terraform apply <terraform_plan>.tfplan

Azure VM은 일반적으로 몇 분 이내에 곧 실행되기 시작합니다. terraform apply 명령 출력에는 출력 목록이 포함되지만 Terraform은 tls_private_key 값을 <sensitive> 레이블로 바꿉니다.

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

출력:

public_ip_address = "74.235.10.136"
resource_group_name = "rg-flexible-shark"
tls_private_key = <sensitive>

SSH 연결을 인증하기 위해 자동 생성된 프라이빗 키를 사용하려면 파일에 저장한 다음 파일의 사용 권한을 설정하여 다른 사용자가 액세스할 수 없도록 합니다. 이렇게 하려면 다음 명령을 실행합니다.

terraform output -raw tls_private_key > id_rsa
chmod 600 id_rsa

이 시점에서 다음 명령을 실행하여 Azure VM에 연결할 수 있습니다(<public_ip_address> 자리 표시자를 terraform apply-generated 출력에서 식별한 IP 주소로 바꾼 후).

ssh -i id_rsa azureuser@<public_ip_address>