Terraform 學(xué)習(xí)筆記

Terraform 是一個(gè) IT 基礎(chǔ)架構(gòu)自動(dòng)化編排工具,它的口號(hào)是 "Write, Plan, and create Infrastructure as Code", 基礎(chǔ)架構(gòu)即代碼。Terraform 幾乎可以支持所有市面上能見(jiàn)到的云服務(wù)。

Terraform 要解決的就是在云上那些硬件資源分配管理的問(wèn)題。相比較 Chef, Puppet, Ansible 這些軟件配置工具,Terraform 提供的是軟件配置之前,軟硬件(基礎(chǔ))資源構(gòu)建的問(wèn)題。

當(dāng)我們創(chuàng)建資源時(shí),使用 terraform 比 ansible 好在哪里?

  • 并發(fā)創(chuàng)建,速度快
  • 擴(kuò)容/縮容 很方便,改一個(gè)數(shù)字就行
  • state 文件記錄資源狀態(tài)

就創(chuàng)建資源這個(gè)角度來(lái)說(shuō),terraform 和 ansible 都能完成,terraform能夠并發(fā),效率高很多,另外它在資源生產(chǎn)成功之后會(huì)在本地以一個(gè)state文件的形式記錄整個(gè)資源的詳細(xì)信息,而這些信息的記錄使得整個(gè)模板所定義的資源可以保證前后端的高度一致性,可以有利于后續(xù)對(duì)于整個(gè)一套資源的有效的版本控制。同時(shí)Terraform擁有一個(gè)Data Source功能,利用這個(gè)功能可以實(shí)現(xiàn)對(duì)于已有資源的獲取,比如在生產(chǎn)資源之前想要查看當(dāng)前有哪些可用區(qū),有哪些可用鏡像等,所有的這些都可以通過(guò)DataSource實(shí)現(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 使用(自動(dòng))
    • Terraform創(chuàng)建的時(shí)候使用tag,ansible直接對(duì)tag 操作(完全解耦,云平臺(tái),動(dòng)態(tài)主機(jī)列表)
    • 第三方工具解析state文件給ansible使用。 比如 Terraform - Inventory 這個(gè)第三方工具能夠?qū)erraform生產(chǎn)出的資源轉(zhuǎn)化為Ansible想要的Inventory文件

安裝軟件

  1. 下載zip 文件 https://www.terraform.io/downloads.html
  2. 解壓后直接就能用。把文件放到合適的路徑,比如 /usr/local/bin

生成配置文件

  1. 新建目錄,并生成配置文件,比如 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 告知與哪一個(gè)云平臺(tái)打交道,這里是Azure;如果使用AWS,這里就寫(xiě)成 provider "aws"。第二部分是資源,說(shuō)明要生成哪些資源,例子中是resource group,還可以繼續(xù)往下寫(xiě),比如網(wǎng)卡,存儲(chǔ),虛擬機(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)通過(guò)Azure CLI 登陸過(guò),所以上面provider 部分沒(méi)有提供用戶驗(yàn)證信息,如果單獨(dú)配置,使用如下形式:

# 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)建資源

  1. 初始化

    在初始化項(xiàng)目的時(shí)候,Terraform 會(huì)解析目錄下的*.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.
  1. 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.
    
  1. 查看狀態(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
...

更改資源

  1. 改配置

    修改剛才的文件,添加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"
       }
   }
  1. 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.
    

銷(xiāo)毀基礎(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.

單獨(dú)刪除一個(gè)資源:

$ 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)系

要?jiǎng)?chuàng)建一個(gè)VM,需要一些資源已經(jīng)具備,這些資源可能包括:

  • Resource group
  • Virtual network and subnet
  • Public IP
  • Network security group
  • Network interface

先來(lái)一個(gè)簡(jiǎn)單的例子,創(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)如下圖所示:

azure_vm_structure.png

把上面的圖,變成代碼,創(chuàng)建VM需要的整個(gè)文件:

# 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)建/銷(xiāo)毀時(shí)在本地/遠(yuǎn)程執(zhí)行腳本。

Provisioners 通常用來(lái)引導(dǎo)一個(gè)資源,在銷(xiāo)毀資源前完成清理工作,進(jìn)行配置管理等。

Provisioners擁有多種類(lèi)型可以滿足多種需求,如:文件傳輸(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ī)器,對(duì)于不能直接連接的vm,通過(guò)跳板來(lái)實(shí)現(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 來(lái)跳轉(zhuǎn)

  provisioner "local-exec" {
    ## 簡(jiǎn)化方式
    command = "ssh -o "ProxyCommand ssh -q -W %h:%p -i mykey jump_server” -C 'echo hello'"
    ## 真實(shí)環(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 來(lái)解耦

為了讓ansible 腳本單獨(dú)運(yùn)行,而不需要?jiǎng)?chuàng)建或銷(xiāo)毀資源,可以用 null_resource 調(diào)用 provisioner 來(lái)實(shí)現(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)}"
    }
  }
}

輸入變量

新建一個(gè)文件定義變量

# file variables.tf
---
variable "prefix" {
  default = "royTF"
}

variable "location" { }

variable "tags" {
  type    = "map"
  default = {
     Environment = "royDemo"
     Dept = "Engineering"
  }
}

文件中 location 部分沒(méi)有定義,運(yùn)行terraform的時(shí)候,會(huì)提示輸入:

$ 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,這個(gè)文件不需要單獨(dú)指定。

環(huán)境變量輸入

TF_VAR_name ,比如 TF_VAR_location

變量類(lèi)型

  • list
  • map

對(duì)于 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 是一個(gè)可以被查詢的表。

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}"
}

測(cè)試

$ 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é)果也是空的,過(guò)一段時(shí)間才能看到結(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 的作用可以通過(guò)輸入一個(gè)資源的變量名,然后獲得這個(gè)變量的其他屬性字段。

用 Azure網(wǎng)絡(luò) 來(lái)舉例,提供一些信息,查詢其它的屬性。具體必須提供什么,能查到什么,參考這個(gè)鏈接

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通過(guò)主機(jī)列表來(lái)連接目標(biāo)主機(jī),我們就要想辦法讓terraform來(lái)生成。(local-exec 也是一種方式,這是另一種思路:用terraform 調(diào)用ansible)

terraform 生成inventory的思路是:從模板到文件,需要先用template_file 渲染成一個(gè)字符串,然后用local_file把這個(gè)字符串輸出到一個(gè)文件。

模版文件

## 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

對(duì)于多個(gè)主機(jī),使用 join 來(lái)把它們合在一起。

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è)計(jì)的,是子節(jié)點(diǎn),子資源,子架構(gòu)模板的整合和抽象。將多種可以復(fù)用的資源定義為一個(gè)module,通過(guò)對(duì) module 的管理簡(jiǎn)化模板的架構(gòu),降低模板管理的復(fù)雜度,這就是module的作用。

Terraform中的模塊是以組的形式管理不同的Terraform配置。模塊用于在Terraform中創(chuàng)建可重用組件,以及用于基本代碼組織。每一個(gè)module都可以定義自己的input與output,方便代碼進(jìn)行模塊化組織。

用模塊,可以寫(xiě)更少的代碼。比如用下面的代碼,調(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)用自己寫(xiě)的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

Provisioner connections

Terraform example

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/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,817評(píng)論 0 10
  • The Inner Game of Tennis W Timothy Gallwey Jonathan Cape ...
    網(wǎng)事_79a3閱讀 12,882評(píng)論 3 20
  • 朋友說(shuō),你看一個(gè)人手機(jī)里的音樂(lè),就能知道他大概是怎樣的人,看你的音樂(lè)就覺(jué)得你是那種“文藝青年”。我說(shuō),“文藝青年...
    米糖西西閱讀 435評(píng)論 3 2
  • 這一天是寒冷的,十二月中旬也是該讓我們感受下冬天的真正傷害了,清晨六點(diǎn),被鬧鈴驚醒,絲絲倦意依然在眼中彌漫,在想到...
    邂逅君閱讀 344評(píng)論 2 3

友情鏈接更多精彩內(nèi)容