Terraform 是一個 IT 基礎(chǔ)架構(gòu)自動化編排工具与学,它的口號是 "Write, Plan, and create Infrastructure as Code", 基礎(chǔ)架構(gòu)即代碼鸯隅。Terraform 幾乎可以支持所有市面上能見到的云服務(wù)邦尊。
Terraform 要解決的就是在云上那些硬件資源分配管理的問題。相比較 Chef, Puppet, Ansible 這些軟件配置工具立由,Terraform 提供的是軟件配置之前后裸,軟硬件(基礎(chǔ))資源構(gòu)建的問題。
當(dāng)我們創(chuàng)建資源時殖蚕,使用 terraform 比 ansible 好在哪里轿衔?
- 并發(fā)創(chuàng)建,速度快
- 擴(kuò)容/縮容 很方便睦疫,改一個數(shù)字就行
- state 文件記錄資源狀態(tài)
就創(chuàng)建資源這個角度來說害驹,terraform 和 ansible 都能完成,terraform能夠并發(fā)蛤育,效率高很多宛官,另外它在資源生產(chǎn)成功之后會在本地以一個state文件的形式記錄整個資源的詳細(xì)信息葫松,而這些信息的記錄使得整個模板所定義的資源可以保證前后端的高度一致性,可以有利于后續(xù)對于整個一套資源的有效的版本控制底洗。同時Terraform擁有一個Data Source功能腋么,利用這個功能可以實現(xiàn)對于已有資源的獲取,比如在生產(chǎn)資源之前想要查看當(dāng)前有哪些可用區(qū)亥揖,有哪些可用鏡像等珊擂,所有的這些都可以通過DataSource實現(xiàn)。
Terraform 和 Ansible 的結(jié)合
- terraform 調(diào)用 ansible
- Provisioner(local-exec, remote-exec) (官方推薦)
- ansible 調(diào)用 terraform
- Ansible module for terraform(官方推薦)
- 其它方式
- terraform output 生成 inventory 給 ansible 使用(手工)
- Terraform template 渲染后费变,生成 inventory 給 ansible 使用(自動)
- Terraform創(chuàng)建的時候使用tag摧扇,ansible直接對tag 操作(完全解耦,云平臺挚歧,動態(tài)主機(jī)列表)
- 第三方工具解析state文件給ansible使用扛稽。 比如 Terraform - Inventory 這個第三方工具能夠?qū)erraform生產(chǎn)出的資源轉(zhuǎn)化為Ansible想要的Inventory文件
安裝軟件
- 下載zip 文件 https://www.terraform.io/downloads.html
- 解壓后直接就能用。把文件放到合適的路徑滑负,比如 /usr/local/bin
生成配置文件
-
新建目錄在张,并生成配置文件,比如 azure.tf
# Configure the provider provider "azurerm" { version = "=1.20.0" } # Create a new resource group resource "azurerm_resource_group" "rg" { name = "royTR" location = "eastasia" }
配置有兩部分:provider 和 resource橙困。provider 告知與哪一個云平臺打交道瞧掺,這里是Azure;如果使用AWS凡傅,這里就寫成 provider "aws"辟狈。第二部分是資源,說明要生成哪些資源夏跷,例子中是resource group哼转,還可以繼續(xù)往下寫,比如網(wǎng)卡槽华,存儲壹蔓,虛擬機(jī)等。
格式:resource resource_type resource_name { }
A resource block has two string parameters before opening the block: the resource type (first parameter) and the resource name (second parameter). The combination of the type and name must be unique in the configuration.
我已經(jīng)通過Azure CLI 登陸過猫态,所以上面provider 部分沒有提供用戶驗證信息佣蓉,如果單獨配置,使用如下形式:
# Configure the Microsoft Azure Provider
provider "azurerm" {
# More information on the authentication methods supported by
# the AzureRM Provider can be found here:
# http://terraform.io/docs/providers/azurerm/index.html
subscription_id = "..."
client_id = "..."
client_secret = "..."
tenant_id = "..."
}
這些信息怎么獲取? 可以用Azure CLI 的命令生成:
az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/${SUBSCRIPTION_ID}"
詳細(xì)信息參考微軟文檔
創(chuàng)建資源
-
初始化
在初始化項目的時候亲雪,Terraform 會解析目錄下的*.tf文件并加載相關(guān)的 provider插件勇凭。
$ terraform init
Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "azurerm" (1.20.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.
-
apply changes
This output shows the execution plan, describing which actions Terraform will take in order to change real infrastructure to match the configuration.
$ terraform apply . An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: + azurerm_resource_group.rg id: <computed> location: "eastasia" name: "royTR" tags.%: <computed> Plan: 1 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes # 查看 execution plan 符合期望,輸入 yes 確認(rèn)义辕,之后真正執(zhí)行虾标。 azurerm_resource_group.rg: Creating... location: "" => "eastasia" name: "" => "royTR" tags.%: "" => "<computed>" azurerm_resource_group.rg: Creation complete after 1s (ID: /subscriptions/7c91db0e-eb7f-491b-997f-32cf55b85dea/resourceGroups/royTR) Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
- 查看狀態(tài)
$ terraform state show
id = /subscriptions/7c91db0e-eb7f-491b-997f-32cf55b85dea/resourceGroups/royTR
location = eastasia
name = royTR
tags.% = 0
更多
$ terraform state list
module.roy-azure.azurerm_availability_set.hdp-avset
module.roy-azure.azurerm_network_interface.bastion-nic
...
$ terraform state show module.roy-azure.azurerm_virtual_machine.hdp-slave[1]
...
location = japaneast
name = roy-tf0-hdp-slave-02
...
$ terraform state show module.roy-azure.azurerm_network_interface.hdp[0]
...
ip_configuration.0.load_balancer_backend_address_pools_ids.# = 0
ip_configuration.0.load_balancer_inbound_nat_rules_ids.# = 0
ip_configuration.0.name = hdp-01-ip-conf
....
private_ip_address = 10.0.10.8
...
更改資源
-
改配置
修改剛才的文件,添加tag部分灌砖。
# Configure the provider
provider "azurerm" {
version = "=1.20.0"
}
# Create a new resource group
resource "azurerm_resource_group" "rg" {
name = "royTR"
location = "eastasia"
tags {
environment = "TF sandbox"
}
}
-
apply changes
An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: ~ azurerm_resource_group.rg tags.%: "0" => "1" tags.environment: "" => "TF sandbox" Plan: 0 to add, 1 to change, 0 to destroy.
銷毀基礎(chǔ)設(shè)施
terraform destroy
$ terraform destroy
azurerm_resource_group.rg: Refreshing state... (ID: /subscriptions/xxxx/resourceGroups/royTR-rg)
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
- azurerm_resource_group.rg
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
azurerm_resource_group.rg: Destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxx/resourceGroups/royTR-rg, 10s elapsed)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg, 20s elapsed)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg, 30s elapsed)
azurerm_resource_group.rg: Still destroying... (ID: /subscriptions/xxxxx/resourceGroups/royTR-rg, 40s elapsed)
azurerm_resource_group.rg: Destruction complete after 48s
Destroy complete! Resources: 1 destroyed.
單獨刪除一個資源:
$ terraform destroy -target=module.roy-azure.azurerm_virtual_machine.hdp[2]
...
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
- module.roy-azure.azurerm_virtual_machine.hdp[2]
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
....
Destroy complete! Resources: 1 destroyed.
資源的依賴關(guān)系
要創(chuàng)建一個VM璧函,需要一些資源已經(jīng)具備傀蚌,這些資源可能包括:
- Resource group
- Virtual network and subnet
- Public IP
- Network security group
- Network interface
先來一個簡單的例子,創(chuàng)建網(wǎng)絡(luò):
# Create virtual network
resource "azurerm_virtual_network" "vnet" {
name = "royTFVnet"
address_space = ["10.0.0.0/16"]
location = "${azurerm_resource_group.rg.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
}
在location
等部分引入了插值(interpolation)蘸吓,它已經(jīng)在前面的資源定義善炫,之后直接調(diào)用,格式是 TYPE.NAME.ATTRIBUTE.
Azure 網(wǎng)絡(luò)和虛擬機(jī)的基礎(chǔ)架構(gòu)如下圖所示:
把上面的圖美澳,變成代碼销部,創(chuàng)建VM需要的整個文件:
# Configure the provider
provider "azurerm" {
version = "=1.20.0"
}
# Create a new resource group
resource "azurerm_resource_group" "rg" {
name = "royTR"
location = "eastasia"
tags {
environment = "TF sandbox"
}
}
# Create virtual network
resource "azurerm_virtual_network" "vnet" {
name = "royTFVnet"
address_space = ["10.0.0.0/16"]
location = "${azurerm_resource_group.rg.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
}
# Create subnet
resource "azurerm_subnet" "subnet" {
name = "royTFSubnet"
resource_group_name = "${azurerm_resource_group.rg.name}"
virtual_network_name = "${azurerm_virtual_network.vnet.name}"
address_prefix = "10.0.1.0/24"
#address_prefix = "${cidrsubnet(var.cluster_cidr, 8, 10)}"
}
# Create public IP
resource "azurerm_public_ip" "publicip" {
name = "myTFPublicIP"
location = "${azurerm_resource_group.rg.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
public_ip_address_allocation = "dynamic"
}
# Create Network Security Group and rule
resource "azurerm_network_security_group" "nsg" {
name = "myTFNSG"
location = "${azurerm_resource_group.rg.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
security_rule {
name = "SSH"
priority = 1001
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" "nic" {
name = "myNIC"
location = "${azurerm_resource_group.rg.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
network_security_group_id = "${azurerm_network_security_group.nsg.id}"
ip_configuration {
name = "myNICConfg"
subnet_id = "${azurerm_subnet.subnet.id}"
private_ip_address_allocation = "dynamic"
public_ip_address_id = "${azurerm_public_ip.publicip.id}"
}
}
# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {
name = "royTFVM"
location = "${azurerm_resource_group.rg.location}"
resource_group_name = "${azurerm_resource_group.rg.name}"
network_interface_ids = ["${azurerm_network_interface.nic.id}"]
vm_size = "Standard_DS1_v2"
storage_os_disk {
name = "myOsDisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
}
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04.0-LTS"
version = "latest"
}
os_profile {
computer_name = "royvm"
admin_username = "royzeng"
}
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
path = "/home/royzeng/.ssh/authorized_keys"
key_data = "ssh-rsa AAAAB3Nz{snip}hwhqT9h"
}
}
}
使用 Provisioners 進(jìn)行環(huán)境配置
Provisioners 可以在資源創(chuàng)建/銷毀時在本地/遠(yuǎn)程執(zhí)行腳本。
Provisioners 通常用來引導(dǎo)一個資源制跟,在銷毀資源前完成清理工作,進(jìn)行配置管理等酱虎。
Provisioners擁有多種類型可以滿足多種需求雨膨,如:文件傳輸(file),本地執(zhí)行(local-exec)读串,遠(yuǎn)程執(zhí)行(remote-exec)等 Provisioners可以添加在任何的resource當(dāng)中:
# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {
<...snip...>
provisioner "file" {
connection {
type = "ssh"
user = "royzeng"
private_key = "${file("~/.ssh/id_rsa")}"
}
source = "newfile.txt"
destination = "newfile.txt"
}
provisioner "remote-exec" {
connection {
type = "ssh"
user = "royzeng"
private_key = "${file("~/.ssh/id_rsa")}"
}
inline = [
"ls -a",
"cat newfile.txt"
]
}
}
上面的方式適合有public ip聊记,能夠直接連接的機(jī)器,對于不能直接連接的vm恢暖,通過跳板來實現(xiàn)排监。
官方的方法,定義 bastion_host
resource "null_resource" "connect_private" {
connection {
bastion_host = "${aws_instance.bastion.public_ip}"
host = "${aws_instance.private.private_ip}"
user = "ubuntu"
private_key = "${file("~/.ssh/id_rsa")}"
}
provisioner "remote-exec" {
inline = ["echo 'CONNECTED to PRIVATE!'"]
}
}
或者
resource "azurerm_virtual_machine" "vm" {
<...snip...>
provisioner "remote-exec" {
connection {
bastion_host= "${azurerm_public_ip.bastion.ip_address}"
type = "ssh"
user = "${var.admin-username}"
private_key = "${file("~/.ssh/id_rsa")}"
}
inline = [
"sudo parted /dev/disk/azure/scsi1/lun0 mklabel msdos",
"sudo parted /dev/disk/azure/scsi1/lun0 mkpart primary 1 100%",
"sudo partprobe",
"sleep 5; sudo mkfs.xfs /dev/disk/azure/scsi1/lun0-part1",
"sudo mkdir /roytest",
"sudo mount /dev/disk/azure/scsi1/lun0-part1 ${var.mount_path[0]}",
"echo 'UUID='`sudo blkid -s UUID -o value $(readlink -f /dev/disk/azure/scsi1/lun0-part1)` ${var.mount_path[0]} 'xfs defaults 0 0' | sudo tee -a /etc/fstab",
"df -hl | grep /dev/sd"
]
}
}
另一種方法杰捂,用local-exec 來跳轉(zhuǎn)
provisioner "local-exec" {
## 簡化方式
command = "ssh -o "ProxyCommand ssh -q -W %h:%p -i mykey jump_server” -C 'echo hello'"
## 真實環(huán)境用的方式
command = <<EOF
sleep 30; ansible-playbook -i '${element(azurerm_network_interface.master_bind.*.private_ip_address, count.index)},' ${local.ansible_ssh_args} ${var.ansible_path}/mount_disk.yml --extra-vars '{
"root_user": "centos",
"deviceName": "/dev/disk/azure/scsi1/lun0",
"mountPath": "${var.mount_path}",
"bind_zone_name": "${var.bind_zone_name}"
}'
EOF
}
使用 null resource 和 trigger 來解耦
為了讓ansible 腳本單獨運(yùn)行舆床,而不需要創(chuàng)建或銷毀資源,可以用 null_resource 調(diào)用 provisioner 來實現(xiàn)嫁佳。
resource "null_resource" "datanode" {
count = "${var.count.datanode}"
triggers {
instance_ids = "${element(aws_instance.datanode.*.id, count.index)}"
}
provisioner "remote-exec" {
inline = [
...
]
connection {
type = "ssh"
user = "centos"
host = "${element(aws_instance.datanode.*.private_ip, count.index)}"
}
}
}
輸入變量
新建一個文件定義變量
# file variables.tf
---
variable "prefix" {
default = "royTF"
}
variable "location" { }
variable "tags" {
type = "map"
default = {
Environment = "royDemo"
Dept = "Engineering"
}
}
文件中 location
部分沒有定義挨队,運(yùn)行terraform的時候,會提示輸入:
$ terraform plan -out royplan
var.location
Enter a value: eastasia
<...snip...>
This plan was saved to: royplan
To perform exactly these actions, run the following command to apply:
terraform apply "royplan"
其它輸入變量的方式
命令行輸入
$ terraform apply \
>> -var 'prefix=tf' \
>> -var 'location=eastasia'
文件輸入
$ terraform apply \
-var-file='secret.tfvars'
默認(rèn)讀取文件 terraform.tfvars
蒿往,這個文件不需要單獨指定盛垦。
環(huán)境變量輸入
TF_VAR_name
,比如 TF_VAR_location
變量類型
- list
- map
對于 list 變量
# 定義 list 變量
variable "image-RHEL" {
type = "list"
default = ["RedHat", "RHEL", "7.5", "latest"]
}
# 調(diào)用 list 變量
storage_image_reference {
publisher = "${var.image-RHEL[0]}"
offer = "${var.image-RHEL[1]}"
sku = "${var.image-RHEL[2]}"
version = "${var.image-RHEL[3]}"
}
map 是一個可以被查詢的表瓤漏。
variable "sku" {
type = "map"
default = {
westus = "16.04-LTS"
eastus = "18.04-LTS"
}
}
查詢方式(使用 lookup)
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "${lookup(var.sku, var.location)}"
version = "latest"
}
輸出變量
定義輸出
output "ip" {
value = "${azurerm_public_ip.publicip.ip_address}"
}
測試
$ terraform apply
...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
ip = 52.184.97.1
$ terraform output ip
52.184.97.1
Bug? 第一次運(yùn)行腾夯,ip 輸出是空的,terraform output ip
命令的結(jié)果也是空的蔬充,過一段時間才能看到結(jié)果蝶俱。
$ terraform output -module=roy-azure
bastion-private-ip = 10.0.1.4
bastion-public-ip = 40.115.243.72
cluster_cidr = 10.0.0.0/16
cluster_location = japaneast
cluster_prefix = roy-tf0
cluster_resource_group = roy-tf0-rg
hdp-master-ip = 10.0.10.4,10.0.10.6,10.0.10.7
hdp-master-name = roy-tf0-hdp-master-01,roy-tf0-hdp-master-02,roy-tf0-hdp-master-03
hdp-slave-ip = 10.0.10.5,10.0.10.9,10.0.10.8
hdp-slave-name = roy-tf0-hdp-slave-01,roy-tf0-hdp-slave-02,roy-tf0-hdp-slave-03
k8s-master-ip = 10.0.20.8,10.0.20.5
k8s-master-name = roy-tf0-k8s-master-01,roy-tf0-k8s-master-02
k8s-slave-ip = 10.0.20.6,10.0.20.7,10.0.20.4
k8s-slave-name = roy-tf0-k8s-slave-01,roy-tf0-k8s-slave-02,roy-tf0-k8s-slave-03
virtual_network = roy-tf0-vnet
Data Source
DataSource 的作用可以通過輸入一個資源的變量名,然后獲得這個變量的其他屬性字段娃惯。
用 Azure網(wǎng)絡(luò) 來舉例跷乐,提供一些信息,查詢其它的屬性趾浅。具體必須提供什么愕提,能查到什么馒稍,參考這個鏈接。
data "azurerm_virtual_network" "test" {
name = "production"
resource_group_name = "networking"
}
output "virtual_network_id" {
value = "${data.azurerm_virtual_network.test.id}"
}
output "virtual_network_subnet" {
value = "${data.azurerm_virtual_network.test.subnets[0]}"
}
生成主機(jī)列表
ansible通過主機(jī)列表來連接目標(biāo)主機(jī)浅侨,我們就要想辦法讓terraform來生成纽谒。(local-exec 也是一種方式,這是另一種思路:用terraform 調(diào)用ansible)
terraform 生成inventory的思路是:從模板到文件如输,需要先用template_file 渲染成一個字符串鼓黔,然后用local_file把這個字符串輸出到一個文件。
模版文件
## file inventory.tpl
[backend]
${bastion_private_ip}
[frontend]
${bastion_pub_ip}
[all:vars]
ansible_ssh_private_key_file = ${key_path}
ansible_ssh_user = dcpuser
渲染和輸出
## file inventory.tf
data "template_file" "inventory" {
template = "${file("./test/inventory.tpl")}"
vars {
bastion_private_ip = "${element(azurerm_network_interface.bastion-nic.*.private_ip_address, count.index)}"
bastion_pub_ip = "${element(azurerm_public_ip.bastion.*.ip_address, count.index)}"
key_path = "~/.ssh/id_rsa"
}
}
resource "local_file" "save_inventory" {
content = "${data.template_file.inventory.rendered}"
filename = "./myhost"
}
運(yùn)行后不见,當(dāng)前目錄生成文件myhost
[backend]
13.78.94.242
[frontend]
10.0.1.4
[all:vars]
ansible_ssh_private_key_file = ~/.ssh/id_rsa
ansible_ssh_user = dcpuser
對于多個主機(jī)澳化,使用 join
來把它們合在一起。
File inventory.tf
data "template_file" "k8s" {
template = "${file("./templates/k8s.tpl")}"
vars {
k8s_master_name = "${join("\n", azurerm_virtual_machine.k8s-master.*.name)}"
}
}
resource "local_file" "k8s_file" {
content = "${data.template_file.k8s.rendered}"
filename = "./inventory/k8s-host"
}
File k8s.tpl
[kube-master]
${k8s_master_name}
Final result
[kube-master]
k8s-master-01
k8s-master-02
k8s-master-03
使用module進(jìn)行代碼的組織管理
Module 是 Terraform 為了管理單元化資源而設(shè)計的稳吮,是子節(jié)點缎谷,子資源,子架構(gòu)模板的整合和抽象灶似。將多種可以復(fù)用的資源定義為一個module列林,通過對 module 的管理簡化模板的架構(gòu),降低模板管理的復(fù)雜度酪惭,這就是module的作用希痴。
Terraform中的模塊是以組的形式管理不同的Terraform配置。模塊用于在Terraform中創(chuàng)建可重用組件春感,以及用于基本代碼組織砌创。每一個module都可以定義自己的input與output,方便代碼進(jìn)行模塊化組織甥厦。
用模塊纺铭,可以寫更少的代碼。比如用下面的代碼刀疙,調(diào)用已有的module 創(chuàng)建vm舶赔。
調(diào)用官方module
# declare variables and defaults
variable "location" {}
variable "environment" {
default = "dev"
}
variable "vm_size" {
default = {
"dev" = "Standard_B2s"
"prod" = "Standard_D2s_v3"
}
}
# Use the network module to create a resource group, vnet and subnet
module "network" {
source = "Azure/network/azurerm"
version = "2.0.0"
location = "${var.location}"
resource_group_name = "roytest-rg"
address_space = "10.0.0.0/16"
subnet_names = ["mySubnet"]
subnet_prefixes = ["10.0.1.0/24"]
}
# Use the compute module to create the VM
module "compute" {
source = "Azure/compute/azurerm"
version = "1.2.0"
location = "${var.location}"
resource_group_name = "roytest-rg"
vnet_subnet_id = "${element(module.network.vnet_subnets, 0)}"
admin_username = "royzeng"
admin_password = "Password1234!"
remote_port = "22"
vm_os_simple = "UbuntuServer"
vm_size = "${lookup(var.vm_size, var.environment)}"
public_ip_dns = ["roydns"]
}
調(diào)用自己寫的module
## file main.cf
module "roy-azure" {
source = "./test"
}
## file test/resource.tf
variable "cluster_prefix" {
type = "string"
}
variable "cluster_location" {
type = "string"
}
resource "azurerm_resource_group" "core" {
name = "${var.cluster_prefix}-rg"
location = "${var.cluster_location}"
}
參考文檔
https://docs.microsoft.com/en-us/azure/virtual-machines/linux/terraform-install-configure
https://learn.hashicorp.com/terraform/azure/install_az
https://www.terraform.io/docs/providers/azurerm/r/virtual_machine.html
Create a VM cluster with Terraform https://docs.microsoft.com/en-us/azure/terraform/terraform-create-vm-cluster-with-infrastructure
http://aukjan.vanbelkum.nl/2016/02/23/Ansible-inventory-from-Terraform/
Terraform Azure modules https://registry.terraform.io/browse?offset=9&provider=azurerm
How to use Ansible with Terraform https://alex.dzyoba.com/blog/terraform-ansible/