# Terraform

# Login & Token

我们本地运行 terraform 命令的时候,但是 terraform state 保存在 terraform cloud 上。这就需要我们配置 token 让我们本地的可以访问 terraform cloud 。

# terraform login

# 保存登录凭证到 ${HOME}/.terraform.d/credentials.tfrc.json,这个是全局配置
terraform login

# 推荐配置,也是全局,配置了 `export TF_CLI_CONFIG_FILE=.terraformrc` 就不会找全局的 `${HOME}/.terraformrc`
${HOME}/.terraformrc

# .terraformrc

我们也可以将 token 保存在 .terraformrc 中,terraform 默认会找当前 Home 下的 .terraformrc 文件,既 ${HOME}/.terraformrc

credentials "app.terraform.io" {
token = ""
}

如果有多个 terraform 项目来自不同的 org,我们可以通过配置 TF_CLI_CONFIG_FILE ,让不同的项目读取不同的 token。

创建了 .envrc 文件,其中定义了 terraform 项目 token 从哪里去

export TF_CLI_CONFIG_FILE="$HOME/.terraformrc-mflyyou"

$HOME/.terraformrc-mflyyou 写入 terraform token 信息

credentials "app.terraform.io" {
token = ""
}

# Terraform state

terraform 会存储我们创建的资源和配置的状态,以便于 Terraform 来确定要对哪些资源进行了更改。

这些元数据信息默认会保存在 本地的 terraform.tfstate 中,不过我们也可以将 state 保存在 terraform cloud 上或者别的第三方存储服务上,比如说 s3。

tfstate 状态文件的内容格式是 JSON。

# local state

terraform {
  required_version = ">= 1.1.7"

  backend "local" {
    path = "relative/terraform.tfstate"
  }
}

TIP

我们不会使用 loca state 进行项目开发,一般我们本地 spike 或者研究性可以。

# command

# 从 state 文件中移除这个 resource,不会销毁 infra.
tf state rm docker_container.web
# 从远程拉取 statue 保存到本地的 terraform.tfstate
tf state pull > terraform.tfstate

# terraform import

terraform import 用于导入已经创建好的基础设施,让 terraform 来管理。

例如,我已经创建了一个 docker container 在本地,我想让这个 container 的让 terraform 管理。

我就可以将其导入 terraform 中去。

TIP

terraform import 直接操作的就是 state,如果是 remote 模式,直接就改变了线上 state。

最好在本地实验好之后,在在远程 state 操作。

  • 创建一个 container

    docker run --name hashicorp-learn --detach --publish 8080:80 nginx:latest
    
    # 查看 container 运行
    docker ps --filter="name=hashicorp-learn"
    
  • 拉取远程 state 到本地,我们直接操作这个本地 state,防止修改了线上

    tf state pull > terraform.tfstate
    
  • 修改 terraform backend 为 local

    terraform {
      #   cloud {
      #     organization = "mflyyou"
      #     workspaces {
      #       name = "learn-terraform-import"
      #     }
      #   }
    
      backend "local" {
        path = "terraform.tfstate"
      }
     }
    
  • 先创建少对应的 resource 不用加配置

    provider "docker" {
      # 兼容 colima
      host = "unix:///Users/panqinzhang/.colima/docker.sock"
    }
    resource "docker_container" "web" {}
    
  • 导入 state 到本地的 terraform.tfstate 文件

    terraform import -state=terraform.tfstate docker_container.web $(docker inspect --format="{{.ID}}" hashicorp-learn)
    
  • tf plan 查看执行计划

    tfp -state=terraform.tfstate
    
  • 修改 resource 配置到 tf plan 在期望的变更内

  • 然后切换 remote 模式,用 tf import 把 state 同步到远程去。

  • 然后 tf plan 查看执行计划,然后在预期内,tf apply

# TF_VAR_name

terraform 定义的 variable 可以通过环境变量来传值,优先级低于 auto.tfvars.json 文件。

比如在 terraform 定义了敏感的 secret 。

variable "auth0_client_secret" {
  type      = string
  sensitive = true
}

你可以通过传递环境变量,在运行 tf plan 的时候,terraform 会从环境变量中找到对应的值。

export TF_VAR_auth0_client_secret="xxx"

For more on how to use TF_VAR_name in context, check out the section on Variable Configuration (opens new window).

# Terraform demo code

# shell_script

Terraform shell_script provider (opens new window)

fly-devops/terraform/shell-script (opens new window)

根据传入的 bound_styra_systems 去查询对应的 system_id,然后根据 id 拿到对应的 dir,去创建这个 dir。

bound_styra_systems 取值可以是 a,b,c 中的任意组合。

# Debug terraform

# 查看执行日志

export TF_LOG=1

# 查看执行代码输出

cd ./debug

terraform init
# 进入控制台查看变量,控制台 exit 退出

terraform console -var-file sandbox.auto.tfvars.json
# *.auto.tfvars.json 会自动识别
terraform console

有的时候我们写的 terraform 逻辑比较复杂,想调试的时候,可以使用 terraform console 来读取计算之后的变量值。