本例中,将共创建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