Azure Terraform(四)状态文件存储

时间:2024-01-27 22:56:40

一,引言

  我们都知道在执行部署计划之后,当前目录中就产生了名叫 “” 的 Terraform 的状态文件,该文件中记录了已部署资源的状态。默认情况下,在执行部署计划后,Terraform 的状态文件会存储在本地,但是这样往往就造成一些弊端:

(1)不适用团队之间协助,就好比在数据库中对同一条数据进行操作时,就会引起异常

(2)状态文件中包含一些机密信息,会造成一定的机密泄露

(3)如果不慎将本地的状态文件删除掉的话,已执行部署计划的资源的管理将很难在通过 Terraform 进行管理

所以,Terraform 是支持在远端存储状态文件,也就是在 Azure Storage Account 中存储远端状态文件,Terraform 状态的存储是由一个称之为Backend的组件决定的,local state使用的是local backend。并且其他所有的Backend在使用之前都需要在模板中显式定义并通过 terraform init 来实现加载和配置。

二,正文

1,创建状态文件存储账户

转到Azure Portal 上,点击 “+ Create a resource”,输入 “Storage account“ 进行搜索,并且点击 ”create“

输入以下参数:

Resource group 选择:”Web_Test_TF_RG“

Storage account name:”cnbateterraformstorage“

Location:”(Asia Pacific) East Asia“

Performance:”Standard“

Account kind (账户类型)选择:”BlobStorage“

Replication (复制)选择:”Locally-redundant storage(LRS)“ (本地冗余存储(LRS))

点击 ”Review + create“ 进行创建预校验

校验完成后,点击 ”Create“ 进行创建操作

稍等片刻,等待创建完成后,点击 ”go to resource“ 跳转到资源可以查看创建的资源。

选择 “Blog service =》Containers”,点击页面上的 “+ Container” 添加存储状态文件的 Container

Name:"terraform-state"

Public access level:“Private(no anonymous access)”

点击 “Create” 进行创建。

可以看到刚刚创建容器

复制存储账户的访问密钥,稍后会有用

2,创建 Azure Key Vault(密钥保管库)

回到 Azure Portal 首页,点击 ”+ create a resource“,输入”Key Vault“ 进行搜索,点击 ”Create“ 创建

输入相关参数:

Resource group 选择:”Web_Test_TF_RG“

Key vault name:”cnbate-terraform-kv“

Region:”East Asia“

Pricing tier:”Standard“

点击 ”Review + create“ ,创建预校验。

预校验完成后,点击 ”Create“ 进行创建操作

创建完成后,可以点击 ”Go to resource“ 查看创建好的资源

选择 “Settings=》Secrets”,点击 “+ Generate/Import” 创建、或者导入机密信息

Upload options:“Manual”(手动)

Name:“terraform-stste-storage-key”

Value:复制粘贴刚刚的存储账户访问密钥

创建成功,并且可以查看到刚刚创建的机密信息

3,配置 Terraform 后端,并且测试远程 tf 状态

Terraform 需要配置后端,需要以下参数

(1)storage_account_name :Azure 存储账户名称

terraform init -backend-config="access_key=$(az keyvault secret show --name terraform-stste-storage-key --vault-name cnbate-terraform-kv --query value -o tsv)"

(2)container_name:容器名称

(3)key:存储状态文件的名称

(4)access_key:存储账户访问密钥

大家需要注意的是,我这里将 “access_key” 也就是存储账户访问密钥存放在 Azure Key Vault 中了,想要获取 “access_key” 就得通过 Azure Key Vault 获取。

以下是 Terraform 后端配置

terraform {
  backend "azurerm" {
    storage_account_name = "cnbateterraformstorage"
    container_name       = "terraform-state"
    key                  = "cnbate.terraform.stats"
  }
}

3.1,初始化 Terraform 代码

既然我们没有在 Terraform 后端配置代码块中添加 “access_key” 的信息,那么我们就得在初始化的时候对 ”access_key“ 信息赋值

terraform init -backend-config="access_key=$(az keyvault secret show --name terraform-stste-storage-key --vault-name cnbate-terraform-kv --query value -o tsv)"

然后,我们可以看到执行初始化命令之后的日志输出

同时会在存储账户的容器中生成 Blob 块

并且可以看到当前blob 块的详细信息

LEASE STATUS:解锁状态

LEASE STATE:可用状态

3.2,生成执行计划

terraform plan

以下是执行后输入的日志信息

从中不难看到,在生成执行计划之前,先获取状态锁。(注意,生成执行计划。不会将该执行计划持久化到远程状态存储)

PS D:\Core\Terraform\Azure\terraform_cnbate_traffic manager> terraform plan
Acquiring state lock. This may take a few moments...
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.azurerm_resource_group.cnbate_resource_group: Refreshing state...

------------------------------------------------------------------------

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_app_service.cnbate_app_service01 will be created
  + resource "azurerm_app_service" "cnbate_app_service01" {
      + app_service_plan_id               = (known after apply)
      + app_settings                      = {
          + "ASPNETCORE_ENVIRONMENT" = "Production"
        }
      + client_affinity_enabled           = false
      + client_cert_enabled               = false
      + custom_domain_verification_id     = (known after apply)
      + default_site_hostname             = (known after apply)
      + enabled                           = true
      + https_only                        = false
      + id                                = (known after apply)
      + location                          = "eastasia"
      + name                              = "CnBateBlogWeb01"
      + outbound_ip_address_list          = (known after apply)
      + outbound_ip_addresses             = (known after apply)
      + possible_outbound_ip_address_list = (known after apply)
      + possible_outbound_ip_addresses    = (known after apply)
      + resource_group_name               = "Web_Test_TF_RG"
      + site_credential                   = (known after apply)

      + auth_settings {
          + additional_login_params        = (known after apply)
          + allowed_external_redirect_urls = (known after apply)
          + default_provider               = (known after apply)
          + enabled                        = (known after apply)
          + issuer                         = (known after apply)
          + runtime_version                = (known after apply)
          + token_refresh_extension_hours  = (known after apply)
          + token_store_enabled            = (known after apply)
          + unauthenticated_client_action  = (known after apply)

          + active_directory {
              + allowed_audiences = (known after apply)
              + client_id         = (known after apply)
              + client_secret     = (sensitive value)
            }

          + facebook {
              + app_id       = (known after apply)
              + app_secret   = (sensitive value)
              + oauth_scopes = (known after apply)
            }

          + google {
              + client_id     = (known after apply)
              + client_secret = (sensitive value)
              + oauth_scopes  = (known after apply)
            }

          + microsoft {
              + client_id     = (known after apply)
              + client_secret = (sensitive value)
              + oauth_scopes  = (known after apply)
            }

          + twitter {
              + consumer_key    = (known after apply)
              + consumer_secret = (sensitive value)
            }
        }

      + connection_string {
          + name  = (known after apply)
          + type  = (known after apply)
          + value = (sensitive value)
        }

      + identity {
          + identity_ids = (known after apply)
          + principal_id = (known after apply)
          + tenant_id    = (known after apply)
          + type         = (known after apply)
        }

      + logs {
          + detailed_error_messages_enabled = (known after apply)
          + failed_request_tracing_enabled  = (known after apply)

          + application_logs {
              + file_system_level = (known after apply)

              + azure_blob_storage {
                  + level             = (known after apply)
                  + retention_in_days = (known after apply)
                  + sas_url           = (sensitive value)
                }
            }

          + http_logs {
              + azure_blob_storage {
                  + retention_in_days = (known after apply)
                  + sas_url           = (sensitive value)
                }

              + file_system {
                  + retention_in_days = (known after apply)
                  + retention_in_mb   = (known after apply)
                }
            }
        }

      + site_config {
          + always_on                   = (known after apply)
          + app_command_line            = (known after apply)
          + auto_swap_slot_name         = (known after apply)
          + default_documents           = (known after apply)
          + dotnet_framework_version    = (known after apply)
          + ftps_state                  = (known after apply)
          + health_check_path           = (known after apply)
          + http2_enabled               = (known after apply)
          + ip_restriction              = (known after apply)
          + java_container              = (known after apply)
          + java_container_version      = (known after apply)
          + java_version                = (known after apply)
          + linux_fx_version            = (known after apply)
          + local_mysql_enabled         = (known after apply)
          + managed_pipeline_mode       = (known after apply)
          + min_tls_version             = (known after apply)
          + php_version                 = (known after apply)
          + python_version              = (known after apply)
          + remote_debugging_enabled    = (known after apply)
          + remote_debugging_version    = (known after apply)
          + scm_ip_restriction          = (known after apply)
          + scm_type                    = (known after apply)
          + scm_use_main_ip_restriction = (known after apply)
          + use_32_bit_worker_process   = (known after apply)
          + websockets_enabled          = (known after apply)
          + windows_fx_version          = (known after apply)

          + cors {
              + allowed_origins     = (known after apply)
              + support_credentials = (known after apply)
            }
        }

      + source_control {
          + branch             = (known after apply)
          + manual_integration = (known after apply)
          + repo_url           = (known after apply)
          + rollback_enabled   = (known after apply)
          + use_mercurial      = (known after apply)
        }

      + storage_account {
          + access_key   = (sensitive value)
          + account_name = (known after apply)
          + mount_path   = (known after apply)
          + name         = (known after apply)
          + share_name   = (known after apply)
          + type         = (known after apply)
        }
    }

  # azurerm_app_service.cnbate_app_service02 will be created
  + resource "azurerm_app_service" "cnbate_app_service02" {
      + app_service_plan_id               = (known after apply)
      + app_settings                      = {
          + "ASPNETCORE_ENVIRONMENT" = "Production"
        }
      + client_affinity_enabled           = false
      + client_cert_enabled               = false
      + custom_domain_verification_id     = (known after apply)
      + default_site_hostname             = (known after apply)
      + enabled                           = true
      + https_only                        = false
      + id                                = (known after apply)
      + location                          = "southeastasia"
      + name                              = "CnBateBlogWeb02"
      + outbound_ip_address_list          = (known after apply)
      + outbound_ip_addresses             = (known after apply)
      + possible_outbound_ip_address_list = (known after apply)
      + possible_outbound_ip_addresses    = (known after apply)
      + resource_group_name               = "Web_Test_TF_RG"
      + site_credential                   = (known after apply)

      + auth_settings {
          + additional_login_params        = (known after apply)
          + allowed_external_redirect_urls = (known after apply)
          + default_provider               = (known after apply)
          + enabled                        = (known after apply)
          + issuer                         = (known after apply)
          + runtime_version                = (known after apply)
          + token_refresh_extension_hours  = (known after apply)
          + token_store_enabled            = (known after apply)
          + unauthenticated_client_action  = (known after apply)

          + active_directory {
              + allowed_audiences = (known after apply)
              + client_id         = (known after apply)
              + client_secret     = (sensitive value)
            }

          + facebook {
              + app_id       = (known after apply)
              + app_secret   = (sensitive value)
              + oauth_scopes = (known after apply)
            }

          + google {
              + client_id     = (known after apply)
              + client_secret = (sensitive value)
              + oauth_scopes  = (known after apply)
            }

          + microsoft {
              + client_id     = (known after apply)
              + client_secret = (sensitive value)
              + oauth_scopes  = (known after apply)
            }

          + twitter {
              + consumer_key    = (known after apply)
              + consumer_secret = (sensitive value)
            }
        }

      + connection_string {
          + name  = (known after apply)
          + type  = (known after apply)
          + value = (sensitive value)
        }

      + identity {
          + identity_ids = (known after apply)
          + principal_id = (known after apply)
          + tenant_id    = (known after apply)
          + type         = (known after apply)
        }

      + logs {
          + detailed_error_messages_enabled = (known after apply)
          + failed_request_tracing_enabled  = (known after apply)

          + application_logs {
              + file_system_level = (known after apply)

              + azure_blob_storage {
                  + level             = (known after apply)
                  + retention_in_days = (known after apply)
                  + sas_url           = (sensitive value)
                }
            }

          + http_logs {
              + azure_blob_storage {
                  + retention_in_days = (known after apply)
                  + sas_url           = (sensitive value)
                }

              + file_system {
                  + retention_in_days = (known after apply)
                  + retention_in_mb   = (known after apply)
                }
            }
        }

      + site_config {
          + always_on                   = (known after apply)
          + app_command_line            = (known after apply)
          + auto_swap_slot_name         = (known after apply)
          + default_documents           = (known after apply)
          + dotnet_framework_version    = (known after apply)
          + ftps_state                  = (known after apply)
          + health_check_path           = (known after apply)
          + http2_enabled               = (known after apply)
          + ip_restriction              = (known after apply)
          + java_container              = (known after apply)
          + java_container_version      = (known after apply)
          + java_version                = (known after apply)
          + linux_fx_version            = (known after apply)
          + local_mysql_enabled         = (known after apply)
          + managed_pipeline_mode       = (known after apply)
          + min_tls_version             = (known after apply)
          + php_version                 = (known after apply)
          + python_version              = (known after apply)
          + remote_debugging_enabled    = (known after apply)
          + remote_debugging_version    = (known after apply)
          + scm_ip_restriction          = (known after apply)
          + scm_type                    = (known after apply)
          + scm_use_main_ip_restriction = (known after apply)
          + use_32_bit_worker_process   = (known after apply)
          + websockets_enabled          = (known after apply)
          + windows_fx_version          = (known after apply)

          + cors {
              + allowed_origins     = (known after apply)
              + support_credentials = (known after apply)
            }
        }

      + source_control {
          + branch             = (known after apply)
          + manual_integration = (known after apply)
          + repo_url           = (known after apply)
          + rollback_enabled   = (known after apply)
          + use_mercurial      = (known after apply)
        }

      + storage_account {
          + access_key   = (sensitive value)
          + account_name = (known after apply)
          + mount_path   = (known after apply)
          + name         = (known after apply)
          + share_name   = (known after apply)
          + type         = (known after apply)
        }
    }

  # azurerm_app_service_plan.cnbate_app_service_plan01 will be created
  + resource "azurerm_app_service_plan" "cnbate_app_service_plan01" {
      + id                           = (known after apply)
      + kind                         = "Windows"
      + location                     = "eastasia"
      + maximum_elastic_worker_count = (known after apply)
      + maximum_number_of_workers    = (known after apply)
      + name                         = "cnbate_appserviceplan01"
      + resource_group_name          = "Web_Test_TF_RG"

      + sku {
          + capacity = (known after apply)
          + size     = "S1"
          + tier     = "Standard"
        }
    }

  # azurerm_app_service_plan.cnbate_app_service_plan02 will be created
  + resource "azurerm_app_service_plan" "cnbate_app_service_plan02" {
      + id                           = (known after apply)
      + kind                         = "Windows"
      + location                     = "southeastasia"
      + maximum_elastic_worker_count = (known after apply)
      + maximum_number_of_workers    = (known after apply)
      + name                         = "cnbate_appserviceplan02"
      + resource_group_name          = "Web_Test_TF_RG"

      + sku {
          + capacity = (known after apply)
          + size     = "S1"
          + tier     = "Standard"
        }
    }

  # azurerm_traffic_manager_endpoint.cnbate_traffic_manager_endpoint01 will be created
  + resource "azurerm_traffic_manager_endpoint" "cnbate_traffic_manager_endpoint01" {
      + endpoint_location       = (known after apply)
      + endpoint_monitor_status = (known after apply)
      + endpoint_status         = (known after apply)
      + geo_mappings            = [
          + "CN",
        ]
      + id                      = (known after apply)
      + name                    = "cnbateblogweb_webapp01_performance"
      + priority                = (known after apply)
      + profile_name            = "cnbateblogweb"
      + resource_group_name     = "Web_Test_TF_RG"
      + target                  = (known after apply)
      + target_resource_id      = (known after apply)
      + type                    = "azureEndpoints"
      + weight                  = (known after apply)
    }

  # azurerm_traffic_manager_endpoint.cnbate_traffic_manager_endpoint02 will be created
  + resource "azurerm_traffic_manager_endpoint" "cnbate_traffic_manager_endpoint02" {
      + endpoint_location       = (known after apply)
      + endpoint_monitor_status = (known after apply)
      + endpoint_status         = (known after apply)
      + geo_mappings            = [
          + "SG",
        ]
      + id                      = (known after apply)
      + name                    = "cnbateblogweb_webapp02_performance"
      + priority                = (known after apply)
      + profile_name            = "cnbateblogweb"
      + resource_group_name     = "Web_Test_TF_RG"
      + target                  = (known after apply)
      + target_resource_id      = (known after apply)
      + type                    = "azureEndpoints"
      + weight                  = (known after apply)
    }

  # azurerm_traffic_manager_profile.cnbate_traffic_manager_profile will be created
  + resource "azurerm_traffic_manager_profile" "cnbate_traffic_manager_profile" {
      + fqdn                   = (known after apply)
      + id                     = (known after apply)
      + name                   = "cnbateblogweb"
      + profile_status         = (known after apply)
      + resource_group_name    = "Web_Test_TF_RG"
      + tags                   = {
          + "Environment" = "Production"
        }
      + traffic_routing_method = "Geographic"

      + dns_config {
          + relative_name = "cnbateblogweb"
          + ttl           = 60
        }

      + monitor_config {
          + interval_in_seconds          = 30
          + path                         = "/"
          + port                         = 80
          + protocol                     = "http"
          + timeout_in_seconds           = 10
          + tolerated_number_of_failures = 3
        }
    }

Plan: 7 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

PS D:\Core\Terraform\Azure\terraform_cnbate_traffic manager>

3.3,执行部署计划

terraform apply

以下是正在执行部署计划输入日志

同样,也是先获取状态锁

PS D:\Core\Terraform\Azure\terraform_cnbate_traffic manager> terraform plan
Acquiring state lock. This may take a few moments...
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.azurerm_resource_group.cnbate_resource_group: Refreshing state...

在执行的过程中,我们再次登录Azure Portal 中,查看存储账容器中的 Blob 块的状态

LEASE STATUS:已锁定

LEASE STATE:已租用(其实可以理解为 “不可用”)

等待部署计划执行完毕之后,Blob 块的状态又恢复到 “已解锁,可用”

同时,点击图中的 “Edit” 可以看到由 terraform 管理的各自资源状态信息全部写到了当前 Blob 块中

ok,今天的内容就先到此。重要提醒:大家做完测试后,别忘记执行 terraform destroy (销毁部署计划)

*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。φ(゜▽゜*)♪是✌✌✌✌✌

三,结尾

  将状态文件进行远端存到Azure Storage Account 中,Blob 中存储的数据会在保存前进行加密处理,并且一旦配置远端存储模式后,状态文件永远不会存储在本地,这样更加方面团队之间的协作。并且远端存储带来的好处是实现了与资源定义模板管理的解耦,可以让 Terraform 状态脱离本地磁盘而存储,提升了资源状态的安全性。

参考资料:Terraform 官方azurerm 文档

Terraform_Cnbate_Traffic_Manager github:https://github.com/yunqian44/Terraform_Cnbate_Traffic_Manager

作者:Allen 

版权:转载请在文章明显位置注明作者及出处。如发现错误,欢迎批评指正。