我一直在使用Terraform的state environments(soon to be renamed as workspaces)作为CI系统(Gitlab CI)的一部分来为每个分支启动动态环境以便运行测试。
这似乎工作正常,但作为删除分支后terraform env delete [ENVIRONMENT NAME]
的拆除的一部分,我也尝试使用environment
。在本地运行时,这很好,但我的CI系统在Docker中运行,因此在创建环境之间有一个干净的工作空间,然后在构建阶段销毁它。在这种情况下,它似乎看不到Environment "restrict-dev-websites-internally" doesn't exist!
You can create this environment with the "new" option.
。
如果我尝试删除它,我会看到此错误:
terraform env list
terraform env list
也不会显示环境。
我还注意到,尽管在S3中存储了远程状态,但我无法选择它。如果我创建一个名为相同的新环境,则使用远程状态的环境(它不会尝试创建另一组资源)。
除此之外,当我使用CI系统创建的环境时,我注意到有时我选择了$ terraform env list
default
$ cat .terraform/environment
[ENVIRONMENT NAME]
$ terraform env list
default
未显示的环境:
*
请注意所选环境中缺少$ terraform env list
default
* development
mitchellh-test
,并且未列出docs中示例所预期的环境:
#!/bin/sh
set -e
if [ "$#" -ne 2 ]; then
echo "Usage: ./env.sh terraform_target env_name"
echo ""
echo "Example: ./env.sh test test-branch"
fi
TERRAFORM_TARGET_LOCATION=${1}
TERRAFORM_ENV=${2}
REPO_BASE=`git rev-parse --show-toplevel`
TERRAFORM_BASE="${REPO_BASE}"/terraform
. "${TERRAFORM_BASE}"/remote.sh "${TERRAFORM_BASE}"/"${TERRAFORM_TARGET_LOCATION}"
if ! terraform env select ${TERRAFORM_ENV} 2> /dev/null; then
terraform env new ${TERRAFORM_ENV}
fi
我不确定状态环境是如何工作的,因此我可能错过了一个在Docker中工作时导致这种奇怪损坏的技巧。
为了完整性,我使用一些包装器脚本来管理环境:
#!/bin/sh
set -e
if [ "$#" -ne 2 ]; then
echo "Usage: ./env.sh terraform_target env_name"
echo ""
echo "Example: ./env.sh test test-branch"
fi
TERRAFORM_TARGET_LOCATION=${1}
TERRAFORM_ENV=${2}
REPO_BASE=`git rev-parse --show-toplevel`
TERRAFORM_BASE="${REPO_BASE}"/terraform
. "${TERRAFORM_BASE}"/remote.sh "${TERRAFORM_BASE}"/"${TERRAFORM_TARGET_LOCATION}"
if terraform env select ${TERRAFORM_ENV} 2> /dev/null; then
terraform env select default
terraform env delete ${TERRAFORM_ENV}
fi
terraform init
remote.sh脚本运行带有动态状态文件位置的#!/bin/sh
set -e
terraform --version
TERRAFORM_TARGET_LOCATION="${1}"
cd "${TERRAFORM_TARGET_LOCATION}"
REPO_NAME="$(basename "`git config --get remote.origin.url`" .git)"
STATE_BUCKET="<BUCKET_NAME>"
STATE_KEY="$(git rev-parse --show-prefix | cut -d"/" -f2-)"
STATE_FILE="terraform.tfstate"
terraform init -backend-config="bucket=${STATE_BUCKET}" \
-backend-config="key=${STATE_KEY}/${STATE_FILE}"
terraform get -update=true
,具体取决于使用S3作为后端的项目中的项目和路径。
{
"Version" : "2012-10-17",
"Statement": [
{
"Sid" : "1",
"Effect" : "Allow",
"Action" : [ "s3:List*",
"s3:Get*",
"s3:PutObject*" ],
"Resource": [ "arn:aws:s3:::<BUCKET_NAME>",
"arn:aws:s3:::<BUCKET_NAME>/*" ]
},
{
"Sid": "2",
"Effect": "Allow",
"Action": [
"s3:DeleteObject*"
],
"Resource": [
"arn:aws:s3:::<BUCKET_NAME>/env:*"
]
}
]
}
在本地运行时,我拥有非常广泛的权限,包括对所有S3的完全访问权限。我的Gitlab CI实例使用附加到实例配置文件的以下IAM特权:
terraform env list
为了清楚起见,我的构建可以很好地查看和使用远程状态的环境但是被迫一遍又一遍地创建环境,然后在销毁状态文件中的所有内容之后无法删除环境,因为它无法选择环境。
我可以在删除它之前始终创建环境,以便我可以在{{1}}中使用它,但重点是我不确定为什么环境不在列表中环境是在另一台机器或另一个容器中创建的。
答案 0 :(得分:1)
你需要国家来破坏环境 从文档中了解他们为什么需要州:
Terraform通常使用配置来确定依赖关系 订购。但是,从Terraform中删除资源时 配置,Terraform必须知道如何删除该资源。 Terraform可以看到存在不存在于您的资源中的映射 配置和计划销毁。但是,由于配置没有 它存在的时间越长,它就不再知道正确的销毁顺序。
如果涉及的实例不多,您也可以尝试to first import it,这可能是可行的。 我建议将running a consul container(或3使其稳定,它们非常小)将状态存储在另一个远程存储中,而不是默认的s3存储。这将确保您的CI环境不会显示在其他人使用的远程存储中。 Consul有一个web gui,可以让你清理那里存储的K / V(如果需要的话)。您也可以使用curl或Ansible通过api与它进行交互 或者,您可以将consul服务器作为您设置的开发环境的一部分,将状态存储在那里并在销毁时从中读取。在这种情况下,你仍然可以保持其他一切清洁。我个人这样做。
如果开发人员在本地计算机上启动环境并且您希望保持远程状态清洁,则应使用本地状态。您还可以将上述解决方案用于开发人员的本地计算机,并在其本地设置中使用consul服务器。对他来说,创造/摧毁是很好的,你会像你说的那样让你保持远程状态清洁。
作为免责声明,我最近才开始使用Terraform,但我不太了解环境的优势。我正在为每个环境使用带子目录的git repo。这样他们就可以真正地相互独立,我可以在本地设置一个开发人员,并在我们的consul集群上使用ACL保护我们的staging / prod。
答案 1 :(得分:0)
您是否在转轮配置中尝试了Volumes选项? https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#the-runners-docker-section 要在构建之间保存terraform状态吗?