使用Terraform进行实际运营时,遇到了各种问题
首先
我是CYBIRD工程师Advent Calendar 2017年第一天的主讲者@ntrv。
在CYBIRD,我负责运营女性向恋爱游戏的服务器和基础设施的改进。
我是一名刚毕业两年的Golang工程师,希望能够做出一些优秀的东西。
最近因为连续熬夜观看AWS的Re:invent,非常疲倦。
因此,今年我们将继续举办圣诞节倒数活动!
Terraform是什么?
-
- Terraformとはインフラ構築をコード化することのできるツールです。
- CYBIRDではAWSを使用した, 割と最近のタイトルで使用しております。
遇到不便使用的情况
- ここでは実際に運用しているタイトルでTerraformを使用したタイトルで実際に困った事例を紹介していきたいと思います。
- 当在Terraform中手动添加安全组后,希望能修改ELB下的EC2实例(服务中)的实例类型。
使用中遇到困难情况,例一。
我想做的事情
-
- 取り急ぎセキュリティグループを手動で追加し, ALBにattachした。
- 手動で追加したセキュリティグループを後からTerraform管理下におきたい。
已经执行的事情
terraform importを行い, 既存のリソースを.tfstateに取り込むことを考えた。
terraform import module.fuga.aws_security_group.https_hoge sg-1234abcd
その後, terraform planで差分がなくなるまで*.tfに書いていく。
为难的事情
Ideal
-
- 以下のように*.tfに記述できることを望んでいた。
既存のコードと書きっぷりが変わらないようにしたかった。
terraform importを行うことでaws_security_group.https_hogeだけが.tfstateに追加されるものだと考えていた。
resource "aws_security_group" "https_hoge" {
name = "${var.env}-${var.app_name}-HTTPSFromHoge"
description = "Allow HTTPS From Hoge"
vpc_id = "${var.vpc_id}"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [
"8.8.8.8/32",
"8.8.8.4/32",
]
}
egress {
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["0.0.0.0/0"]
}
}
实际情况
-
- 実際には以下のように記述する必要がありました。
セキュリティグループを記述する方法として二通り存在するため。
aws_security_group + aws_security_group_ruleを使用する方法 <- こちらに合わせて書く必要があった。
aws_security_groupにインラインで記述する方法
aws_security_group_ruleに関しては自由な名前を付けることが出来なかった。
今回はaws_security_group.https_hogeの”https_hoge”から連想されてか”aws_security_group_rule.https_hoge-1と名付けられている。
## 現実
resource "aws_security_group" "https_hoge" {
name = "${var.env}-${var.app_name}-HTTPSFromHoge"
description = "Allow HTTPS From HOGE"
vpc_id = "${var.vpc_id}"
}
resource "aws_security_group_rule" "https_hoge" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
security_group_id = "${aws_security_group.hoge.id}"
cidr_blocks = [
"8.8.8.8/32",
"8.8.8.4/32",
]
}
resource "aws_security_group_rule" "https_hoge-1" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
security_group_id = "${aws_security_group.hoge.id}"
cidr_blocks = [
"0.0.0.0/0",
]
}
如何做才是好的
-
- 急ぎの場合以外はTerraform管理下のリソースに直接変更を加えない。
terraform importを極力行わないようにする。
遇到了困难的情况,第二种情况。
想做的事情
如果想要在ELB下的EC2实例中“安全地”更改实例类型,需要进行以下手动操作。
-
- 从ALB上拆除
-
- 检查访问日志,确认已完全分离,并关闭电源
-
- 更改实例类型并启动电源
- 连接到ALB上
如果在Terraform管理下执行这个步骤,可以考虑以下方法。
-
- 手动执行上述步骤后,稍后修正Terraform…①
- 将ELB的attachment不纳入Terraform管辖范围,其他交由Terraform处理…②
为难的事情 (Komatatta koto)
-
- 今まで(Terraform v0.8.5)は①の方法で実施しておりました。
しかしTerraform v0.10.4で同じ方法を実施したところ, リソース再作成のplanが表示されました。。
その後v0.10.7で検証しましたが, 再現しなかった… 今後詳しく調査する予定です。
在Terraform管理下进行操作的方式
-
- そもそもTerraformで管理しているリソースに手を加えること自体危険であったので, ②の方針にしようかと考えております。
Terraform v0.8.8からはインスタンスタイプ変更時にリソース再作成ではなく, 再起動してくれるようになりました。
provider/aws: Allow aws_instances to be resized rather than forcing a new instance (#11998)
如果选择采用方法②,实际的步骤如下所示。
-
- 从ALB中分离
-
- 检查访问日志,确认已完全分离
-
- 使用之前预先更改过的*.tf文件执行terraform apply
- 由于实例类型已更改并重新启动,需要手动将其附加到ALB上。
可以从中汲取的教训。
terraform importを多用すると, コードがカオスなことになってくる。
緊急時以外はterraform管理下のリソースに手動で変更しない。
terraform importで間違えたときに切り戻しできるように, backendのversioningの機能はONにしておく。
運用することを考えて, Terraformを使用する
何でもTerraformに落とし込んでしまうと, 運用時に困るものこともある。
ignore_changesを有効利用する。
Terraformで管理しているリソースに手動で変更を行うことは基本的にしない。
Terraformで保持している状態と実際の状態が乖離していく。
後からTerraform側の修正で対応すると大変なことになる。
想要提出的其他主张
-
- とにかくterraform planは絶対必須!!
TerraformがどのようにAPIを叩くのかを見ることができるため。
あくまでterraformの立てた実行計画なので, apply時に失敗することはありますが..
安全にTerraformを実行できる環境づくりは必要!!
RDS等消えると困るリソースは lifecycle.prevent_destroyでリソース再作成時にエラーとなるようにする。
State Lockingでterraform applyを同時実行されることを防止する。
terraform plan時に生成される.tfplanをterraform applyに渡す。
terraform applyはCircle CIやJenkins上から実行する。
tfenvを使用し, Terraformのバージョンをリポジトリごとに固定する。
将以下文字用中文进行改述,只需提供一个选项:
思考
- Terraformは難しい…(おざなりな感想)
最后
CYBIRD工程师Advent Calendar 2017明天是@masatoshiitoh 的“尝试编写TCP服务器”!他坐在我旁边,据说是公司里最厉害的技术大神之一。非常期待!