TerraformでALBを構築する
はじめに
こんにちは、中山です。
弊社ブログで何度も取り上げているALBですが、v0.7.1でTerraformにも対応しました。早速使ってみたので、レポートします。CloudFormationでのALB利用方法については以下のエントリを参照してください。
構成図
今回作成する構成は以下のとおりです。
パスパターンとルーティング先ターゲットグループは以下のように設定します。
- 何もマッチしない -> ターゲットグループ1へ
/target/*
にマッチ -> ターゲットグループ2へ
コード
GitHubにコードを上げておきました。ご自由にお使いください。
ALB関連のリソース
ALBを作成するためのコードとその意味を以下に記載します。なおそれぞれの情報は現時点(2016/08/22)の情報であることに留意してください。
リソース | 用途 |
---|---|
aws_alb |
ALBの作成 |
aws_alb_target_group |
ターゲットグループの作成 |
aws_alb_target_group_attachment |
ターゲットグループとインスタンスまたはコンテナとひも付け |
aws_alb_listener |
リスナーの作成(とALBとターゲットグループのひも付け) |
aws_alb_listener_rule |
リスナーのルール作成 |
aws_alb
コードは以下のとおりです。
resource "aws_alb" "alb" { name = "${var.name}" security_groups = ["${aws_security_group.alb.id}"] subnets = ["${aws_subnet.frontend_subnet.*.id}"] internal = false enable_deletion_protection = false access_logs { bucket = "${aws_s3_bucket.alb_log.bucket}" } }
設定内容は以下のとおりです。最新の情報はドキュメントを参照するようにしてください。
設定 | 値 | 必須の有無 |
---|---|---|
name |
ALBの名前。デフォルトでTerraformが自動で生成する。 | No |
internal |
true であればInternal ALBになる。 |
No |
security_groups |
ALBに紐付けるセキュリティグループの配列。 | No |
access_logs |
ALBのアクセスログ。指定可能な設定は下記参照。 | No |
subnets |
ALBに紐付けるサブネットIDの配列。 | Yes |
idle_timeout |
idleタイム。この時間を超過するとコネクションをクローズする。デフォルト60秒。 | No |
enable_deletion_protection |
true であればdeletionポリシーを有効する。 |
No |
tags |
ALBに紐付けるタグ。 | No |
アクセスログで指定可能な設定は以下のとおりです。
設定 | 値 | 必須の有無 |
---|---|---|
bucket |
S3のバケット名 | Yes |
prefix |
S3のキー名 | No |
aws_alb_target_group
コードは以下のとおりです。
resource "aws_alb_target_group" "alb" { count = 2 name = "${var.name}-tg${count.index+1}" port = 80 protocol = "HTTP" vpc_id = "${aws_vpc.vpc.id}" health_check { interval = 30 path = "/index.html" port = 80 protocol = "HTTP" timeout = 5 unhealthy_threshold = 2 matcher = 200 } }
設定内容は以下のとおりです。最新の情報はドキュメントを参照するようにしてください。
設定 | 値 | 必須の有無 |
---|---|---|
name |
ターゲットグループの名前。 | Yes |
port |
ターゲットグループがトラフィックを待ち受けるポート。ヘルスチェックのポートや、個々のインスタンスをターゲットグループに登録する際のデフォルトポートのように扱われる。 | Yes |
protocol |
ターゲットグループがトラフィックを待ち受けるプロトコル。 | Yes |
vpc_id |
ターゲットグループが所属しているVPC ID。 | Yes |
deregistration_delay |
draining から unused へ推移させるまでの時間。この時間経過後ALBは完全にコネクションをクローズする。デフォルト300秒。 |
No |
stickiness |
スティッキーセッションの設定。下記参照。 | No |
health_check |
ヘルスチェックの設定。下記参照。 | No |
スティッキーセッションの設定は以下のとおりです。
設定 | 値 | 必須の有無 |
---|---|---|
type |
スティッキーセッションのタイプ。現在のところ lb_cookie のみサポート。 |
Yes |
cookie_duration |
cookieが利用されるまでの時間。この時間経過後新しくcookieが生成される。デフォルト1日。 | No |
ヘルスチェックの設定は以下のとおりです。
設定 | 値 | 必須の有無 |
---|---|---|
interval |
ヘルスチェックのインターバル時間。デフォルト30秒。 | No |
path |
ヘルスチェック先のパス。デフォルト / 。 |
No |
port |
ヘルスチェックする際のポート。1から65535を指定可能。デフォルトは traffic-port (ターゲットグループに設定したポート番号) 。 |
No |
protocol |
ヘルスチェックする際のプロトコル。デフォルトHTTP。 | No |
timeout |
タイムアウト値。この時間経過後ヘルスチェックに失敗したと判断する。デフォルト5秒。 | No |
healthy_threshold |
ヘルスチェックに成功したと判断するまでの回数。デフォルト5。 | No |
unhealthy_threshold |
ヘルスチェックに失敗したと判断するまでの回数。デフォルト2。 | No |
matcher |
ターゲットから返却した場合、ヘルスチェックに成功したと判断するHTTPレスポンスコード。デフォルト200。カンマ区切り( "200,202" )やレンジ指定( "200-299" )でも可能。 |
No |
aws_alb_target_group_attachment
コードは以下のとおりです。
resource "aws_alb_target_group_attachment" "alb" { count = 2 target_group_arn = "${element(aws_alb_target_group.alb.*.arn, count.index)}" target_id = "${element(aws_spot_instance_request.web.*.spot_instance_id, count.index)}" port = 80 }
設定内容は以下のとおりです。最新の情報はドキュメントを参照するようにしてください。
設定 | 値 | 必須の有無 |
---|---|---|
target_group_arn |
ひも付けるターゲットグループのARN。 | Yes |
target_id |
ターゲットグループにひも付けるインスタンスまたはコンテナのID。 | Yes |
port |
ターゲット(インスタンスまたはコンテナ)が待ち受けるポート番号。 | Yes |
aws_alb_listener
コードは以下のとおりです。
resource "aws_alb_listener" "alb" { load_balancer_arn = "${aws_alb.alb.arn}" port = "443" protocol = "HTTPS" ssl_policy = "ELBSecurityPolicy-2015-05" certificate_arn = "${var.alb_config["certificate_arn"]}" default_action { target_group_arn = "${aws_alb_target_group.alb.0.arn}" type = "forward" } }
設定内容は以下のとおりです。最新の情報はドキュメントを参照するようにしてください。
設定 | 値 | 必須の有無 |
---|---|---|
load_balancer_arn |
ALBのARN。 | Yes |
port |
ALBが待ち受けるポート番号。 | Yes |
protocol |
クライアントからALBへのアクセス時に利用されるプロトコル。HTTPかHTTPSのみ指定可能。デフォルトHTTP。 | No |
ssl_policy |
クライアンとALB間での通信に利用されるSSLポリシー。現在サポートされているのは ELBSecurityPolicy-2015-05 。 |
Yes( protocol がHTTPSの場合) |
certificate_arn |
(AWS上の)SSL証明書のARN。 | Yes( protocol がHTTPSの場合 ) |
default_action |
リスナーのデフォルトアクションの設定。下記参照。 | Yes |
アクションで指定可能な設定は以下のとおりです。
設定 | 値 | 必須の有無 |
---|---|---|
target_group_arn |
ターゲットグループのARN。 このターゲットグループにトラフィックが流れる。 | Yes |
type |
トラフィックの流し方。サポートされているのは forward のみ。 |
Yes |
aws_alb_listener_rule
コードは以下のとおりです。
resource "aws_alb_listener_rule" "tg2" { listener_arn = "${aws_alb_listener.alb.arn}" priority = 100 action { type = "forward" target_group_arn = "${aws_alb_target_group.alb.1.arn}" } condition { field = "path-pattern" values = ["/target/*"] } }
設定内容は以下のとおりです。最新の情報はドキュメントを参照するようにしてください。
設定 | 値 | 必須の有無 |
---|---|---|
listener_arn |
ひも付けるリスナーのARN。 | Yes |
priority |
ルールのプライオリティ。同じプライオリティで複数のルールを設定することはできない。 | Yes |
action |
アクションの設定。下記参照。 | Yes |
condition |
コンディションの設定。下記参照。 | Yes |
アクションの設定は以下のとおりです。
設定 | 値 | 必須の有無 |
---|---|---|
target_group_arn |
ひも付けるターゲットグループのARN。このターゲットグループへトラフィックを流す。 | Yes |
type |
ルーティングの方法。現在サポートされているのは forward のみ。 |
Yes |
コンディションの設定は以下のとおりです。
設定 | 値 | 必須の有無 |
---|---|---|
field |
コンディションの設定。現在サポートされているのは path-pattern のみ。 |
Yes |
values |
path-pattern の設定。 |
Yes |
動作確認
いつものようにTerraformを実行後、作成されたALBに curl
コマンドでアクセスしてみます。index.htmlにホスト名が表示されるようにしています。
$ curl https://<alb-dns-name> -k ip-172-16-100-180 $ curl https://<alb-dns-name>/target/index.html -k ip-172-16-101-87
正常にアクセスされたようです。やりましたね。
続いてS3のアクセスログを見てみます。
$ aws s3 ls s3://alb-demo-alb-log --recursive 2016-08-20 11:07:36 83 AWSLogs/345262022757/ELBAccessLogTestFile 2016-08-20 11:15:12 286 AWSLogs/345262022757/elasticloadbalancing/ap-northeast-1/2016/08/20/************_elasticloadbalancing_ap-northeast-1_app.alb-demo.7e0bdfcfe5063096_20160820T0215Z_52.193.129.155_m7p441u7.log.gz 2016-08-20 11:15:07 1200 AWSLogs/345262022757/elasticloadbalancing/ap-northeast-1/2016/08/20/************_elasticloadbalancing_ap-northeast-1_app.alb-demo.7e0bdfcfe5063096_20160820T0215Z_54.64.132.137_5zfzvcah.log.gz
ログが出力されているようです。中身を見てみます。
https 2016-08-20T02:11:03.935122Z app/alb-demo/7e0bdfcfe5063096 49.239.76.29:28631 172.16.100.180:80 0.001 0.001 0.000 404 404 121 3873 "GET https://<alb-dns-name>:443/target HTTP/1.1" "curl/7.43.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:ap-northeast-1:************:targetgroup/alb-demo-tg1/965b2c1bee015bb4
正常に出力されています。
おまけ
v0.7.1から今回のALBやELBのアクセスログを作成する際に便利なデータソースが追加されました。aws_elb_service_accountです。このデータソースを利用することでバケットのポリシーにELBのアカウントIDを指定可能です。
以下のように使用します。
data "aws_elb_service_account" "alb_log" {} data "aws_iam_policy_document" "alb_log" { statement { actions = [ "s3:PutObject", ] resources = [ "arn:aws:s3:::${var.name}-alb-log/*", ] principals = { type = "AWS" identifiers = [ "${data.aws_elb_service_account.alb_log.id}", ] } } } resource "aws_s3_bucket" "alb_log" { bucket = "${var.name}-alb-log" acl = "private" policy = "${data.aws_iam_policy_document.alb_log.json}" force_destroy = true }
aws_iam_policy_document
で生成されるバケットのポリシーは以下のようになります。今回東京リージョンなので「582318560864」が参照されます。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::582318560864:root" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::alb-demo-alb-log/*" } ] }
まとめ
いかがだったでしょうか。
発表されてから比較的サポートされるまでの期間が短かったなという印象です。やはり、ALBは期待度の高い機能なので、Terraformがサポートするのも早くてよかったです。ただ、使ってみて気付いたのですがまだバグがあるようです。リソースの更新を実施すると、更新が完了したと表示されるのに実際は更新されて無かったりします。また、ターゲットグループにインスタンスをひも付けする際、インスタンスのステータスがランニングになっていないと失敗します。この辺りは今後の改善に期待したいと思います。OSSなんだから自分で直せよという話なのですが、Go力が低すぎて、orz。
本エントリがみなさんの参考になれば幸いです。