节前有用户提了两个需求,PostgreSQL和Terraform,趁着过节有大块的时间,把这两个都粗略的过了下。之前已经把PostgreSQL相关测试结果写了篇文档,正好把Terraform的学习经历也记录下来,写个文档。
Terraform的网站上是这么介绍的“Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions.”。在我看来它是一个可以实现跨云的代码即基础架构工具。目前Terraform支持的公有/私有云平台包括: AWS,Azure(ARM和ASM),阿里云,Google Cloud,Oracle Cloud,OpenStack,CloudStack,VMware等等等等等。嗯,要是还能支持AzureStack就完美了。
Terraform具体的功能可以在上学习,它的文档和示例都写得很不错,我在这就简单介绍下怎么用Terraform来管理Azure上的基础架构。
目前Terraform支持Azure ARM的功能如下
Base Resource | azurerm_resource_group | Creates a new resource group on Azure. |
Template | azurerm_template_deployment | Create a template deployment of resources |
Web App | azurerm_app_service_plan | Create an App Service Plan component |
azurerm_app_service | Manages an App Service (within an App Service Plan) | |
Virtual Machine | azurerm_virtual_machine | Create a virtual machine. |
azurerm_availability_set | Create an availability set for virtual machines. | |
azurerm_virtual_machine_extension | Creates a new Virtual Machine Extension to provide post deployment configuration and run automated tasks. | |
azurerm_virtual_machine_scale_set | Create a virtual machine scale set. | |
Storage | azurerm_storage_account | Create an Azure Storage Account. |
azurerm_storage_container | Create an Azure Storage Container. | |
azurerm_storage_blob | Create an Azure Storage Blob. | |
azurerm_storage_queue | Create an Azure Storage Queue. | |
azurerm_storage_share | Create an Azure Storage File Share. | |
azurerm_storage_table | Create an Azure Storage Table. | |
Managed Disk | azurerm_managed_disk | Create a managed disk. |
azurerm_image | Create a custom virtual machine image that can be used to create virtual machines. | |
Network | azurerm_express_route_circuit | Creates an ExpressRoute circuit. |
azurerm_local_network_gateway | Creates a new local network gateway connection over which specific connections can be configured. | |
azurerm_network_interface | Manages a Network Interface located in a Virtual Network, usually attached to a Virtual Machine. | |
azurerm_network_security_group | Create a network security group that contains a list of network security rules. | |
azurerm_network_security_rule | Create a Network Security Rule. | |
azurerm_public_ip | Create a Public IP Address. | |
azurerm_route | Creates a new Route Resource | |
azurerm_route_table | Creates a new Route Table Resource | |
azurerm_subnet | Creates a new subnet. Subnets represent network segments within the IP space defined by the virtual network. | |
azurerm_traffic_manager_endpoint | Creates a Traffic Manager Endpoint. | |
azurerm_traffic_manager_profile | Creates a Traffic Manager Profile to which multiple endpoints can be attached. | |
azurerm_virtual_network | Creates a new virtual network including any configured subnets. Each subnet can optionally be configured with a security group to be associated with the subnet. | |
azurerm_virtual_network_peering | Creates a new virtual network peering which allows resources to access other resources in the linked virtual network. | |
Load Balance | azurerm_lb | Create a LoadBalancer Resource. |
azurerm_lb_backend_address_pool | Create a LoadBalancer Backend Address Pool. | |
azurerm_lb_rule | Create a LoadBalancer Rule. | |
azurerm_lb_nat_rule | Create a LoadBalancer NAT Rule. | |
azurerm_lb_nat_pool | Create a LoadBalancer NAT pool. | |
azurerm_lb_probe | Create a LoadBalancer Probe Resource. | |
Automation | azurerm_automation_account | Creates a new Automation Account. |
azurerm_automation_credential | Creates a new Automation Credential. | |
azurerm_automation_runbook | Creates a new Automation Runbook. | |
azurerm_automation_schedule | Creates a new Automation Schedule. |
除了这些基础服务,Terraform还支持更多服务,包括Database:MySQL,SQL Server,还有Azure.com支持的PostgreSQL和CosmosDB。DNS 服务,KeyVault服务,消息队列:Event Hub,Service Bus。Redis服务,CDN服务,容器服务(Azure.com支持)。
要使用Terraform来部署Azure资源,官方建议是通过Service Principal 来通过Azure认证。我们会在每个部署脚本最前面看到这样一段内容:
provider "azurerm" {
subscription_id = "..."
client_id = "..."
client_secret = "..."
tenant_id = "..."
}
在这段脚本里指定了登录到哪个Azure环境,使用哪个订阅,以及用户认证。所以接下来我们首先要获得这几个参数。
首先,我们通过Azure Cli登录Azure。如果要登录Azure.cn,记得先用“az cloud set -n AzureChinaCloud” 设置登录环境。
用 az login 命令登录,按照提示进行网页验证。登录成功后会看到类似以下的返回:
[
{
"cloudName": "AzureChinaCloud",
"id": "XXXXXXXXXXXXXXXXXXXXXXXXXX",
"isDefault": true,
"name": "Microsoft Azure Enterprise \u8bd5\u7528\u7248",
"state": "Enabled",
"tenantId": "XXXXXXXXXXXXXXXXXXXXXXXXX",
"user": {
"name": "XXXXXXXX@smsptsp.partner.onmschina.cn",
"type": "user"
}
}
]
注意,这其中的id和tenantid就对应了我们需要的subscription_id和tenant_id这两个参数。
接下来用az ad sp create-for-rbac --role="Contributor" --scopes="/subscriptions/<subscription_id>" 这个命令来创建 Service Principal . 顺利的话可以看到以下返回:
Retrying role assignment creation: 1/36
Retrying role assignment creation: 2/36
Retrying role assignment creation: 3/36
{
"appId": "XXXXXXXXXXXXXXXXXXXXXXXXX",
"displayName": "azure-cli-2017-09-28-08-01-33",
"name": "http://azure-cli-2017-09-28-08-01-33",
"password": "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
"tenant": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
其中appId和password分别对应了我们需要的参数client_id和client_secret
其实也可以在GUI界面里进行相同的工作,结果大致如下图所示
顺便说一下,按照这个思路,我最后写了4个脚本,可以分别在Azure CLI和Powershell环境下登录Azure.com和Azure.cn。不需要在本机或Azure上保存任何证书都可以使用。还是很方便的。大家如果有兴趣以后再写一个文档说明是怎么做的。
获得所需要的Azure登录参数,我们就可以正式来写一个Terraform脚本来部署一个虚机了。
这次我们用到的脚本如下:
variable "resourcesname" {
default = "helloterraform"
}
# 这段是配置Azure的使用环境
# 注意,因为使用的是Azure.cn,所以要加上参数environment = "china",默认是azure.com,参数使用上面所讲的步骤里获得的那几个参数
provider "azurerm" {
subscription_id = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
client_id = "XXXXXXXXXXXXXXXXXXXXXXXXXXX"
client_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
tenant_id = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
environment = "china"
}
# 创建一个Resource Group,名字是lyq-testterraform-rg,位置是北京
resource "azurerm_resource_group" "helloterraform" {
name = "lyq-testterraform-rg"
location = "China North"
}
# 创建一个虚拟网络,给定name,IP,位置和所属资源组
resource "azurerm_virtual_network" "helloterraformnetwork" {
name = "tfvn"
address_space = ["10.0.0.0/16"]
location = "China North"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
}
# 创建一个虚拟子网
resource "azurerm_subnet" "helloterraformsubnet" {
name = "tfsub"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
virtual_network_name = "${azurerm_virtual_network.helloterraformnetwork.name}"
address_prefix = "10.0.2.0/24"
}
# 创建一个公网地址
resource "azurerm_public_ip" "helloterraformips" {
name = "terraformtestip"
location = "China North"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
public_ip_address_allocation = "dynamic"
tags {
environment = "TerraformDemo"
}
}
# 创建一块虚拟网卡
resource "azurerm_network_interface" "helloterraformnic" {
name = "tfni"
location = "China North"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
ip_configuration {
name = "testconfiguration1"
subnet_id = "${azurerm_subnet.helloterraformsubnet.id}"
private_ip_address_allocation = "static"
private_ip_address = "10.0.2.5"
public_ip_address_id = "${azurerm_public_ip.helloterraformips.id}"
}
}
# 创建一个随机数,我们知道存储账户是要求一个不冲突的独立命名,这个随机数就是用在存储账户里的
resource "random_id" "randomId" {
byte_length = 4
}
# 创建一个存储账户,也可以创建一个managed disk
resource "azurerm_storage_account" "helloterraformstorage" {
name = "tfstorage${random_id.randomId.hex}"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
location = "China North"
account_type = "Standard_LRS"
tags {
environment = "staging"
}
}
# 创建一个存储容器
resource "azurerm_storage_container" "helloterraformstoragestoragecontainer" {
name = "vhd"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
storage_account_name = "${azurerm_storage_account.helloterraformstorage.name}"
container_access_type = "private"
depends_on = ["azurerm_storage_account.helloterraformstorage"]
}
# 创建虚拟机,用Ubuntu系统,将之前创建的虚拟网卡,存储都挂载好,设定用户名和密码,在生产环境里建议disable_password_authentication = true,这样需要指定证书登录。
resource "azurerm_virtual_machine" "helloterraformvm" {
name = "terraformvm"
location = "China North"
resource_group_name = "${azurerm_resource_group.helloterraform.name}"
network_interface_ids = ["${azurerm_network_interface.helloterraformnic.id}"]
vm_size = "Standard_A0"
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "14.04.2-LTS"
version = "latest"
}
storage_os_disk {
name = "myosdisk"
vhd_uri = "${azurerm_storage_account.helloterraformstorage.primary_blob_endpoint}${azurerm_storage_container.helloterraformstoragestoragecontainer.name}/myosdisk.vhd"
caching = "ReadWrite"
create_option = "FromImage"
}
os_profile {
computer_name = "hostname"
admin_username = "testadmin"
admin_password = "Password1234!"
}
os_profile_linux_config {
disable_password_authentication = false
}
tags {
environment = "staging"
}
}
这样就可以创建一个虚拟机了。将以上脚本保存为tf文件,例如:lyqdemo.tf,然后先用terraform plan命令来验证脚本是否正确,还可以用-out参数来输出一个执行脚本,例如:terraform plan -out lyqdemo .
验证没有问题后,用 terraform apply 或 terraform apply lyqdemo 命令来执行变更。等执行完成后,我们可以在Azure.cn界面里查看下创建的是否正确
创建虚拟机可以说是最简单的一个动作了,接下来我们会做一些更复杂的事情。