如何将 Terraform 输出变量保存到 Github Action 的环境变量中

6
我的项目使用Terraform设置基础设施,使用Github Actions进行CI/CD。运行terraform apply后,我希望将Terraform输出变量的值保存为Github Action环境变量,以供后续工作流程使用。
根据Github Action文档,是使用工作流命令创建或更新环境变量的方式。
这是我的简化版Github Action工作流程:
name: Setup infrastructure
jobs:
  run-terraform:
    name: Apply infrastructure changes
    runs-on: ubuntu-latest
    steps:
      ...
      - run: terraform output vm_ip
      - run: echo TEST=$(terraform output vm_ip) >> $GITHUB_ENV
      - run: echo ${{ env.TEST }}

当在本地运行命令 echo TEST_VAR=$(terraform output vm_ip) 时,输出的确切内容为 TEST="192.168.23.23" ,但从 Github Action CLI 输出时,我得到了非常奇怪的结果:

enter image description here

我已经尝试过使用单引号和双引号。 在某个时候,我改变了策略,并尝试使用 jq。因此,我添加了以下步骤,以将所有Terraform输出导出到JSON文件中,并使用 jq 解析它:

- run: terraform output -json >> /tmp/tf.out.json
- run: jq '.vm_ip.value' /tmp/tf.out.json

但现在它会抛出以下错误:

parse error: Invalid numeric literal at line 1, column 9

虽然生成的JSON格式是完全有效的:

{
  "cc_host": {
    "sensitive": false,
    "type": "string",
    "value": "private.c.db.ondigitalocean.com"
  },
  "cc_port": {
    "sensitive": false,
    "type": "number",
    "value": 1234
  },
  "db_host": {
    "sensitive": false,
    "type": "string",
    "value": "private.b.db.ondigitalocean.com"
  },
  "db_name": {
    "sensitive": false,
    "type": "string",
    "value": "XXX"
  },
  "db_pass": {
    "sensitive": true,
    "type": "string",
    "value": "XXX"
  },
  "db_port": {
    "sensitive": false,
    "type": "number",
    "value": 1234
  },
  "db_user": {
    "sensitive": false,
    "type": "string",
    "value": "XXX"
  },
  "vm_ip": {
    "sensitive": false,
    "type": "string",
    "value": "206.189.15.70"
  }
}

本地环境下,terraform output -json >> /tmp/tf.out.jsonjq '.vm_ip.value' /tmp/tf.out.json 命令可以正常工作。

3个回答

10
经过数小时的搜索,我终于弄清楚了。
看起来 Terraform 的 Github Action 提供了一个名为 terraform_wrapper 的附加参数,如果您计划在命令中使用输出,则需要将其设置为 false。您可以在这里阅读更详细的文章。
否则,它们会自动暴露给步骤的输出,并且可以像这样访问:steps.<step_id>.outputs.<variable>。您可以在这里这里阅读更多相关信息。

4
如果你打算直接在其他地方使用字符串输出值,我建议使用terraform output -raw NAME来访问它,这样它就不会包含引号和转义,这些是Terraform为了人类读者查看Terraform语言语法中的值而包括的,而且只会返回字面量字符串值。 - Martin Atkins
1
你或者其他人有没有使用步骤输出变量的 GitHub 工作流示例?我使用的解决方案以及我在互联网上看到的所有解决方案都指导设置 terraform_wrapper: false 以便能够获取输出变量,但是你的评论暗示可以从步骤输出中获取 terraform 输出,你有没有任何证据证明它有效? - undefined

6
对我而言,有效的做法是使用terraform-bin output代替terraform output
更多信息请看这里

0
这真是个难题!在尝试了上述方法后,我无法让任何东西正常工作,所以我把所有的东西拼凑在一起,最终找到了一种不使用任何扩展的方法。
以下是我的 Terraform 应用:
- name: 'Terraform_Apply'
  id: tfapply
  if: github.ref == 'refs/heads/master'
  uses: hashicorp/terraform-github-actions@master
  with:
    tf_actions_version: 1.4.6
    tf_actions_subcommand: 'apply'
    tf_actions_working_dir: "./Admin/Infrastructure"

steps.tfapply.outputs.login_server 对我来说没有起作用。

我正在使用 tf_actions_version 1.4.6,并且我尝试了 terraform_wrapper: true 和 false。然而,最终起作用的是将 terraform_wrapper 设置为 false,并添加这个中间步骤:

- name: 'Set vars'
  id: vars
  run: |
    printf "login_server=%s\n" $(terraform -chdir="./Admin/Infrastructure" output -raw login_server) >> "$GITHUB_OUTPUT"
    printf "admin_username=%s\n" $(terraform -chdir="./Admin/Infrastructure" output -raw admin_username) >> "$GITHUB_OUTPUT"
    printf "admin_password=%s\n" $(terraform -chdir="./Admin/Infrastructure" output -raw admin_password) >> "$GITHUB_OUTPUT"

我正在使用-chdir,因为我的Dockerfile位于主解决方案的子目录中,如果您不需要格式化任何内容,您也可以在这里使用echo。
然后,变量显示出来时没有引号(感谢-raw),我可以在后续步骤中访问它们。
- name: 'Set Azure Login for ACR'
  uses: azure/docker-login@v1
  with:
    login-server: ${{steps.vars.outputs.login_server}}
    username: ${{steps.vars.outputs.admin_username}}
    password: ${{steps.vars.outputs.admin_password}}

这让我能够使用Terraform创建一个ACR,然后获取这些值,以便我可以将构建镜像直接推送到ACR。
以下是完整的Terraform代码。
resource "azurerm_container_registry" "acr" {
  name                = "devportalacr"
  resource_group_name = azurerm_resource_group.rg.name
  location            = "eastus2"
  sku                 = "Basic"
  admin_enabled       = true

  tags = {
    Environment = "production"
  }
}

output login_server {
    value = azurerm_container_registry.acr.login_server
}

output admin_username {
    value = azurerm_container_registry.acr.admin_username
}

output admin_password {
    sensitive = true
    value = azurerm_container_registry.acr.admin_password
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接