自社でDIY的に作った仕組みが案外好評だったので記事にしてみました。
面倒くさいからとりあえずEIP使う を無くしたいだけだった
開発や検証用途でAWS上にInstanceを立ち上げた時、とりあえずブラウザにIP直打ちしたり、とりあえずSSHもconfig使わずにIP直打ちしてしまう経験ありませんか??
私は壮絶にございました。
- Public IPはInstanceを起動する度に変わるから、とにかくやってられなくてEIP使っちゃう
- EIPは別に1個ならInstance起動中は0円だけど、停止してベッドでぐっすり寝てる時はじわじわ料金キテる。チリツモ
- Public IP変わってもDDNS的にドメインを自動的にアップデートしてくれるような仕組みがあればEIPなんぞ使わなくてもいいんだけど…
一般的な実現方法
前述したようなケースの場合、これまではEC2の「user-data」などを使ってcloud-initやシェルスクリプトでInstanceの作成/起動時にRoute53のレコードをUPSERTするような手法が一般的だったと勝手に解釈しています。
[参考:クラスメソッドさん]
cloud-initを使ってRoute53をPrivate Dynamic DNSにする
http://dev.classmethod.jp/cloud/aws/route53-private-dynamic-dns-use-cloudinit/
Jenkinsを導入したEC2インスタンスに常に同じ名前でアクセスする
http://dev.classmethod.jp/cloud/jenkins-ec2-name-upsert/
上記の例は多くの場合に役立ちますが、1つ問題があります。
リソースが削除された時に、ドメインが削除されないという点です。
スクリプトがInstance内部にある場合はTerminate時にレコードを消す事は容易ではありません。
そこで今回はこれを解決するために、今年の初めにアップデートされた「CloudWatch Events」とみんな大好きLambdaを使ってこの問題を解決したいと思います。
CloudWatch Events とは
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/DeveloperGuide/WhatIsCloudWatchEvents.html
http://aws.typepad.com/aws_japan/2016/01/new-cloudwatch-events-track-and-respond-to-changes-to-your-aws-resources.html
詳細は上記のドキュメントを見てみてください。
何が嬉しいかと言うと、これまでEC2 Instanceのリソース状態の変化をシンプルに検知するにはCloudTrailなどを使うしかなかったのですが、CloudTrailはログが書き出されるまでに結構な時差があり、リアルタイムに検知することはできませんでした。
例. あるEC2のステータスがPendingからrunningに変わったのをトリガーに、すぐに任意の処理を走らせたい
これを見事に解決してくれるのがCloudWatch Eventsです。
EC2 Instanceであれば、
Pending, Running, Stopping, Stopped, Terminated
などの各状態変化をリアルタイムに検知して、
Lambda, SNS, SQS, Kinesis, Built-in traget
などにイベントを流す事ができます。
上記の画像は全てのInstanceを対象として状態が「Terminated」、「Running」になった際に、Lambdaファンクションを発火させる設定例です。設定は、CloudWatch -> Events -> Rules からルールを作成していきます。
Lambdaファンクションには、
{
"id": "ee376907-2647-4179-9203-343cfb3017a4",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "123456789012",
"time": "2015-11-11T13:30:34Z",
"region": "us-east-1",
"resources": [
"arn:aws:ec2:us-east-1:123456789012:instance/i-abcd1111"
],
"detail": {
"instance-id": "i-abcd1111",
"state": "running"
}
}
のようなイベントが渡されるため、あとはLambdaから焼くなり煮るなり好きにすることができます。
今回の主目的は脱EIPでしたが、Route53のプライベートホストゾーンにも簡単に応用することができます。
Labmda内での処理
さて、前述までの部分でLambdaにInstanceの状態変化をリアルタイムに伝える事ができるようになったので、後はLambdaで好きにコードを書いて処理するだけです。
観点としては、
- Instanceの作成/起動時にはInstanceのTagsを見て、Nameをドメイン名のprefixとして任意のAレコードをUPSERTで登録する
- Instanceの削除(停止を含めてもよい)時には、その逆にレコードを削除する処理を書く
ただ、注意点としては現状のCloudWatch Eventsのルールではあくまでもリージョン内全てのInstance or 特定のInstanceしか対象にできないので、
上記を参考に実装するとDDNSをする必要の無いInstanceまで不要なレコードが追加されてしまいます。
そこで、個人的にオススメしたいのは、ドメインのprefixとしてInstanceのNameを使うのではなく、
任意のTagを1つルール決めしておいて、Lambdaファンクション実行時に、そのInstanceにDDNS設定用のTagがある/ない を基準に処理を続ける/止める という風にするのが良いと思います。
具体的には、下記のようなイメージです。
この場合、Lambdaからタグ名「Domain」の存在を確かめる事で、レコードの追加の必要有無を判断できます。
その他
いかがだったでしょうか。小ネタ中の小ネタですみません。
自社ではこれらの仕組みを使って、ドメインが必要な場合は構築時にTagを追加するという運用ルールを決めることで自動化を取り入れました。
プライベートホストゾーンにも簡単に応用できるので、
例えばTerraformでの構築時にTagを設定するだけで内部DNSの設定自動化までサクッと出来たりすると思います。