AWSの管理をterraformとroadworkerにした
Ansibleのcloud_moduleで大量に書かれたplaybookをterraformに少しずつ移して、 Route53の管理だけをroadworkerに移してみたのですが、 今のところうまくいっているようなので紹介しておきます。
terraform
HashiCorpのGoで書かれたオーケストレーションツール。
各OS、ディストリビューションに合わせた実行可能ファイルが配布されているのでインストールはとても簡単。 インストール方法で悩むチームでも導入の敷居は低いだろうと思う。というかよろしく入れた。
同種のツールとしてはcloudformationがあるが、terraformはGCPなどにも対応している。
設定ファイルはクラウド側の事情に引っ張られやすいため、EC2の設定をGCPに使うということはもちろんできないが、 管理方法などは共通化できる面もある。
ドキュメントはかなりまとまっていてやりたいことに対して設定の例が乗っていることが多い。 多少学習コストはあるが比較的低いと言える。
設定ファイル
terraformの設定ファイルは *.tf でディレクトリに任意の名前でおいて良い。
terraformの特徴の一つがこの設定ファイルの読み込み方法で、ディレクトリ内のすべての *.tf が読み込まれて評価される。
具体的に言えば、 s3.tf や rds.tf のようにファイルを分割しても 「s3.tf のみ適用する」ということはできない。
触ったことがないと戸惑うポイントになるが、このルールは「ちゃんと設定を書けば、結果的に個別の適用をする必要は無くなる」ためむしろ楽になる。
terraformの設定はHCLで書く。HCLとは「HashiCorp Configration language」である。
まあ名前の通りなので、特に気にせずこういう感じで書くとだけ思えばいいと思う。
YAMLとかJSONとかそういうものではないが nginx の設定などにインスパイアされた、 人にもそこそこ読みやすく機械的にも扱える設定フォーマットを目指していることもあって、 慣れればそれなりに書きやすい、と思う。
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "web" {
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.micro"
tags {
Name = "HelloWorld"
}
}
上記の設定はEC2のインスタンスを立ち上げる設定の例でterraformのマニュアルのもの。
ami や instance_type など AWS 固有の設定があることがわかると思う。
特徴的なのは属性値の参照、 ${data.aws_ami.ubuntu.id} の部分で、
data "aws_ami" "ubuntu" でフィルターして得られたAMIのidを使うという意味になっている。
terraformは設定ファイルに他の設定によって決定する値を埋め込むのが得意なため、 ひとまとまりの構成を比較的簡単に記述することができる。
これは各設定が依存するということでもあるが、記述量が大幅に減らせ変更にも強くなる。
裏返すと、変更が困難な箇所を変更する際に多くの箇所で変更を強いられる場合もあるが、 terraformには実行計画を事前に出力する機能があるため、一応意図しない大幅な構成変更は避けることができるようになっている。
stateファイル
terraformのもう一つの特徴が状態管理で、terraform.tfstate という名前のファイルで実行時に状態を保存するようになっている。
このためterraform以外で(例えばマネジメントコンソール)リモート状態を変更すると手元の状態とリモートの状態が一致しなくなり問題が起こる場合がある。
基本的にterraformは1箇所で実行し terraform.tfstate はたまにバックアップを取っておくのがよさそうだが、
terraform.tfstate にはパスワードなどのセンシティブな情報が含まれることがあるので、gitで管理するのは避けたい。
中身はただのテキストなので、なんとなく手で直すこともできるし、壊れた場合は、importを使ってリモートの状態を tfstate に取り込む方法もある。
terraform import はドキュメントに細かい使い方が乗っているが、あくまでのリモート状態を手元に同期するだけで、
*.tf ファイルを作ることはできないので注意。ただし、適当に作って terraform import した後に差分がないように設定を自分で書くことはできる。
roadworker
わざわざterraformを使っているのにRoute53の管理はterraformを使わないのかという話になるんですが、
前述の通り、terraformには構成ファイル *.tf を生成する機能はない。
これは既存の設定を取り込む必要がある場合に非常に面倒で、DNSのレコードが大量に存在する現場では厳しい。というかまさにこれ。
roadworkerのいいところは、設定ファイルを自動生成する機能がある点で、これだけでも使う価値がある。
生成時にzoneごとにファイルを分けることもできる。まあ、ゾーン内にrrsetが多すぎるとどのみち長くはなるが。
欠点はRubyで書かれているため、Rubyを導入できるだけの現場じゃないと導入が難しいところ。まあ、ここはゴリ押した。
あと、Ruby 2.4対応が完了していないため、Ruby 2.3で動かすのをオススメ。テスト機能で大量に警告が出る。 Rubyユーザとしては最新版で動かないのが少しモニョるが、rbenvとbundlerを使うなら環境は固定できるので、普段使いする分には困らないだろう。
終わりに
まあ当然といえば当然なんですが、用途に合わせて適切なツールは導入した方がいいですね。
学習コストの問題はありますが、ansibleにオーケストレーションを頑張らせるのは却って大変な気はします。
まあ、aws系モジュールのタスクが、boto/boto3を使ってAWS APIをそのまま呼び出していそうなところがplaybookを書くだけで見えてくる時点でお察しな感じはします。
あと、changedとかの判定も今ひとつだし、何より事前に実行計画を見ることができないのは痛いです。terraform plan 相当のことが、ansible-playbook -C では達成できません。
もちろんプロビジョニングについては ansible は強力なツールです。うまく使い分けましょうというお話でした。(これを理解してもらうのがなかなか難しい
もうAWSのマネジメントコンソールからセットアップするの面倒なんでterraformでいいなという感想です
— シリル@ガルパ沼🍊⚓️😈 (@d_cyrill1129) 2018年3月13日
現場からは以上です。