📌
NginxをECS-fargateで簡単にデプロイ ~ terraformで実装 ~
前提
Terraformのコードで実装しています。Terraformの解説はしておりません。
NW・ロードバランサー・セキュリティグループについてある程度理解されている方が望ましいです。
簡単なNginxのコンテナをECSで起動する方法を解説します。
なるべく最小限の設定だけで、デプロイできるように意識しています。
AWS構成
ざっくり構成です。非常にシンプルです。
ロードバランサーもNginxサービスもパブリックサブネットに配置しました。(サービスをプライベートサブネットに配置する方法もあり)
Internet
|
|
[Internet Gateway]
|
|
+---------------+---------------+
| | |
[Public Subnet 1a] | [Public Subnet 1c]
10.0.1.0/24 | 10.0.2.0/24
| | |
| [Application Load Balancer] |
| | |
| | |
+---------[ECS Cluster]---------+
|
|
[ECS Service (Nginx)]
|
|
[ECS Task Definition]
All within VPC (10.0.0.0/16)
NWを作成
- VPCを用意
- パブリックサブネットを2つのAZに配置
- インターネットゲートウェイをルートテーブルに設置、パブリックサブネットに設定 = インターネットとの通信を許可
// VPC
resource "aws_vpc" "ecs_navi_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.service_name}-vpc"
}
}
// Subnet
resource "aws_subnet" "ecs_navi_subnet_public_1a" {
vpc_id = aws_vpc.ecs_navi_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
map_public_ip_on_launch = true
tags = {
Name = "${var.service_name}-subnet-public-1a"
}
}
resource "aws_subnet" "ecs_navi_subnet_public_1c" {
vpc_id = aws_vpc.ecs_navi_vpc.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-northeast-1c"
map_public_ip_on_launch = true
tags = {
Name = "${var.service_name}-subnet-public-1c"
}
}
// Internet Gateway
resource "aws_internet_gateway" "ecs_navi_igw" {
vpc_id = aws_vpc.ecs_navi_vpc.id
}
// Route Table
resource "aws_route_table" "ecs_navi_route_table" {
vpc_id = aws_vpc.ecs_navi_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.ecs_navi_igw.id
}
}
// Route Table Association
resource "aws_route_table_association" "ecs_navi_subnet_public_1a_association" {
subnet_id = aws_subnet.ecs_navi_subnet_public_1a.id
route_table_id = aws_route_table.ecs_navi_route_table.id
}
resource "aws_route_table_association" "ecs_navi_subnet_public_1c_association" {
subnet_id = aws_subnet.ecs_navi_subnet_public_1c.id
route_table_id = aws_route_table.ecs_navi_route_table.id
}
セキュリティグループを作成
- ロードバランサーに付与するセキュリティグループ(ecs_navi_sg)とタスクに付与するセキュリティグループ(ecs_navi_backend_sg)を作成
// セキュリティグループ
resource "aws_security_group" "ecs_navi_sg" {
vpc_id = aws_vpc.ecs_navi_vpc.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.service_name}-sg"
}
}
// セキュリティグループ
resource "aws_security_group" "ecs_navi_backend_sg" {
vpc_id = aws_vpc.ecs_navi_vpc.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.ecs_navi_sg.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
ロードバランサーを作成
- ロードバランサー、リスナールール、ターゲットグループを作成
- ターゲットグループの target typeはIPで指定します
// ロードバランサー
resource "aws_lb" "ecs_navi_lb" {
name = "${var.service_name}-lb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.ecs_navi_sg.id]
subnets = [aws_subnet.ecs_navi_subnet_public_1a.id, aws_subnet.ecs_navi_subnet_public_1c.id]
enable_deletion_protection = false
}
resource "aws_lb_target_group" "nginx_tg" {
name = "${var.service_name}-nginx-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.ecs_navi_vpc.id
target_type = "ip" // IPで設定
health_check {
path = "/"
interval = 30
timeout = 5
healthy_threshold = 5
unhealthy_threshold = 2
matcher = "200"
}
}
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.ecs_navi_lb.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.nginx_tg.arn
}
}
// https のリスナー
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.ecs_navi_lb.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = aws_acm_certificate.ecs_navi_cert.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.nginx_tg.arn
}
}
ECSを作成
ECSのリソースを作成していきます。
ECS Serviceでは今まで作成してきたNWとロードバランサー・ターゲットグループなどを反映していきます。
そうすることで、コンテナとして起動するタスク(Nginxコンテナ)へのインターネットからの処理フローを制御します。
// IAM
resource "aws_iam_role" "ecs_navi_ecs_task_execution_role" {
name = "${var.service_name}-ecs-task-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
}
]
})
tags = {
Name = "${var.service_name}-ecs-task-execution-role"
}
}
// ECS Cluster
resource "aws_ecs_cluster" "ecs_navi_cluster" {
name = "${var.service_name}-cluster"
}
// ECS Service
resource "aws_ecs_service" "nginx_service" {
name = "${var.service_name}-nginx-service"
cluster = aws_ecs_cluster.ecs_navi_cluster.id
task_definition = aws_ecs_task_definition.ecs_navi_nginx_task_definition.arn
desired_count = 1
launch_type = "FARGATE"
network_configuration {
subnets = [aws_subnet.ecs_navi_subnet_public_1a.id, aws_subnet.ecs_navi_subnet_public_1c.id]
security_groups = [aws_security_group.ecs_navi_backend_sg.id]
assign_public_ip = true
}
load_balancer {
target_group_arn = aws_lb_target_group.nginx_tg.arn
container_name = "nginx"
container_port = 80
}
}
// nginxのタスク定義
resource "aws_ecs_task_definition" "ecs_navi_nginx_task_definition" {
family = "${var.service_name}-nginx-task"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = 256
memory = 512
// nginxのデフォルトイメージをECRから取得
container_definitions = jsonencode([
{
name = "nginx"
image = "nginx:latest"
portMappings = [
{
containerPort = 80
hostPort = 80
}
]
}
])
execution_role_arn = aws_iam_role.ecs_navi_ecs_task_execution_role.arn
}
確認
コンソールからDNS名を確認してみます。
Amazon Elastic Container Service >> クラスター >> ecs-navi-cluster >> サービス
サービスの「設定とネットワーク」にネットワーク情報が記載されています。
ここからDNS名を取得してブラウザでリクエストしてみてください。
Nginxのデフォルト画面が表示されればOKです。
終わりに
新しいサービスを利用するときには、簡単な状態をまずは作ってそこから色々といじっていくと理解が早まると思います。
不備などあれば、教えて下さい。
Discussion