2021年の1月に入社した @hidenba です。入社後は開発プロセスの改善をしたりインフラの刷新なんかをしていたら、あれよあれよという間にゴールデンウィークもおわり最近はバイオ村であそんでいます。
みなさんECS使ってますか!! EC2だとSSHでログインできるのにECSを使うと出来ない(というか大変)だったりしてぐぎぎぎぎぎってなったりしてないでしょうか?そんなあなたに朗報です。ECS Execの登場で、より簡単にECSのコンテナに接続してコンテナ内部での作業が可能になっています。
今回は、プライベートなサブネット内にECS Execで接続可能なコンテナ内でnginxを動作させるECSをTerraformで作っていこうと思います。(VPCやALB等のネットワークやロードバランサー周りの設定は割愛します)
Terraformの作成
セキュリティリグループの作成
resource "aws_security_group" "ecs" { name = "ecs" description = "ecs" vpc_id = aws_vpc.this.id egress { from_port = 0 to_port = 0 protocol = -1 cidr_blocks = ["0.0.0.0/0"] } } resource "aws_security_group_rule" "ecs" { security_group_id = aws_security_group.ecs.id type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = [aws_vpc.this.cidr_block] }
TaskExecutionのIAMロールの作成
resource "aws_iam_role" "task_execution" { name = "TaskExecution" assume_role_policy = jsonencode({ "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] }) }
TaskExecutionのIAMロールポリシー作成
resource "aws_iam_role_policy" "ecs" { role = aws_iam_role.task_execution.id policy = jsonencode({ "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams", "ssm:GetParameters", "secretsmanager:GetSecretValue", "kms:Decrypt" ], "Effect": "Allow", "Resource": "*" } ] }) } resource "aws_iam_role_policy_attachment" "task_execution" { role = aws_iam_role.task_execution.name policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" }
ECS Exec用のIAMロールポリシーの作成
ECS ExecはSystemsManagerのセッションマネージャを利用してAWSCLIからコンテナにアクセスするのでSSMのIAMロールポリシーが必要となります
resource "aws_iam_policy" "ecs_exec" { name = "ecs_exec" policy = jsonencode({ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", "ssmmessages:OpenDataChannel" ], "Resource": "*" } ] }) } resource "aws_iam_role_policy_attachment" "ecs_exec" { role = aws_iam_role.task_execution.name policy_arn = aws_iam_policy.ecs_exec.arn }
ロググループの作成
ログ設定をすることでnginxのアクセスログとECS Execで接続時の操作ログを見ることができるようになります
resource "aws_cloudwatch_log_group" "this" { name = "ecs" }
ECSクラスターの作成
resource "aws_ecs_cluster" "this" { name = "ecs" capacity_providers = ["FARGATE"] }
ECSタスク定義の作成
task_role_arn
にIAMロールを設定します
initProcessEnable
を有効にすることで、ゾンビSSMエージェントの子プロセスが全て削除されるようになります(この設定はなくてもECS Execで接続は出来ます)
resource "aws_ecs_task_definition" "this" { family = "taskdef" container_definitions = jsonencode([ { "name": "app", "image": "nginx", "linuxParameters": { "initProcessEnabled": true }, "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "ecs", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "app" } }, "portMappings": [ { "hostPort": 80, "protocol": "tcp", "containerPort": 80 } ] } ]) task_role_arn = aws_iam_role.task_execution.arn execution_role_arn = aws_iam_role.task_execution.arn cpu = "256" memory = "512" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] }
ECSサービスの作成
enable_execute_command
でECS Execを有効化します
resource "aws_ecs_service" "this" { name = "ecs_service" cluster = aws_ecs_cluster.this.id task_definition = aws_ecs_task_definition.this.arn launch_type = "FARGATE" desired_count = 1 enable_execute_command = true load_balancer { target_group_arn = aws_lb_target_group.this.arn container_name = "app" container_port = "80" } network_configuration { subnets = [aws_subnet.private-1a.id, aws_subnet.private-1c.id] security_groups = [aws_security_group.ecs.id] assign_public_ip = false } lifecycle { ignore_changes = [ desired_count, task_definition, load_balancer, ] } }
VPCエンドポイントの設定
プライベートサブネット内のコンテナにはVPCエンドポイントを利用してアクセスすることが出来ます。
resource "aws_vpc_endpoint" "this" { for_each = toset( [ "ec2", "ssm", "ec2messages", "ssmmessages" ] ) vpc_id = aws_vpc.this.id service_name = "com.amazonaws.ap-northeast-1.${each.value}" vpc_endpoint_type = "Interface" subnet_ids = [aws_subnet.private-1a.id, aws_subnet.private-1c.id] security_group_ids = [aws_security_group.vpc_endpoint.id] private_dns_enabled = true }
Terraformの実行
設定は以上になります。Terraformを実行してECSを作成します
コンテナに接続
タスクIDを確認
taskArns
の XXXXXXXXXX の部分がタスクIDになります
$ aws ecs list-tasks --cluster ecs { "taskArns": [ "arn:aws:ecs:ap-northeast-1:ACCOUNT:task/ecs/XXXXXXXXXX" ] }
接続
クラスター ecs
のタスクIDXXXXXXXXXX
のコンテナ app
に接続します
$ aws ecs execute-command \ --cluster ecs \ --task XXXXXXXXXX \ --container app \ --interactive \ --command "/bin/bash"
ログの確認
CludWatchロググループの ecs
にECS Execでアクセスした際のログが出力されています
まとめ
ECS Execを利用するためには
- ECS Exec用のIAMロールをタスク定義のタスクロールに設定する
- ECSサービスでECS Execを有効にする
- プライベートサブネットの場合はVPCエンドポイントを作成する
とっても簡単にECSのコンテナに接続することができるようになります!既存の設定に追加するのも簡単なので是非お試しください!!