EC2インスタンスをECSの特定のクラスタに所属させる
今日は、EC2インスタンスをECSの特定のクラスタのコンテナインスタンスとして登録するために必要なものについてまとめておきます。
EC2インスタンスがECSのコンテナインスタンスになる仕組み
ECSのコンテナインスタンスはecs-agent
が動作していて、ecs-agent
がECS APIを叩いてクラスタに登録したコンテナインスタンスなのですが、実は直接的にEC2インスタンスをECSのコンテナインスタンスとして登録するための設定はありません。
EC2インスタンスがECSのコンテナインスタンスとして動作するための条件を満たしていたら勝手にECSのクラスタにコンテナインスタンスとして登録される、という仕組みで初見は結構分かりにくかったです。。
EC2インスタンスがECSのコンテナインスタンスになるために必要なもの
- ECSに最適化されたAMIの利用
- AWSのアカウントに対する認証情報(どこの組織のECSインスタンスなのかわかる情報)が含まれ、ECSがコンテナインスタンスの登録やイメージの取得などに使うアクセス権限が付与されたIAMロール
- IAMロールをEC2インスタンスにアタッチするためのインスタンスプロファイル
- (EC2起動タイプを選択する場合のみ)SSHログインのためのキーペア
- (強く推奨)コンテナインスタンスを起動するVPC
ecs-agent
がECS APIと通信してコンテナインスタンスを登録するためのアウトバウンドの通信が許可されたセキュリティグループ- コンテナインスタンスを登録するクラスタを決定するためのuserdataで指定する環境変数 ECS_CLUSTERの指定
userdata
に指定がなければデフォルトのクラスタに登録する
それぞれ、Terraformで具体的に指定する様子を確認して今日はおしまいにしようと思います。
必要なものを作成するためのTerraformの設定
ECSに最適化されたAMI
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-optimized_AMI.html などを参考に見繕う。
resource "aws_instance" "ecs_container_instance" { ami = "ami-e4657283" // 管理画面を操作しててでてきたのを使った気がする ...
IAMロール
このへんは昨日のエントリと同じですが。。
// 信頼ポリシーをロールに付与 resource "aws_iam_role" "ec2_instance_role" { name = "ec2_instance_role" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "ec2.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] } EOF }
// アクセス権限ポリシー resource "aws_iam_policy" "ecs_container_instance_policy" { name = "ecs_container_instance_policy" path = "/" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecs:CreateCluster", "ecs:DeregisterContainerInstance", "ecs:DiscoverPollEndpoint", "ecs:Poll", "ecs:RegisterContainerInstance", "ecs:StartTelemetrySession", "ecs:UpdateContainerInstancesState", "ecs:Submit*", "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "*" } ] } EOF }
// 信頼ポリシーが付与されているロールにさらにアクセス権限ポリシーを付与 resource "aws_iam_role_policy_attachment" "ecs_container_instance_policy_attachment" { role = "${aws_iam_role.ec2_instance_role.name}" policy_arn = "${aws_iam_policy.ecs_container_instance_policy.arn}" }
インスタンスプロファイル
// EC2インスタンスにはインスタンスプロファイルを利用してロールをアタッチ resource "aws_iam_instance_profile" "ecs_container_instance_profile" { name = "ecs_container_instance_profile" role = "${aws_iam_role.ec2_instance_role.name}" }
resource "aws_instance" "ecs_container_instance" { ... iam_instance_profile = "${aws_iam_instance_profile.ecs_container_instance_profile.name}" }
キーペア
// public_key_pathで指定したパスに ssh-keygen で作成した公開鍵があるとして resource "aws_key_pair" "auth" { key_name = "${var.key_name}" public_key = "${file(var.public_key_path)}" }
VPC
デフォルト*2のものを利用する場合、Terraformでの設定は不要。
セキュリティグループ
ECSインスタンスとして登録するだけなら、アウトバウンドの通信だけを許可すればよいです。実際はALBやAutoScalingGroupと組み合わせて利用するのでそれらのヘルスチェックや、連携して動く他のサービスからのリクエストを受け付けられるようにする必要がありますが。
resource "aws_security_group" "test_security_group" { name = "test_security_group" egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } }
userdataで指定する環境変数 ECS_CLUSTERの指定
#!/bin/bash echo ECS_CLUSTER=woshidan-test-cluster >> /etc/ecs/ecs.config
こういうスクリプトを
$ cat userdata.sh | openssl enc -e -base64
resource "aws_instance" "ecs_container_instance" { ... user_data = <<EOF IyEvYmluL2Jhc2gKZWNobyBFQ1NfQ0xVU1RFUj13b3NoaWRhbi10ZXN0LWNsdXN0 ZXIgPj4gL2V0Yy9lY3MvZWNzLmNvbmZpZw== EOF
のように指定します。
現場からは以上です。
参考
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/get-set-up-for-amazon-ecs.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/instance_IAM_role.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/launch_container_instance.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-optimized_AMI.html
- https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-agent-config.html
- キーペアの作成について http://kenzo0107.hatenablog.com/entry/2017/03/27/215941