ecspresso
ecspresso はECSのタスク定義やサービスを管理するためのツール。
Terraform + ecspresso
ECSの構成
ECSを構成するコンポーネントとして以下がある。
- タスク定義
- クラスター
- サービス
- タスク
クラスターがサービスを持ち、サービスがタスクを持つ。
タスクはタスク定義から作成される。
Terraformとecspressoのそれぞれの役割
TerraformとecspressoでECSを構築する場合はTerraformでクラスターを作成する。
ecspressoはタスク定義、サービス、タスクを作成する。
TerraformでECSクラスターと必要なリソースを作成する
本記事ではnginxをコンテナで動かす最小限のECSクラスターを作成する。
初期設定
まずTerraformの初期設定。
今回はtfstateファイルをローカルに保存する。
S3などリモートに保存する場合は適宜backend
を変更する。
terraform {
required_version = ">= 0.12"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
backend "local" {
path = "example.tfstate"
}
}
provider "aws" {
region = "ap-northeast-1"
default_tags {
tags = {
Project = "terraform-ecspresso-sample"
}
}
}
VPCとサブネットの作成
VPCとサブネットを作成する。
CIDRについて今回はこだわりがないので適当に大きめの範囲を指定する。
サブネットは2つのAZに作成する。
resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "terraform-ecspresso-sample"
}
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "terraform-ecspresso-sample"
}
}
resource "aws_subnet" "subnet_a" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-1a"
cidr_block = "10.0.0.0/20"
map_public_ip_on_launch = true
tags = {
Name = "terraform-ecspresso-sample-a"
}
}
resource "aws_subnet" "subnet_c" {
vpc_id = aws_vpc.vpc.id
availability_zone = "ap-northeast-1c"
cidr_block = "10.0.16.0/20"
map_public_ip_on_launch = true
tags = {
Name = "terraform-ecspresso-sample-c"
}
}
resource "aws_route_table" "route_table" {
vpc_id = aws_vpc.vpc.id
}
resource "aws_route" "route" {
route_table_id = aws_route_table.route_table.id
gateway_id = aws_internet_gateway.igw.id
destination_cidr_block = "0.0.0.0/0"
}
resource "aws_route_table_association" "route_table_association_a" {
subnet_id = aws_subnet.subnet_a.id
route_table_id = aws_route_table.route_table.id
}
resource "aws_route_table_association" "route_table_association_c" {
subnet_id = aws_subnet.subnet_c.id
route_table_id = aws_route_table.route_table.id
}
タスク実行ロールの作成
ECSタスク実行ロールを作成する。
今回はCloudWatch Logsへログを出力したい(エラーとなった場合に原因を探りたい)のでCloudWatch Logsへのアクセス権限を付与する。
data "aws_iam_policy_document" "ecs_task_execution" {
statement {
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents"
]
resources = ["*"]
}
}
resource "aws_iam_policy" "ecs_task_execution_policy" {
name = "ecs_task_execution_policy"
policy = data.aws_iam_policy_document.ecs_task_execution.json
}
data "aws_iam_policy_document" "assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
resource "aws_iam_role" "ecs_task_execution_role" {
name = "ecs_task_execution_role"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
resource "aws_iam_role_policy_attachment" "amazon_ecs_task_execution_role_policy" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = aws_iam_policy.ecs_task_execution_policy.arn
}
CloudWatch Logsのロググループの作成
ECSタスクからログを出力するためのCloudWatch Logsのロググループを作成する。
resource "aws_cloudwatch_log_group" "nginx" {
name = "nginx-cluster-log-group"
}
Security Groupの作成
ECSクラスターにセキュリティグループを作成する。
今回は練習のためのnginx
サーバを立ち上げるだけでALBも無く証明書を用意するのも面倒なため80番ポートのみ許可する。
外部へのアクセスはすべて許可しているが必要な場合は適宜制限する。
resource "aws_security_group" "security_group" {
name = "nginx"
description = "nginx"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "terraform-ecspresso-sample"
}
}
resource "aws_security_group_rule" "ingress_http" {
type = "ingress"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.security_group.id
}
resource "aws_security_group_rule" "ingress_https" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.security_group.id
}
resource "aws_security_group_rule" "egress" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.security_group.id
}
ECSクラスターの作成
ECSクラスターを作成する。
クラスターの中身やタスク定義はecspressoで管理するため、ここではクラスターのみとなる。
resource "aws_ecs_cluster" "cluster" {
name = "nginx-cluster"
}
Terraformの実行
Terraformのapplyを実行する。
$ terraform init
$ terraform plan
$ terraform apply
ecspressoでタスク定義、サービス、タスクを作成する
ディレクトリ構成
今回はここまで作った.tf
ファイルの横にecspresso
ディレクトリを作成し、その中にecspresso
の設定ファイルを配置する。
.
├── cloudwatch_logs.tf
├── ecs.tf
├── ecspresso # ecspressoの設定ファイルを配置するディレクトリ
│ ├── ecs-service-def.json # 以降で作成
│ ├── ecs-task-def.json # 以降で作成
│ └── ecspresso.yml # 以降で作成
├── example.tfstate
├── execution_role.tf
├── provider.tf
├── security_group.tf
└── vpc.tf
ecspressoの設定ファイル(ecspresso.yml)
ecspresso.yml
を作成する。
region: ap-northeast-1
cluster: nginx
service: nginx
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: "10m0s"
plugins:
- name: tfstate
config:
path: ../example.tfstate
Terraformで作成したリソースを参照するためにtfstate
プラグインを使用する。
パスはTerraformのbackend
で指定したファイルを指定する。tfstate
プラグインを使用すると.tfstate
ファイルの内容を参照し以下の書式でリソースの値を取得できる。
{{ tfstate `リソース名.プロパティ名` }}
S3などリモートに保存するbackend
設定をしている場合はpath
ではなくurl
で指定する。
タスク定義(ecs-task-def.json)
タスク定義の設定ファイルを作成する。
ファイル名はecspresso.yml
のtask_definition
へ指定した値で作成する。
{
"family": "terraform-ecspresso-sample",
"cpu": "256",
"memory": "512",
"networkMode": "awsvpc",
"requiresCompatibilities": [
"FARGATE"
],
"executionRoleArn": "{{ tfstate `aws_iam_role.ecs_task_execution_role.arn` }}",
"containerDefinitions": [
{
"name": "nginx",
"image": "public.ecr.aws/nginx/nginx:latest",
"essential": true,
"portMappings": [
{
"appProtocol": "",
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-region" : "ap-northeast-1",
"awslogs-group": "{{ tfstate `aws_cloudwatch_log_group.nginx.name` }}",
"awslogs-stream-prefix": "nginx-container-log-stream"
}
}
}
]
}
サービス定義(ecs-service-def.json)
サービス定義の設定ファイルを作成する。
ファイル名はecspresso.yml
のservice_definition
へ指定した値で作成する。
{
"deploymentConfiguration": {
"deploymentCircuitBreaker": {
"enable": true,
"rollback": true
},
"maximumPercent": 200,
"minimumHealthyPercent": 100
},
"deploymentController": {
"type": "ECS"
},
"desiredCount": 1,
"enableECSManagedTags": true,
"enableExecuteCommand": false,
"launchType": "FARGATE",
"networkConfiguration": {
"awsvpcConfiguration": {
"assignPublicIp": "ENABLED",
"securityGroups": [
"{{ tfstate `aws_security_group.security_group.id` }}"
],
"subnets": [
"{{ tfstate `aws_subnet.subnet_a.id` }}",
"{{ tfstate `aws_subnet.subnet_c.id` }}"
]
}
},
"pendingCount": 0,
"platformFamily": "Linux",
"platformVersion": "LATEST",
"propagateTags": "NONE",
"runningCount": 0,
"schedulingStrategy": "REPLICA",
"tags": [
{
"key": "Project",
"value": "terraform-ecspresso-sample"
}
]
}
ecspressoの実行
ecspressoを実行してECSのタスク定義、サービス、タスクを作成する。
$ ecspresso deploy
確認
AWSのコンソールのECSの管理画面からクラスター、サービス、タスクを確認する。
タスクの画面のネットワーキングの欄にパブリックIPが表示されている。
ブラウザでこのIPにアクセスするとnginxのデフォルトページが表示される。
ECS execでコンテナに接続
【Terraform】ecspresso execコマンドでコンテナ内に接続する