Code as IaaS for Azure : Terraform 做多一點事情
上一篇大概介紹了怎麽用Terraform在Azure上創建一個虛擬機,接下來,我們會用Terraform來做一些更復雜的工作。
在開始工作前,我們還是要先解釋下會用到的幾個命令。
因為我用的是Win10系統,所以下載的Terraform下載後就是一個執行文件,可以放在任何一個目錄下執行。在最開始的時候,記得先要執行以下命令:
terraform init
這條命令會初始化terraform的執行目錄。如果查看隱藏目錄的話,會看見這條命令創建一了一個隱藏目錄”.terraform”,並在這個目錄裏下載了兩個插件。
Terraform可以使用不同的工作區域來區分不同的執行環境。命令是:
terraform workspace
可以在後面再加上new,delete,show,list,select參數來創建刪除和管理工作區域。
還有兩個很重要的命令是terraform plan和terraform apply
terraform plan會解析配置腳本,並比較現有資源和配置腳本之間的差異。如果用了 -out 參數,可以輸出一個執行腳本。如果配置腳本的語法或參數錯誤,plan命令會返回相應的錯誤信息。換句話說,plan沒有報錯,說明至少腳本的語法是正確的。
terraform apply,當plan沒有報錯後,就可以執行apply命令,它會真正在Azure上創建腳本所指定的資源。這個階段也可能會報錯,例如,資源已經存在,或者資源不足,護著指定的資源不存在。
要註意的是,在沒有特殊指定時,plan和apply會執行當前目錄下的所有配置腳本。所以為什麽會有workspace的設置,這就可以理解了。不過按我的理解,多建幾個目錄會是更簡單和可靠的方法。
如果要刪除資源,也是有命令可以用的。。。。。。
terraform plan -destroy 和 terraform destroy
大概了解了terraform的主要命令後,要開始做一些更復雜的事情了。這次我打算建的一個簡單的應用環境,負載均衡後帶兩臺虛擬機,對外開放80端口,包括健康檢查,獨立的網絡。依然放在上一篇文檔所建立的資源組lyq-testterraform-rg裏。
配置腳本如下:經過上一篇文檔,我就不介紹每一段是幹什麽的了。腳本還是很容易讀懂的。
provider "azurerm" {
subscription_id = "xxxxxxxxxxxxxxxxx"
client_id = "xxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxx"
tenant_id = "xxxxxxxxxxxxxxx"
environment = "china"
}
resource "azurerm_resource_group" "rg" {
name = "${var.resource_group}"
location = "${var.location}"
}
resource "azurerm_storage_account" "stor" {
name = "${var.dns_name}stor"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
account_type = "Standard_GRS"
}
resource "azurerm_availability_set" "avset" {
name = "${var.dns_name}avset"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
platform_fault_domain_count = 2
platform_update_domain_count = 2
managed = true
}
resource "azurerm_public_ip" "lbpip" {
name = "${var.rg_prefix}-ip"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
public_ip_address_allocation = "dynamic"
domain_name_label = "${var.lb_ip_dns_name}"
}
resource "azurerm_virtual_network" "vnet" {
name = "${var.virtual_network_name}"
location = "${var.location}"
address_space = ["${var.address_space}"]
resource_group_name = "${azurerm_resource_group.rg.name}"
}
resource "azurerm_subnet" "subnet" {
name = "${var.rg_prefix}subnet"
virtual_network_name = "${azurerm_virtual_network.vnet.name}"
resource_group_name = "${azurerm_resource_group.rg.name}"
address_prefix = "${var.subnet_prefix}"
}
resource "azurerm_lb" "lb" {
resource_group_name = "${azurerm_resource_group.rg.name}"
name = "${var.rg_prefix}lb"
location = "${var.location}"
frontend_ip_configuration {
name = "LoadBalancerFrontEnd"
public_ip_address_id = "${azurerm_public_ip.lbpip.id}"
}
}
resource "azurerm_lb_backend_address_pool" "backend_pool" {
resource_group_name = "${azurerm_resource_group.rg.name}"
loadbalancer_id = "${azurerm_lb.lb.id}"
name = "BackendPool1"
}
resource "azurerm_lb_nat_rule" "tcp" {
resource_group_name = "${azurerm_resource_group.rg.name}"
loadbalancer_id = "${azurerm_lb.lb.id}"
name = "RDP-VM-${count.index}"
protocol = "tcp"
frontend_port = "5000${count.index + 1}"
backend_port = 3389
frontend_ip_configuration_name = "LoadBalancerFrontEnd"
count = 2
}
resource "azurerm_lb_rule" "lb_rule" {
resource_group_name = "${azurerm_resource_group.rg.name}"
loadbalancer_id = "${azurerm_lb.lb.id}"
name = "LBRule"
protocol = "tcp"
frontend_port = 80
backend_port = 80
frontend_ip_configuration_name = "LoadBalancerFrontEnd"
enable_floating_ip = false
backend_address_pool_id = "${azurerm_lb_backend_address_pool.backend_pool.id}"
idle_timeout_in_minutes = 5
probe_id = "${azurerm_lb_probe.lb_probe.id}"
depends_on = ["azurerm_lb_probe.lb_probe"]
}
resource "azurerm_lb_probe" "lb_probe" {
resource_group_name = "${azurerm_resource_group.rg.name}"
loadbalancer_id = "${azurerm_lb.lb.id}"
name = "tcpProbe"
protocol = "tcp"
port = 80
interval_in_seconds = 5
number_of_probes = 2
}
resource "azurerm_network_interface" "nic" {
name = "nic${count.index}"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
count = 2
ip_configuration {
name = "ipconfig${count.index}"
subnet_id = "${azurerm_subnet.subnet.id}"
private_ip_address_allocation = "Dynamic"
load_balancer_backend_address_pools_ids = ["${azurerm_lb_backend_address_pool.backend_pool.id}"]
load_balancer_inbound_nat_rules_ids = ["${element(azurerm_lb_nat_rule.tcp.*.id, count.index)}"]
}
}
resource "azurerm_virtual_machine" "vm" {
name = "vm${count.index}"
location = "${var.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
availability_set_id = "${azurerm_availability_set.avset.id}"
vm_size = "${var.vm_size}"
network_interface_ids = ["${element(azurerm_network_interface.nic.*.id, count.index)}"]
count = 2
storage_image_reference {
publisher = "${var.image_publisher}"
offer = "${var.image_offer}"
sku = "${var.image_sku}"
version = "${var.image_version}"
}
storage_os_disk {
name = "osdisk${count.index}"
create_option = "FromImage"
}
os_profile {
computer_name = "${var.hostname}"
admin_username = "${var.admin_username}"
admin_password = "${var.admin_password}"
}
}
看完上面腳本,大家是不是覺得上面每個參數都是$的引用,到底引用了什麽?Terraform的這個特性是非常好的,可以很簡單定義不同的參數引用。上面這個腳本對應的所有參數引用在下面這個腳本裏定義:
variable "resource_group" {
description = "The name of the resource group in which to create the virtual network."
default = "lyq-testterraform-rg"
}
variable "rg_prefix" {
description = "The shortened abbreviation to represent your resource group that will go on the front of some resources."
default = "rg"
}
variable "hostname" {
description = "VM name referenced also in storage-related names."
default = "lyqterravm"
}
variable "dns_name" {
description = " Label for the Domain Name. Will be used to make up the FQDN. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system."
default = "lyqterraform"
}
variable "lb_ip_dns_name" {
description = "DNS for Load Balancer IP"
default = "lyqtestterralb"
}
variable "location" {
description = "The location/region where the virtual network is created. Changing this forces a new resource to be created."
default = "chinanorth"
}
variable "virtual_network_name" {
description = "The name for the virtual network."
default = "lyq-test-vnet"
}
variable "address_space" {
description = "The address space that is used by the virtual network. You can supply more than one address space. Changing this forces a new resource to be created."
default = "10.0.0.0/16"
}
variable "subnet_prefix" {
description = "The address prefix to use for the subnet."
default = "10.0.10.0/24"
}
variable "storage_account_tier" {
description = "Defines the Tier of storage account to be created. Valid options are Standard and Premium."
default = "Premium"
}
variable "storage_replication_type" {
description = "Defines the Replication Type to use for this storage account. Valid options include LRS, GRS etc."
default = "LRS"
}
variable "vm_size" {
description = "Specifies the size of the virtual machine."
default = "Standard_D1"
}
variable "image_publisher" {
description = "name of the publisher of the image (az vm image list)"
default = "MicrosoftWindowsServer"
}
variable "image_offer" {
description = "the name of the offer (az vm image list)"
default = "WindowsServer"
}
variable "image_sku" {
description = "image sku to apply (az vm image list)"
default = "2012-R2-Datacenter"
}
variable "image_version" {
description = "version of the image to apply (az vm image list)"
default = "latest"
}
variable "admin_username" {
description = "administrator user name"
default = "lyqadmin"
}
variable "admin_password" {
description = "administrator password (recommended to disable password auth)"
default = "[email protected]"
}
如果我們不給參數定義default值,那麽在執行plan時,就會要求輸入相應的參數,這樣就可以實現自定義配置。
把這兩個腳本分別保存為tf文件,例如2VMLB.tf和variables.tf。然後執行terraform plan和 apply,不出意外的話,我們就可以在azure.cn界面裏看到創建出來的這些資源了。
因為指定的虛擬機用了win2012R2模板,所以需要進虛擬機去開啟IIS,完成後,就可以通過負載均衡的公網IP訪問了。
Code as IaaS for Azure : Terraform 做多一點事情