1 概述
terraform学习。 语法查询https://developer.hashicorp.com/terraform/language provider地址https://registry.terraform.io/browse/modules 最佳实践 https://www.cloudbolt.io/eguides/terraform-best-practices/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 命令 用途 terraform version 查看 Terraform 版本 terraform init 初始化 Terraform terraform plan Terraform 执行计划 terraform apply 应用 Terraform terraform show 检查 Terraform 状态 terraform output 查看输出变量的值 terraform graph 生成资源依赖图 terraform destroy 销毁资源 terraform workspace 管理 Terraform 工作区 terraform workspace new 新建工作区 terraform workspace list 列出工作区 terraform workspace select 切换工作区 terraform workspace delete 删除工作区 terraform get 下载或更新 Terraform 模块 terraform fmt 格式化 Terraform 代码 terraform validate 检查 Terraform 语法 terraform console Terraform 控制台
3.1.1 alias的使用
多个 Azure 订阅管理: 如果你有多个 Azure 订阅,每个订阅可能有不同的资源组和资源,你可以通过不同的 alias 配置来管理它们
跨环境管理: 在开发、测试和生产环境中可能有不同的 Azure 订阅或账户,使用 alias 可以在同一个 Terraform 配置文件中管理这些环境的资源。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 terraform { required_version = "~> 1.1" required_providers { azurerm = { version = "~> 3.9.0" } } } provider "azurerm" { # 订阅id subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" alias = "sub1" features {} } provider "azurerm" { subscription_id = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy" alias = "sub2" features {} } resource "azurerm_resource_group" "rg" { provider = azurerm.sub1 # 使用别名为 sub1 的 Azure provider name = "rg-sub1" location = "westeurope" } resource "azurerm_resource_group" "rg2" { provider = azurerm.sub2 # 使用别名为 sub2 的 Azure provider name = "rg-sub2" location = "westeurope" }
3.1.2 使用check来验证基础设施 1 2 3 4 5 6 7 8 9 10 11 12 check "response" { data "http" "webapp" { url = "https://${azurerm_linux_web_app.app.default_hostname}" insecure = true } #通过检查http url地址访问状态码是否为200 assert { condition = data.http.webapp.status_code == 200 error_message = "Web app response is ${data.http.webapp.status_code}" } }
3.1.3 depends_on的使用
https://developer.hashicorp.com/terraform/language/meta-arguments/depends_on
1 2 3 4 5 6 7 8 9 10 11 12 13 14 resource "azurerm_resource_group" "rg" { name = "rgdep" location = "westeurope" } resource "azurerm_virtual_network" "vnet" { name = "vnet" location = "westeurope" resource_group_name = "rgdep" address_space = ["10.0.0.0/16"] depends_on = [azurerm_resource_group.rg] }
3.1.4 函数upper的使用
函数upper的使用,将给定字符串中的所有大小写字母转换为大写 更多函数的使用参考:https://developer.hashicorp.com/terraform/language/functions/chomp
1 2 3 4 5 #FOR CONDITION resource "azurerm_resource_group" "rg-app" { name = var.environment == "Production" ? upper(format("RG-%s", var.app_name)) : upper(format("RG-%s-%s", var.app_name, var.environment)) location = "westeurope" }
3.1.5 环境变量local块的使用 示例1
1 2 3 4 5 6 7 8 9 10 11 12 13 resource "azurerm_public_ip" "pip" { name = "IP-${local.resource_name}" location = "westeurope" resource_group_name = azurerm_resource_group.rg.name allocation_method = "Dynamic" domain_name_label = "mydomain" } locals { resource_name = "${var.application_name}-${var.environment_name}-${var.country_code}" }
示例2
动态配置生成:适用于需要根据外部数据源(如 YAML 文件)动态生成资源配置的场景,避免硬编码每个子网的配置。 模块化和复用:通过 dynamic 块可以实现资源配置的模块化和复用,尤其是在处理变化和扩展性较高的情况下。
1 2 3 4 5 6 7 8 vnet: "myvnet" address_space: "10.0.0.0/16" subnets: - name: subnet1 iprange: "10.0.1.0/24" - name: subnet2 iprange: "10.0.2.0/24"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 locals { network = yamldecode(file("network.yaml")) } resource "azurerm_virtual_network" "vnet" { name = local.network.vnet address_space = [local.network.address_space] dynamic "subnet" { #动态生成子网 for_each = local.network.subnets #遍历列表 content { #content 块:content 块内部的配置会根据 for_each 迭代生成多个实例,每个实例代表一个子网。 name = subnet.value.name address_prefix = subnet.value.iprange } } }
3.1.6 output块的使用 1 2 3 4 output "webapp_name" { description = "output Name of the webapp" value = azurerm_app_service.app.name }
3.1.7 随机数的使用
https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 resource "random_password" "password" { length = 16 special = true override_special = "_%@" } # Create virtual machine resource "azurerm_linux_virtual_machine" "myterraformvm" { name = "myVM" location = "westeurope" resource_group_name = azurerm_resource_group.myterraformgroup.name network_interface_ids = [azurerm_network_interface.myterraformnic.id] disable_password_authentication = false computer_name = "vmdemo" admin_username = "uservm" admin_password = random_password.password.result size = "Standard_DS1_v2" os_disk { name = "myOsDisk" caching = "ReadWrite" storage_account_type = "Standard_LRS" }
1 2 3 4 5 6 7 8 resource "random_string" "random" { length = 4 special = false upper = false } resource "azurerm_resource_group" "rg-app" { name = "${random_string.random.result}" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 provider "azurerm" { skip_provider_registration = true # skip registration features {} # features } # data "terraform_remote_state" "service_plan_tfstate" 用于从远程存储中获取 Terraform 状态信息。 data "terraform_remote_state" "service_plan_tfstate" { backend = "azurerm" #远程后端 config = { # config 区块包含了连接到远程状态存储所需的详细信息: resource_group_name = "rg_tfstate" storage_account_name = "storstate" container_name = "tfbackends" key = "serviceplan.tfstate" } }
3.1.9 variables的使用 1 2 # 定义的location变量要符合validation中的要求 location = "westeurope"
1 2 3 4 5 6 7 8 9 variable "location" { description = "The name of the Azure location" default = "westeurope" type = string validation { condition = contains(["westeurope", "westus"], var.location) error_message = "The location must be westeurope or westus." } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 variable "nsg_rules" { description = "List of NSG rules" type = list(object({ name = string priority = number direction = string access = string protocol = string source_port_range = string destination_port_range = string source_address_prefix = string destination_address_prefix = string })) }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 nsg_rules = [ { name = "rule1" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "80" source_address_prefix = "*" destination_address_prefix = "*" }, { name = "rule" priority = 110 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" destination_address_prefix = "*" } ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 resource "azurerm_network_security_group" "example" { name = "acceptanceTestSecurityGroup1" dynamic "security_rule" { for_each = var.nsg_rules content { name = security_rule.value["name"] priority = security_rule.value["priority"] direction = security_rule.value["direction"] access = security_rule.value["access"] protocol = security_rule.value["protocol"] source_port_range = security_rule.value["source_port_range"] destination_port_range = security_rule.value["destination_port_range"] source_address_prefix = security_rule.value["source_address_prefix"] destination_address_prefix = security_rule.value["destination_address_prefix"] } } }
1 2 3 4 5 6 7 # 1.count # 2.dynamics # 3.filter_array # 4.list_map # 5.map # 6.map_merge
3.3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 resource "aws_instance" "app_server" { count = var.instance_count ami = data.aws_ami.amazon_linux.id instance_type = var.ec2_instance_type key_name = "galendu-key" user_data_base64 = "IyEvYmluL2Jhc2gNCnN1ZG8geXVtIHVwZGF0ZSAteQ0Kc3VkbyB5dW0gaW5zdGFsbCAteSBhbWF6b24tbGludXgtZXh0cmFzDQpzdWRvIHl1bSBpbnN0YWxsIG5naW54IC15DQpzdWRvIHN5c3RlbWN0bCBlbmFibGUgbmdpbngNCnN1ZG8gc3lzdGVtY3RsIHN0YXJ0IG5naW54DQpFT0Y=" tags = var.resource_tags # provisioner "file" { # source = "./conf/nginx.conf" # destination = "/etc/nginx/nginx.conf" # connection { # type = "ssh" # host = self.public_ip # user = "ec2_user" # private_key = file("./.keys/galendu-key.pem") # timeout = "4m" # } # } # provisioner "remote-exec" { # inline = [ # "sudo systemctl restart nginx", # "sudo ls /usr/share/nginx/html/", # ] # } provisioner "local-exec" { command = "ps -ef" } }
https://developer.hashicorp.com/terraform/tutorials/modules
示例代码
1 2 3 4 5 6 7 8 9 10 git clone https://github.com/hashicorp/learn-terraform-modules-create.git cd learn-terraform-modules-createterraform init terraform plan terraform apply aws s3 cp modules/aws-s3-static-website-bucket/www/ s3://$(terraform output -raw website_bucket_name)/ --recursive aws s3 rm s3://$(terraform output -raw website_bucket_name)/ --recursive terraform destroy
配置调试日志 1 2 3 4 5 6 7 8 9 开启详细日志输出(环境变量 TF_LOG) Terraform 使用环境变量 TF_LOG 来控制日志级别。你可以设置不同的日志级别来获得不同程度的调试信息。 日志级别: TRACE:最高级别的日志,提供最详细的信息。 DEBUG:包含调试信息。 INFO:默认的日志级别,提供较少的详细信息。 WARN:仅记录警告信息。 ERROR:仅记录错误信息。
检查语法是否正确terraform validate
检查格式是否正确terraform fmt
查看可视化依赖,生成依赖图terraform graph | dot -Tpng > graph.png
交互式命令行 1 2 3 terraform console > var.my_variable > aws_instance.example
模块调试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 1.在模块中定义输出 output "instance_id" { value = aws_instance.example.id } # 2.在根模块中引用这个输出 module "my_module" { source = "./module" } output "module_instance_id" { value = module.my_module.instance_id } # terraform apply -autoapprove -target="moudle.my_module"
terraform state 调试状态文件terraform state show aws_instance.example
terraform taint 标记资源重新创建terraform taint aws_instance.example
terraform refresh 刷新状态terraform refresh
5.2 alicloud配置 1 2 3 aliyun configure --profile AkProfile
https://github.com/gruntwork-io/terragrunt https://terragrunt.gruntwork.io/
5.3.1 安装 1 2 3 4 5 6 7 8 9 10 11 12 wget https://https://ghp.ci/https://github.com/gruntwork-io/terragrunt/releases/download/v0.68.4/terragrunt_windows_amd64.exe choco install terragrunt brew install terragrunt pkg install terragrunt terragrunt --install-autocomplete
5.3.2 使用
生成依赖图terragrunt graph-dependencies | dot -Tsvg > graph.svg
限制并行数 terragrunt run-all apply --terragrunt-parallelism 4
保存输出terragrunt run-all plan --terragrunt-out-dir /tmp/tfplan
通过输出的文件进行部署terragrunt run-all apply --terragrunt-out-dir /tmp/tfplan
删除输出文件terragrunt run-all plan -destroy --terragrunt-out-dir /tmp/tfplan
输出二进制文件和json文件terragrunt run-all plan --terragrunt-out-dir /tmp/all --terragrunt-json-out-dir /tmp/all
常用命令 1 2 3 4 terragrunt run-all apply terragrunt run-all destroy terragrunt run-all output terragrunt run-all plan
5.3.3 常用函数 1 2 3 basename (get_terragrunt_dir())
6.1 lock锁 terraform force-unlock <ID>
6.2 for_each、appends_on、count不能使用 删除modules中的versions.tf的provider配置