Terraform으로 Azure 환경 구축

11128 단어 AzureTerraform

소개



Infrastructure as Code(IaC)에 도전해 보았습니다.
Terraform을 사용하여 Azure 리소스를 만듭니다.

사전 준비


  • Azure CLI 설치
  • Terraform 설치
  • VSCode에 확장 기능 설치 (필자가 VSCode로 작성하고 싶기 때문입니다)
  • Azure Terraform

  • Terraform


  • 디렉토리 구성



    env 아래에 각 환경의 디렉토리를 준비하여 환경 의존 자원에 대응합니다.
    공통으로 사용할 수 있는 것에 대해서는 디렉토리의 최상위에 배치합니다.
    terraform
    │  availability.tf
    │  recovery_services_vault.tf
    │  resource_group.tf
    │  storage_account.tf
    │  variables.tf
    │  virtual_network.tf
    │
    ├─env
    │  └─sample
    │          main.tf
    │          sample-lb.tf
    │          sample-nsg.tf
    │          sample-vm.tf
    │          variables.tf
    │
    └─modules
        ├─lb
        │      lb.tf
        │      outputs.tf
        │      variables.tf
        │
        ├─nsg
        │      nsg.tf
        │      variables.tf
        │
        └─vm
                outputs.tf
                variables.tf
                vm.tf
    

    정의



    기본 정의



    디렉토리의 최상위로 정의하고 있는 자원의 작성은 env\sample\variables.tf 로 선언한 변수와 값을 env\sample\main.tf 로 최상위의 variables.tf 내의 변수에 건네주는 것으로 실시합니다.
    환경이 복수 있는 경우는 env\sample2 와 같은 디렉토리를 작성해 대응합니다.

    env\sample\variables.tf
    locals {
      ##### Azureログイン情報 #####
      login = {
        subscription_id = "xxxxxx"
        tenant_id       = "xxxxxx"
      }
    
      location = {
        main = "japaneast"
        sub  = "japanwest"
      }
    
      ##### リソースグループ #####
      resource_group = {
        rg1 = {
          name     = "sample-rg"
          location = local.location.main
        }
      }
    
    ~~~省略~~~
    }
    

    변수를 전달하는 방법은 다음과 같습니다.

    env\sample\main.tf
    provider "azurerm" {
      version = "~>2.0"
      features {}
      subscription_id = local.login.subscription_id
      tenant_id       = local.login.tenant_id
    }
    
    module "main" {
      source = "../../"
    
      resource_group            = local.resource_group
      virtual_network           = local.virtual_network
      subnet                    = local.subnet
      public_ip                 = local.public_ip
      availability_set          = local.availability_set
      storage_account           = local.storage_account
      recovery_services_vault   = local.recovery_services_vault
      backup_policy_vm_daily    = local.backup_policy_vm_daily
      backup_policy_vm_weekly   = local.backup_policy_vm_weekly
      proximity_placement_group = local.proximity_placement_group
      backup_storage_account    = local.backup_storage_account
    }
    

    최상위 variables.tf 는 값만 받습니다.

    variables.tf
    variable "resource_group" {}
    
    variable "virtual_network" {}
    
    variable "subnet" {}
    
    variable "public_ip" {}
    
    variable "availability_set" {}
    
    variable "storage_account" {}
    
    variable "recovery_services_vault" {}
    
    variable "backup_policy_vm_daily" {}
    
    variable "backup_policy_vm_weekly" {}
    
    variable "proximity_placement_group" {}
    
    variable "backup_storage_account" {}
    

    모듈 정의



    설정 항목이 많은 VM, NSG, LB는 가독성을 높이기 위해 모듈화하여 1 리소스 = 1 파일로 정의하기로 했습니다.
    VM의 경우는, 이하 env\sample\sample-vm.tf 와 같이 정의한 값을 modules\vm\variables.tf 에 건네줍니다.
    LB와 NSG도 같은 구성입니다.

    env\sample\sample-vm.tf
    locals {
      sample-vm_var = {
        resource_group_key            = "rg1"
        subnet_key                    = "sub1"
        ehable_boot_diagnostics       = false
        ehable_backup                 = false
        storage_account_key           = "sa1"
        availability_set_key          = ""
        proximity_placement_group_key = ""
        public_ip_key                 = ""
        recovery_services_vault_key   = ""
        backup_policy_vm_key          = ""
      }
    }
    
    locals {
      ##### 仮想マシン #####
      sample-vm_vm = {
    
        name                         = "sample-vm"
        resource_group_name          = module.main.resource_group[local.sample-vm_var.resource_group_key].name
        location                     = module.main.resource_group[local.sample-vm_var.resource_group_key].location
        vm_size                      = "Standard_D2s_v3"
        availability_set_id          = length(local.sample-vm_var.availability_set_key) > 0 ? module.main.availability_set[local.sample-vm_var.availability_set_key].id : ""
        proximity_placement_group_id = length(local.sample-vm_var.proximity_placement_group_key) > 0 ? module.main.proximity_placement_group[local.sample-vm_var.proximity_placement_group_key].id : ""
    
        ##### ディスク関連 #####
        delete_os_disk_on_termination    = false
        delete_data_disks_on_termination = false
        ultra_ssd_enabled                = false
    
        ##### 仮想マシンイメージ #####
        image = {
          is_windows_image = true
          os_id            = ""
          publisher        = "MicrosoftWindowsServer"
          offer            = "WindowsServer"
          sku              = "2019-Datacenter"
          version          = "latest"
        }
    
        ##### OSディスク #####
        # managed_disk_type : Standard_LRS, StandardSSD_LRS, Premium_LRS
        os_disk = {
          managed_disk_type         = "Standard_LRS"
          write_accelerator_enabled = false
        }
    
        ##### 仮想ネットワーク #####
        network = {
          subnet_id                     = module.main.subnet[local.sample-vm_var.subnet_key].id
          private_ip_address            = "10.0.0.5"
          public_ip_address_id          = length(local.sample-vm_var.public_ip_key) > 0 ? module.main.public_ip[local.sample-vm_var.public_ip_key].id : ""
          enable_accelerated_networking = false
        }
    
        ##### ローカル管理者 #####
        os_profile = {
          admin_username = "sampleadmin"
          admin_password = "Hogehoge12#$"
        }
    
        ##### ブート診断 #####
        boot_diagnostics = {
          ehable_boot_diagnostics = local.sample-vm_var.ehable_boot_diagnostics
          primary_blob_endpoint   = local.sample-vm_var.ehable_boot_diagnostics ? module.main.storage_account[local.sample-vm_var.storage_account_key].primary_blob_endpoint : ""
        }
    
        ##### Windows個別設定 #####
        windows = {
          timezone = "Tokyo Standard Time"
        }
    
        ##### Linux個別設定 #####
        linux = {
          enable_ssh_key = false
          ssh_key        = ""
        }
    
        ##### Backup #####
        backup = {
          recovery_vault_name = local.sample-vm_var.ehable_backup ? module.main.recovery_services_vault[local.sample-vm_var.recovery_services_vault_key].name : ""
          backup_policy_id    = local.sample-vm_var.ehable_backup ? module.main.backup_policy_vm_daily[local.sample-vm_var.backup_policy_vm_key].id : ""
        }
    
        ##### Load Balancer #####
        load_balancer = {
          ehabled_load_balancer   = false
          backend_address_pool_id = module.sample-lb.lb_backend_address_pool.id
        }
    
        tags = {
          name = "サンプル仮想マシン"
        }
      }
    
      ##### データディスク #####
      sample-vm_data_disk = {
        "disk1" = {
          disk_size_gb              = "16"
          managed_disk_type         = "Standard_LRS"
          caching                   = "ReadOnly"
          lun                       = 0
          write_accelerator_enabled = false
        }
      }
    
    }
    
    ##### 仮想マシンの作成 #####
    module "sample-vm" {
      source = "../../modules/vm/"
    
      vm        = local.sample-vm_vm
      data_disk = local.sample-vm_data_disk
    }
    
    

    수신측

    modules\vm\variables.tf
    variable "vm" {}
    
    variable "data_disk" {}
    

    리소스 생성 유무 제어



    자원 유무에 의한 수정 개소를 줄이기 위해 env\sample 내의 변수를 코멘트 아웃하는 것도 대응할 수 있도록 했습니다.

    예를 들어 공용 IP 주소를 만들 필요가 없는 경우 다음을 수행합니다.

    evn\sample\variables.tf
    public_ip = {
      # pip1 = {
      #   name               = "vm1-pip"
      #   resource_group_key = "rg1"
      #   sku                = "Basic"
      #   allocation_method  = "Static"
      # }
    }
    

    공용 IP 주소의 리소스 생성 부분은 for_each를 사용하여 제어합니다.
    변수 public_ip 의 map 가 존재하지 않는 경우는 through 됩니다.

    virtual_network.tf
    resource "azurerm_public_ip" "main" {
      for_each            = var.public_ip
      name                = each.value.name
      resource_group_name = azurerm_resource_group.main[each.value.resource_group_key].name
      sku                 = each.value.sku
      location            = azurerm_resource_group.main[each.value.resource_group_key].location
      allocation_method   = each.value.allocation_method
    }
    

    실행



    정의가 준비되었으므로 실제로 리소스를 만들어 보겠습니다.
    이번에는 서비스 주체를 사용하지 않으므로 사전에 Azure CLI로 Azure에 로그인합니다.
    az login
    
    env\sample 로 이동한 후 terraform init 로 초기화합니다.
    terraform init
    
    Initializing modules...
    - main in ..\..
    - sample-lb in ..\..\modules\lb
    - sample-nsg in ..\..\modules\nsg
    - sample-vm in ..\..\modules\vm
    
    Initializing the backend...
    
    Initializing provider plugins...
    - Checking for available provider plugins...
    - Downloading plugin for provider "azurerm" (hashicorp/azurerm) 2.14.0...
    
    Terraform has been successfully initialized!
    
    You may now begin working with Terraform. Try running "terraform plan" to see
    any changes that are required for your infrastructure. All Terraform commands
    should now work.
    
    If you ever set or change modules or backend configuration for Terraform,
    rerun this command to reinitialize your working directory. If you forget, other
    commands will detect it and remind you to do so if necessary.
    

    실행 계획 검토를 수행하여 오류가 없는지 확인합니다.
    terraform plan
    
    ~~~省略~~~
    
    Plan: 15 to add, 0 to change, 0 to destroy.
    
    terraform apply 에서 리소스를 만듭니다.
    terraform apply
    
    ~~~省略~~~
    
    Apply complete! Resources: 15 added, 0 changed, 0 destroyed.
    

    포털에서도 자원이 작성되었음을 확인할 수 있었습니다.


    마지막으로



    일단 정의하면 쉽게 자원을 작성, 변경, 삭제를 할 수 있는 것이 훌륭하네요.
    이번 범용적으로 사용할 수 있도록 정의하려고 능숙하지 않고 오이타 고전했습니다.
    다만, 그 덕분에 조금은 Terraform의 구문을 이해할 수 있었던 것이 아닐까 생각하고 있습니다.

    이번에 쓴 샘플 코드는 GitHub에서 공개하고 있으므로 좋으면 이용해보세요.
    이르지 않는 점도 많이 있다고 생각하므로 사용하기 쉽도록 수정하여 사용하실 수 있다고 생각합니다.
    htps : // 기주 b. 코 m / y 타무 2 / 테라 후 rm - 아즈레 - mp ぁ

    좋은 웹페이지 즐겨찾기