使用 Terraform 远程状态/工作空间等可以轻松实现协同工作
我知道现在不是时机,但是我一直在思考,如果我想与其他人一起使用Terraform进行共同工作,应该怎么办呢?因为实际上我还没有深入实践过,所以我认为在这种情况下,有些事情可能不行,请务必指出这些部分…
我在考虑需要做的事情是否可以简要概括如下。
-
- 共享配置文件(.tf 文件集)
-
- 将状态远程化
- 控制多个环境(prod/stage)
共享配置文件(.tf 文件集)
如果不做这个,即使state存在于远程,也会发生以下这样的情况,无法进行协作。
リソース1, リソース2 が書かれているtfファイルをAさんとBさんが共有
Aさんが、tfファイルに リソース3 を足して terraform apply
remote stateには、 リソース1〜3 が記録されている状態
Bさんが、terraform apply 。この時のリソースファイルには リソース1 , リソース2 しか書かれていないので、リソース3 がDestroy
用Git进行共享怎么样?
我在git中管理tf文件群是否可以呢?
在进行任务之前一定要执行git pull,在任务完成后一定要执行git push。
也许把这个过程包装成脚本化会更好吧。
换句话说,我认为可以在本地只进行到计划的操作确认,然后只从持续集成(CI)进行实际的应用操作。
另外,我已在结尾处考虑了是否应该统一管理 .terraform 目录。
将状态远程化
这次我先试试在Consul上创建一个试验环境。
Consul的安装
由于个人没有钱支付给S3,所以我会使用consule。consul的安装完全可以。
公式 からバイナリを持ってきてパスを通す
consul agent -dev -ui くらいでagent起動しておく
只需要那个就可以。
创建 terraform.tf
在terraform.tf等文件中创建Terraform自身的定义块,并在其中设置后端配置。实际上可能需要更详细的设置,但这次只需要能正常运行就可以了。
terraform.tf 文件的中文释义是 __terraform配置文件__。
terraform {
backend "consul" {
path = "terraform/tfstate"
lock = true
}
}
后端更改的应用
进行后端更改时,需要执行terraform init。
请执行init然后尝试apply。
在这种情况下,输入 “consul kv get terraform/tfstate”,如果显示了state的JSON,那就没问题。
请注意,这个命令用于获取consul的key/value存储中的数据。
详细信息请点击这里。
% consul kv get terraform/tfstate
{
"version": 4,
"terraform_version": "0.12.0",
"serial": 1,
"lineage": "56e7253a-8ff5-a369-c966-45a6f37e2fb2",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "ecl_compute_instance_v2",
"name": "instance_1",
"provider": "provider.ecl",
"instances": [
{
...
锁定 = true 的效果
如果有人在进行 terraform apply 的过程中,另一个人尝试执行 apply 或其他操作来引用相同的 remote state,则会出现以下错误。
% terraform apply
Acquiring state lock. This may take a few moments...
Error: Error locking state: Error acquiring the state lock: Lock Info:
ID: [uuid-1]
Path: terraform/tfstate
Operation: OperationTypeApply
Who: yuzu@[PC名]
Version: 0.12.0
Created: 2019-06-04 00:14:47.01916 +0000 UTC
Info: consul session: [uuid-2]
Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.
在可以锁定的情况下,最好将其保持在打开状态。很可能。
顺便提一下…
这次的配置只是一个临时环境,如果停止agent,状态就会消失,所以请注意。
最好先将状态恢复到正常状态,然后运行terraform init。(状态将会保存到文件中)
(我知道有一种持久化的方法,但我对consul的学习还不够,所以现在只能这样。
而且大多数人都使用s3吧)
停止使用Consul进行状态管理
-
- 後述の terraform.tf のstate定義をコメントアウト
terraform init を実行
stateが一旦 terraform.tfstate に戻る
重新开始使用Consul进行状态管理。
-
- 後述の terraform.tf のstate定義をコメント解除
terraform init を実行
stateがconsulに戻る
控制多个环境(prod/stage)。
使用workspace进行切换好呢,还是使用目录进行分隔好呢?直觉告诉我应该选择后者,而且观察世界的话好像也更多人选择后者派呢。
因此,在本文中,我们故意选择使用workspace(前者)。
工作空间在官方文件中似乎没有专门的章节,所以似乎没有被使用。
工作空间是什么?
工作空间就像一个虚拟环境。
每个工作空间都会管理自己的状态。
我记得是在HashiCorp的调查中看到过,说这个功能没有被广泛使用……是因为什么原因呢。
在中国,可以将以下内容用中文进行本地化:
通过使用“terraform workspace new”命令创建工作区,然后使用“terraform workspace select”命令进行使用。
(如果进行了新建操作,系统会自动进行选取)
顺便提一下,如果你什么都不做的话,默认是在一个名为“default”的工作区里工作的,大家至少都在使用工作区。
此外,目前正在使用的工作空间名称存储在 .terraform/environment 中。我稍微看一下。
% cat .terraform/environment
default%
% terraform workspace new ws1
Created and switched to workspace "ws1"!
You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
% cat .terraform/environment
ws1%
当工作区改变时,有什么是美味的?
您可以单独管理state。
比如说。
-
- 現在resourceとして server1 だけがstage(検証用)環境でもprod(商用用)環境でも動作しているとする
-
- これに server2 を足したい
-
- ということで、 main.tf に server2 を足す(server1 はすでに記載があってstageで動いているので)
-
- とはいえいきなりprod側に実際に変更を適用する(terraform apply)のは怖い
-
- そこで workspace = stage(検証用) でapplyして環境がうまく動くかを確認する
-
- うまく行ったのでworkspace = prod(商用用) に切り替える
- ここで terraform apply して、初めて workspace = prod(商用用)にも server2 が足された
可以创造出类似的流程。
如果工作区增加或减少了,要如何向其他工作者传达这个消息?
因为我们使用了remote state,所以会自动传达。原因是,当创建工作空间时,远程端的状态会增加。实际上,当某个人使用 terraform workspace new 创建工作空间时,另一个人使用 terraform workspace list 就会在列表中看到它。一开始很惊讶。
那个时候的状态是如何被管理的?
每个工作区的state被管理的实体在哪里呢?实际上,它以consul的键/值形式存在。
[terraform.tf指定的路径]-env:ws1
存储在路径 terraform/tfstate 中。(我认为如果使用s3等服务,则路径可能会有所不同)
由于在terraform块中指定了路径 terraform/tfstate,所以该状态文件适用于名为 ws1 的工作区。
terraform/tfstate-env:ws1 可以翻译为 “土壤/状态环境:工作区1”
实际上是存储在这个路径中的。当我们亲眼看到时就是这样的。
% consul kv get terraform/tfstate-env:ws1
{
"version": 4,
"terraform_version": "0.12.0",
"serial": 0,
"lineage": "fc9b977b-c5f5-9b8f-a1df-349e09d9a3f8",
"outputs": {},
"resources": []
}
由于没有与其他工作区状态的干扰,可以独立运行环境并拥有独立的生命周期。
我们可以通过切换工作区来逐步构建环境,并同时控制多个环境。
由于我已经写了关于大概的内容,所以接下来是闲谈。
有关git管理的考虑:关于.terraform文件夹的内容。
虽然我在 .gitignore 中忽略了 .terraform 文件夹,但是关于它的处理可能需要进行一些讨论和考虑。
在 .terraform 中包含了以下内容(可能还有其他我不知道的)。
-
- 环境
-
- terraform.tfstate
- 插件二进制文件
对于这些问题应该由每个团队自行讨论考虑吧。嗯,关于提交插件的部分(上面的3个),好像没有吧。所以我会写关于上面的1和2。
“.terraform/environment” 是指什么?
再次强调一下,这是存储当前使用的工作区名称的文件。
如果将 .terraform/environment 与 git 一起管理,那么最新的工作区名称也将被一起管理。
例如,假设有两个工作区,一个是 stage,一个是 prod,前者是用于临时环境,后者是用于生产环境。
在这种情况下,
-
- 基本的に stage という名前のworkspace以外での作業はしない
terraform workspace select prod して、 terraform apply したあと、そのまま workspace = prod な状態を保持するのは危険。うっかり別作業しちゃったら怖い
如果想考虑类似的情况,可以将 .terraform/environment设为git管理的内容,这样在pull时可以强制将workspace切换至那个环境…等等,也可以实现这种运维操作。
“terraform.tfstate” 是指 Terraform 的状态文件。
后端和Terraform本身的设置似乎存储在后台。
由于含有除了后端以外的项目,所以它似乎并不是为了这个而创建的文件。
然而,即使只指定了”required_version”这样的参数,相应的文件也不会被创建……
嗯,撇开不谈这个,以下是一个文件的内容。
% cat .terraform/terraform.tfstate
{
"version": 3,
"serial": 1,
"lineage": "[uuid]",
"backend": {
"type": "consul",
"config": {
"access_token": "",
"address": "",
"ca_file": "",
"cert_file": "",
"datacenter": "",
"gzip": false,
"http_auth": "",
"key_file": "",
"lock": true,
"path": "terraform/tfstate",
"scheme": ""
},
"hash": 3609260479
},
"modules": [
{
"path": [
"root"
],
"outputs": {},
"resources": {},
"depends_on": []
}
]
当资源增加时,有可能需要添加插件。在那种情况下,考虑到总会执行 terraform init,我觉得管理它的意义可能不大。但即使进行管理,问题本身也似乎没有什么大问题。
稍微离题一下,我想讨论一下Terraform的”terraform refresh”行为。
您可以使用Terraform刷新命令,将最新的资源状态反映到状态文件中。即使状态文件由远程管理,也不会对其行为产生特殊影响。
刷新(refresh)的行为非常简单,只是通过使用read方法来更新存在于状态(state)中的资源集合。它完全在状态(state)的世界中完成,似乎与资源在tf文件上是否存在无关。因为在tf文件中存在的资源当然不会有真实的ID等描述,这是理所当然的。
实际上会执行以下动作。(不算作验证类)
-
- tfファイルに存在し、stateに存在するもの -> refreshされる
-
- tfファイルに存在し、stateに存在しないもの -> refreshされない(というか、refreshしようがないだけ)
-
- tfファイルに存在せず、stateに存在するもの -> refreshされる
- tfファイルに存在せず、stateに存在しないもの -> refreshされない(というか、refreshしようがないだけ)
此外,如果在没有使用Terraform更新资源的情况下,在进行terraform refresh后,如果没有在tf文件中进行任何更改并直接执行terraform apply,将会取消之前的更改。因此,最好就干脆停止操作。
比如说,
-
- OpenStackのInstanceをTerraform経由でflavor=m1.tinyで作成
-
- 作成したInstanceをTerraformを通さずにflavor=m1.smallに変更
terraform refresh を実行 -> stateにおける当該インスタンスのflavor情報がm1.smallに書き換わる
再度 terraform apply を実行
state上はm1.small
tfファイル上はm1.tinyのまま
なので、Terraformは m1.small -> m1.tiny のresizeを行おうとする
会出现这种情况。这也是理所当然的。
总结
根据这样的想法,我试着总结一下共同合作的方式,实际上我认为这只是基本的,我想运用起来可能要通过使用Shell等方式来进行操作,希望有经验的人能够告诉我。
以上就是。