基于 Terraform 在 Azure 创建一个VM

本例中,将共创建8个资源到新的resource group里,算上rg的话,共9个资源,共自动化地实现了如下功能

  • 虚拟机 (VM) 密码采用随机生成的24位密码,并保存在 key vault中
  • 虚拟机 (VM) 同时开启了账号密码和密钥登陆两种方式(可以只限密钥登陆,更安全!)
  • 安全组 (Network security group) 同时开了ssh(22),http(80),https(443)
  • 虚拟机 (VM) 预装常用命令:helm,az,kubectl,k9s
  • 虚拟机 (VM) 新增数据盘(可选:放开注释)

话不多说,直接上源码

文件名: main.tf

terraform {
  required_version = ">= 1.3"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.39.0"
    }
  }
}

provider "azurerm" {
  features {
    key_vault {
      purge_soft_delete_on_destroy    = true
      recover_soft_deleted_key_vaults = true
    }
  }
}

locals {
  virtual_machine_name = "${var.prefix}-vm"
  admin_username       = "qaadmin"
  # admin_password      = "P@ssw0rd#999" # unused, instead by random
}

resource "random_password" "vm-password" {
  length           = 24
  special          = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
}

resource "azurerm_resource_group" "rg" {
  name     = "rg-${var.prefix}"
  location = var.location
}

resource "azurerm_virtual_network" "vnet" {
  name                = "${var.prefix}-vnet"
  address_space       = ["10.111.0.0/16"]
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_subnet" "subnet" {
  name                 = "${var.prefix}-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.111.2.0/24"]
}

resource "azurerm_public_ip" "pip" {
  name                = "${var.prefix}-pip"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  allocation_method   = "Static"
}

resource "azurerm_network_interface" "nic-public" {
  name                = "${var.prefix}-nic-public"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location

  ip_configuration {
    name                          = "${var.prefix}-public"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.pip.id
  }
}

resource "azurerm_network_interface" "nic-private" {
  name                      = "${var.prefix}-nic-private"
  resource_group_name       = azurerm_resource_group.rg.name
  location                  = azurerm_resource_group.rg.location

  ip_configuration {
    name                          = "${var.prefix}-private"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_network_security_group" "webserver" {
  name                = "${var.prefix}-nsg"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  security_rule {
    name                       = "Allow-someapp"
    description                = "Allow someapp"
    priority                   = 102
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    source_address_prefix      = "*"
    destination_port_range     = "65299"
    destination_address_prefix = "*"
  }

  security_rule {
    name                       = "Allow-HTTP"
    description                = "Allow HTTP Traffic"
    priority                   = 101
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    source_address_prefix      = "*"
    destination_port_ranges     = [80,443]
    destination_address_prefix = "*"
  }

  security_rule {
    name                       = "Allow-SSH"
    description                = "Allow SSH"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    source_address_prefixes      = ["218.2.119.162","221.226.253.166","34.92.87.28"]
    destination_port_range     = "22"
    destination_address_prefix = "*"
  }
}

resource "azurerm_network_interface_security_group_association" "private-nic-nsg-association" {
  network_interface_id      = azurerm_network_interface.nic-private.id
  network_security_group_id = azurerm_network_security_group.webserver.id
}

resource "azurerm_linux_virtual_machine" "qa-vm" {
  name                            = "${var.prefix}-linux-vm"
  resource_group_name             = azurerm_resource_group.rg.name
  location                        = azurerm_resource_group.rg.location
  size                            = "Standard_D4ds_v4"
  admin_username                  = "${local.admin_username}"
  # admin_password                  = "${local.admin_password}"
  admin_password                  = random_password.vm-password.result
  disable_password_authentication = false
  network_interface_ids = [
    azurerm_network_interface.nic-public.id,
    azurerm_network_interface.nic-private.id,
  ]
  admin_ssh_key {
    username   = "${local.admin_username}"
    public_key = file("~/.ssh/id_rsa.pub")
  }
  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }

  os_disk {
    storage_account_type = "Standard_LRS"
    caching              = "ReadWrite"
  }

  provisioner "file" {
    source      = "init.sh"
    destination = "/tmp/init.sh"

    connection {
      type     = "ssh"
      host     = self.public_ip_address
      user     = self.admin_username
      password = self.admin_password
    }
  }

  provisioner "remote-exec" {
    inline = [
      "chmod +x /tmp/init.sh",
      "ls -la /tmp",
      "/tmp/init.sh",
    ]

    connection {
      type     = "ssh"
      host     = self.public_ip_address
      user     = self.admin_username
      password = self.admin_password
    }
  }
}

# Add additional data disk, testing passed
# If needed
# resource "azurerm_managed_disk" "data" {
#   name                 = "${var.prefix}-vm-data-disk"
#   location             = azurerm_resource_group.rg.location
#   create_option        = "Empty"
#   disk_size_gb         = 50
#   resource_group_name  = azurerm_resource_group.rg.name
#   storage_account_type = "Standard_LRS"
# }

# resource "azurerm_virtual_machine_data_disk_attachment" "data" {
#   virtual_machine_id = azurerm_linux_virtual_machine.qa-vm.id
#   managed_disk_id    = azurerm_managed_disk.data.id
#   lun                = 0
#   caching            = "ReadWrite"
# }

output "public_ip_address" {
  value       = azurerm_linux_virtual_machine.qa-vm.public_ip_address
  sensitive   = false
  description = "Public ip for ssh login"
  depends_on  = [ azurerm_linux_virtual_machine.qa-vm ]
}

output "vm_password" {
  value       = random_password.vm-password.result
  sensitive   = true
  description = "VM password for ssh login"
  depends_on  = [ azurerm_linux_virtual_machine.qa-vm ]
}

data "azurerm_client_config" "current" {}

resource "azurerm_key_vault" "vm-kv" {
  name                        = "${var.prefix}-kv"
  location                    = azurerm_resource_group.rg.location
  resource_group_name         = azurerm_resource_group.rg.name
  enabled_for_disk_encryption = true
  tenant_id                   = data.azurerm_client_config.current.tenant_id
  soft_delete_retention_days  = 7
  purge_protection_enabled    = false

  sku_name = "standard"
}

resource "azurerm_key_vault_access_policy" "current-service-principle" {
  key_vault_id = azurerm_key_vault.vm-kv.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = data.azurerm_client_config.current.object_id

  key_permissions = [
      "Get", "List"
    ]

  secret_permissions = [
      "Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set"
    ]
}


resource "azurerm_key_vault_access_policy" "devops-group" {
  key_vault_id = azurerm_key_vault.vm-kv.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = "pkgd2ebsd-7563-1e23-b567-7fdbb3916d29"

  key_permissions = [
      "Get", "List"
    ]

  secret_permissions = [
      "Backup", "Delete", "Get", "List", "Purge", "Recover", "Restore", "Set"
    ]
}

resource "azurerm_key_vault_secret" "vm-username" {
  name         = "VMUSERNAME"
  value        = "${local.admin_username}"
  key_vault_id = azurerm_key_vault.vm-kv.id
  depends_on = [
    azurerm_key_vault.vm-kv,
    azurerm_key_vault_access_policy.devops-group, 
    azurerm_key_vault_access_policy.current-service-principle
  ]
}

resource "azurerm_key_vault_secret" "vm-password" {
  name         = "VMPASSWORD"
  value        = random_password.vm-password.result
  key_vault_id = azurerm_key_vault.vm-kv.id
  depends_on = [
    azurerm_key_vault.vm-kv, azurerm_key_vault_access_policy.devops-group, azurerm_key_vault_access_policy.current-service-principle
  ]
}

文件名: init.sh

#!/usr/bin/env bash

# Install az
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
echo -e '---- Install az over.'

# Install helm 
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | sudo bash
echo -e '---- Install helm over.'

# Install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
source <(kubectl completion bash) 
echo "source <(kubectl completion bash)" >> ~/.bashrc
echo -e '---- Install kubectl over.'

# Install k9s
wget https://github.com/derailed/k9s/releases/download/v0.26.3/k9s_Linux_x86_64.tar.gz
[ -d k9s ] || mkdir k9s
tar -zxvf k9s_Linux_x86_64.tar.gz -C k9s
sudo mv k9s /usr/bin/
rm -rf k9s*
echo -e '---- Install k9s over.'

文件名:variables.tf

# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0
variable "prefix" {
  description = "The prefix which should be used for all resources in this example"
}

variable "location" {
  description = "The Azure Region in which all resources in this example should be created."
}

部署命令:

# 创建
terraform plan -out createvm.tfplan -var='prefix=autotesting' -var="location=westeurope"
terraform apply createvm.tfplan

# 销毁
terraform plan -destroy -out createvm.destroy.tfplan -var='prefix=autotesting' -var="location=westeurope"
terraform apply createvm.destroy.tfplan
客官慢走,有空常来啊😄
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇