GitLab 管理的 Terraform/OpenTofu 状态
- 版本:Free, Premium, Ultimate
- 提供方式:GitLab.com, GitLab Self-Managed, GitLab Dedicated
跨团队管理基础设施状态文件需要安全性和可靠性。GitLab 管理的 OpenTofu 状态消除了状态管理的典型挑战。 通过最少的配置,您的 OpenTofu 状态成为 GitLab 项目的自然延伸。 这种集成将您的基础设施定义、代码和状态都保存在一个安全的位置。
使用 GitLab 管理的 OpenTofu 状态,您可以:
- 安全地存储状态文件,并自动进行静态加密
- 使用内置版本跟踪变更,识别谁在何时更改了什么
- 使用 GitLab 权限模型控制访问,而不是创建单独的身份验证系统
- 跨团队协作,避免状态文件冲突或损坏
- 与现有的 GitLab CI/CD 管道无缝集成
- 从 CI/CD 作业和本地开发环境远程访问状态
灾难恢复规划
当 OpenTofu 状态文件在磁盘和对象存储中静态存储时,它们会使用从 db_key_base 应用程序设置派生的密钥,通过 Lockbox Ruby gem 进行加密。
要解密状态文件,GitLab 必须可用。
如果 GitLab 离线,并且您使用 GitLab 部署 GitLab 所需的基础设施(如虚拟机、Kubernetes 集群或网络组件),您将无法轻松访问或解密状态文件。
此外,如果 GitLab 提供启动 GitLab 所需的 OpenTofu 模块或其他依赖项,这些将无法访问。为解决此问题,请做出其他安排来托管或备份这些依赖项,或考虑使用没有共享故障点的独立 GitLab 实例。
前提条件
对于 GitLab 自托管版,在使用 GitLab 管理 OpenTofu 状态文件之前:
- 管理员必须 设置 Terraform/OpenTofu 状态存储。
- 您必须为项目启用 Infrastructure 菜单:
- 转到 Settings > General。
- 展开 Visibility, project features, permissions。
- 在 Infrastructure 下,打开开关。
使用 GitLab CI/CD 将 OpenTofu 状态初始化为后端
前提条件:
- 要使用
tofu apply锁定、解锁和写入状态,您必须至少拥有 Maintainer 角色。 - 要使用
tofu plan -lock=false读取状态,您必须至少拥有 Developer 角色。
与其他作业产物一样,OpenTofu 计划数据可以被仓库中拥有 Guest 角色的任何人查看。
默认情况下,OpenTofu 和 GitLab 都不会加密计划文件。如果您的 OpenTofu plan.json 或 plan.cache
文件包含密码、访问令牌或证书等敏感数据,您应该加密计划输出或修改项目可见性设置。您还应该 禁用
公开管道
并将 产物的访问标志设置为 ‘developer’ (access: 'developer')。
此设置确保产物只能被 GitLab 管理员和至少拥有 Developer 角色的项目成员访问。
要将 GitLab CI/CD 配置为后端:
-
在您的 OpenTofu 项目中,在
backend.tf等.tf文件中, 定义 HTTP 后端:terraform { backend "http" { } } -
在项目仓库的根目录中,创建一个
.gitlab-ci.yml文件。使用 OpenTofu CI/CD 组件 来构建您的.gitlab-ci.yml文件。 -
将您的项目推送到 GitLab。此操作会触发一个管道,该管道 运行
gitlab-tofu init、gitlab-tofu validate和gitlab-tofu plan命令。 -
从上一个管道中手动触发
deploy作业。此操作运行gitlab-tofu apply命令,该命令配置定义的基础设施。
上一个命令的输出应该在作业日志中可见。
gitlab-tofu CLI 是 tofu CLI 的包装器。
自定义您的 OpenTofu 环境变量
在定义 CI/CD 作业时,您可以使用 OpenTofu HTTP 配置变量。
要自定义您的 init 并覆盖 OpenTofu 配置,
请使用环境变量而不是 init -backend-config=... 方法。
当您使用 -backend-config 时,配置会:
- 缓存在
plan命令的输出中。 - 通常会传递给
apply命令。
这种配置可能导致问题,例如 无法在 CI 作业中锁定状态文件。
从本地机器访问状态
您可以从本地机器访问 GitLab 管理的 OpenTofu 状态。
在 GitLab 的集群部署中,您不应使用本地存储。 状态可能会在节点间分裂,导致后续的 OpenTofu 执行不一致。请改用远程存储资源。
-
确保 OpenTofu 状态已 为 CI/CD 初始化。
-
复制一个预填充的 OpenTofu
init命令:- 在左侧边栏,选择 Search or go to 并找到您的项目。
- 选择 Operate > Terraform states。
- 在您要使用的环境旁边,选择 Actions ( ) 并选择 Copy Terraform init command。
-
打开终端并在您的本地机器上运行此命令。
迁移到 GitLab 管理的 OpenTofu 状态
OpenTofu 支持在后端更改或重新配置时复制状态。使用这些操作从另一个后端迁移到 GitLab 管理的 OpenTofu 状态。
您应该使用本地终端来运行迁移到 GitLab 管理的 OpenTofu 状态所需的命令。
以下示例演示如何更改状态名称。从不同的状态存储后端迁移到 GitLab 管理的 OpenTofu 状态需要相同的工作流程。
您应该 在本地机器上 运行这些命令。
设置初始后端
PROJECT_ID="<gitlab-project-id>"
TF_USERNAME="<gitlab-username>"
TF_PASSWORD="<gitlab-personal-access-token>"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/old-state-name"
tofu init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5Initializing the backend...
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
re-run this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.更改后端
现在 tofu init 已经创建了一个 .terraform/ 目录,它知道旧状态的位置,
您可以告诉它新位置:
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/new-state-name"
tofu init \
-migrate-state \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5Initializing the backend...
Backend configuration changed!
Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.
Acquiring state lock. This may take a few moments...
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "http" backend to the
newly configured "http" backend. No existing state was found in the newly
configured "http" backend. Do you want to copy this state to the new "http"
backend? Enter "yes" to copy and "no" to start with an empty state.
Enter a value: yes
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.如果您输入 yes,它会将您的状态从旧位置复制到新位置。然后您可以回到在 GitLab CI/CD 中运行它。
将您的 GitLab 后端用作远程数据源
您可以将 GitLab 管理的 OpenTofu 状态后端用作 OpenTofu 数据源。
-
在您的
main.tf或其他相关文件中,声明这些变量。将值留空。variable "example_remote_state_address" { type = string description = "GitLab 远程状态文件地址" } variable "example_username" { type = string description = "用于查询远程状态的 GitLab 用户名" } variable "example_access_token" { type = string description = "用于查询远程状态的 GitLab 访问令牌" } -
要覆盖上一步中的值,创建一个名为
example.auto.tfvars的文件。此文件 不应 在您的项目仓库中进行版本控制。example_remote_state_address = "https://gitlab.com/api/v4/projects/<TARGET-PROJECT-ID>/terraform/state/<TARGET-STATE-NAME>" example_username = "<GitLab 用户名>" example_access_token = "<GitLab 个人访问令牌>" -
在
.tf文件中,使用 OpenTofu 输入变量 定义数据源:data "terraform_remote_state" "example" { backend = "http" config = { address = var.example_remote_state_address username = var.example_username password = var.example_access_token } }- address: 您要用作数据源的远程状态后端的 URL。
例如,
https://gitlab.com/api/v4/projects/<TARGET-PROJECT-ID>/terraform/state/<TARGET-STATE-NAME>。 - username: 用于与数据源身份验证的用户名。如果您使用
个人访问令牌 进行
身份验证,此值是您的 GitLab 用户名。如果您使用 GitLab CI/CD,此值是
'gitlab-ci-token'。 - password: 用于与数据源身份验证的密码。如果您使用个人访问令牌进行
身份验证,此值是令牌值(令牌必须具有 API 范围)。
如果您使用 GitLab CI/CD,此值是
${CI_JOB_TOKEN}CI/CD 变量的内容。
- address: 您要用作数据源的远程状态后端的 URL。
例如,
现在可以使用 data.terraform_remote_state.example.outputs.<OUTPUT-NAME> 在您的 Terraform 资源中引用数据源的输出。
要在目标项目中读取 OpenTofu 状态,您至少需要 Developer 角色。
管理 OpenTofu 状态文件
要查看 OpenTofu 状态文件:
- 在左侧边栏,选择 Search or go to 并找到您的项目。
- 选择 Operate > Terraform states。
存在一个史诗 来跟踪此 UI 的改进。
管理 OpenTofu 状态版本
可以使用 GitLab REST API 管理单个状态版本。
如果您至少拥有 Developer 角色,您可以使用序列号检索状态版本:
curl --header "Private-Token: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/versions/<version-serial>"如果您至少拥有 Maintainer 角色,您可以使用序列号删除状态版本:
curl --header "Private-Token: <your_access_token>" --request DELETE "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>/versions/<version-serial>"删除状态文件
如果您至少拥有 Maintainer 角色,您可以删除状态文件。
- 在左侧边栏,选择 Operate > Terraform states。
- 在 Actions 列中,选择 Actions ( ),然后选择 Remove state file and versions。
使用 API 删除状态文件
您可以使用个人访问令牌向 REST API 发送请求来删除状态文件:
curl --header "Private-Token: <your_access_token>" --request DELETE "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"您也可以使用 CI/CD 作业令牌 和基本身份验证:
curl --user "gitlab-ci-token:$CI_JOB_TOKEN" --request DELETE "https://gitlab.example.com/api/v4/projects/<your_project_id>/terraform/state/<your_state_name>"您也可以使用 GraphQL API。