今回の意図
Terraformとコンテナに対する知識が曖昧なためハンズオンを実施してより知識を深める。
参考資料
https://catalog.us-east-1.prod.workshops.aws/workshops/7ffc4ed9-d4b3-44dc-bade-676162b427cd/ja-JP
※この構成をTerraformを使用して作成、操作する
今回の構成図
基本設定
今回は東京リージョン(ap-northeast-1)で実施
terraformでDockerを扱うために(環境準備)
AWS CLI のインストールと設定
Terraform のインストール
Docker のインストール
AWS CLIの設定(設定済みであれば不要)
①インストール
https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
②下記コマンドで基本設定(※リージョンとフォーマットは任意)
$ aws configure
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: ap-northeast-1
Default output format [None]: json
TerraformでECRリポジトリを作成
Terraformを使用してECRリポジトリを作成
→ Terraform 構成ファイル (main.tf) を作成し以下を記述して保存
provider "aws" {
region = "ap-northeast-1"
}
resource "aws_ecr_repository" "my_repository" {
name = "my-ecr-repo"
}
ファイルの保存後に下記を実行してTerraformを実行
terraform init
terraform apply
Dockerイメージをビルド
Dockerfile を作成して Docker イメージをビルド
→内容は参考資料を参照して下記のように
FROM ubuntu:18.04
# Install dependencies
RUN apt-get update && \
apt-get -y install apache2
# Install apache and write hello world message
RUN echo 'Hello World!' > /var/www/html/index.html
# Configure apache
RUN echo '. /etc/apache2/envvars' > /root/run_apache.sh && \
echo 'mkdir -p /var/run/apache2' >> /root/run_apache.sh && \
echo 'mkdir -p /var/lock/apache2' >> /root/run_apache.sh && \
echo '/usr/sbin/apache2 -D FOREGROUND' >> /root/run_apache.sh && \
chmod 755 /root/run_apache.sh
EXPOSE 80
CMD /root/run_apache.sh
この記述内容は以下の画像参照
黄部分 : コンテナイメージを新たに作成する際に、基とするベースイメージを指定。FROM ubuntu:18.04 は、Docker Hub で公開されている Ubuntu イメージをベースイメージとしている。
紫部分 : Web サーバーの動作に必要な設定。Apache HTTP Server のインストール、index.html ファイルの作成、起動のためのスクリプトファイルの作成を行っている。
緑部分 : EXPOSE の指定で、コンテナ実行時にどのポートを公開したいのか指定する。80 を指定しており、HTTP 公開をする点を表現している。
青部分 : コンテナを実行時に動かすシェルスクリプトを指定する。
ファイルをビルド
"Dockerfile"のあるディレクトリに移動して下記コマンドを実施
docker build -t my-apache-image .
これでイメージのビルドに成功出来ていれば次はECRにプッシュする
DockerイメージをECRにプッシュ
#ECRにログイン
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <AWS_ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com
#イメージをタグ付け(正しいリポジトリにプッシュするために必要)
docker tag my-apache-image:latest <AWS_ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr-repo:latest
#タグ付けしたイメージをプッシュ
docker push <AWS_ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr-repo:latest
VPCの作成
こちらもあえてTerraformで作成してみる
※セキュリティグループの設定で自分のIPアドレスを指定しようと考えているため下記コマンドで検索しておく
curl http://checkip.amazonaws.com
設定としては
名前タグ:h4b-ecs
IPv4 CIDR:10.0.0.0/16
AZ:2
パブリックサブネット:2
VPCエンドポイント:S3ゲートウェイ
セキュリティグループ:default
インバウンドルール:HTTP ソース:マイIP
インバウンドルール:HTTP ソース:自分のIP/32
下記を“main.tf"に記述
#AWSを使用することを明示
provider "aws" {
region = "ap-northeast-1"
}
#VPCの作成
resource "aws_vpc" "h4b_vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "h4b-ecs"
}
}
#インターネットゲートウェイの作成
resource "aws_internet_gateway" "h4b_igw" {
vpc_id = aws_vpc.h4b_vpc.id
tags = {
Name = "h4b-ecs-igw"
}
}
#パブリックサブネットの作成
resource "aws_subnet" "h4b_public_subnet_1" {
vpc_id = aws_vpc.h4b_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
map_public_ip_on_launch = true
tags = {
Name = "h4b-public-subnet-1"
}
}
resource "aws_subnet" "h4b_public_subnet_2" {
vpc_id = aws_vpc.h4b_vpc.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-northeast-1c"
map_public_ip_on_launch = true
tags = {
Name = "h4b-public-subnet-2"
}
}
#ルートテーブルとルートの作成
resource "aws_route_table" "h4b_public_rt" {
vpc_id = aws_vpc.h4b_vpc.id
tags = {
Name = "h4b-public-rt"
}
}
resource "aws_route" "h4b_public_route" {
route_table_id = aws_route_table.h4b_public_rt.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.h4b_igw.id
}
resource "aws_route_table_association" "h4b_public_subnet_1_association" {
subnet_id = aws_subnet.h4b_public_subnet_1.id
route_table_id = aws_route_table.h4b_public_rt.id
}
resource "aws_route_table_association" "h4b_public_subnet_2_association" {
subnet_id = aws_subnet.h4b_public_subnet_2.id
route_table_id = aws_route_table.h4b_public_rt.id
}
#S3ゲートウェイエンドポイントの作成
resource "aws_vpc_endpoint" "s3_gateway" {
vpc_id = aws_vpc.h4b_vpc.id
service_name = "com.amazonaws.ap-northeast-1.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = [aws_route_table.h4b_public_rt.id]
tags = {
Name = "h4b-s3-gateway"
}
}
#セキュリティグループの作成
resource "aws_security_group" "h4b_sg" {
vpc_id = aws_vpc.h4b_vpc.id
name = "default"
tags = {
Name = "h4b-sg"
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["<YOUR_IP>/32"] #curl http://checkip.amazonaws.comで検索した自分のIP
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["126.89.51.98/32"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
そしてTerraformを実行
terraform apply
しかし,,,
│ Error: creating Security Group (default): InvalidParameterValue: Cannot use reserved security group name: default
│ status code: 400, request id: 0839fffa-fa43-4923-9425-9c9fa88167ae
│
│ with aws_security_group.h4b_sg,
│ on main.tf line 81, in resource "aws_security_group" "h4b_sg":
│ 81: resource "aws_security_group" "h4b_sg" {
原因はセキュリティグループの名前「default」はAWSで予約されている名前のため使用できないとのことで「h4b-sg」に変更し再度実行。
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
ECSの作成
こちらもTerraformにて
上記で作成したVPCとサブネットを使用するように明記
さらにタスク定義とALB、ターゲットグループも作成
同様に"main.tf"に追記
# ECSクラスターの作成
resource "aws_ecs_cluster" "h4b_ecs_cluster" {
name = "h4b-ecs-cluster"
}
# IAMロールの作成
resource "aws_iam_role" "ecs_task_execution_role" {
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"
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
# ECSタスク定義の作成
resource "aws_ecs_task_definition" "h4b_task" {
family = "apache-helloworld"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
container_definitions = jsonencode([
{
name = "apache-helloworld"
image = "223303915231.dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr-repo"
essential = true
portMappings = [
{
containerPort = 80
hostPort = 80
protocol = "tcp"
}
]
}
])
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
}
# ALBの作成
resource "aws_lb" "h4b_alb" {
name = "h4b-ecs-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.h4b_sg.id]
subnets = [aws_subnet.h4b_public_subnet_1.id, aws_subnet.h4b_public_subnet_2.id]
enable_deletion_protection = false
}
# ALBターゲットグループの作成
resource "aws_lb_target_group" "h4b_target_group" {
name = "h4b-ecs-target-group"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.h4b_vpc.id
target_type = "ip"
health_check {
path = "/"
protocol = "HTTP"
interval = 30
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 2
}
}
# ALBリスナーの作成
resource "aws_lb_listener" "h4b_listener" {
load_balancer_arn = aws_lb.h4b_alb.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.h4b_target_group.arn
}
}
# ECSサービスの作成
resource "aws_ecs_service" "h4b_service" {
name = "h4b-ecs-service"
cluster = aws_ecs_cluster.h4b_ecs_cluster.id
task_definition = aws_ecs_task_definition.h4b_task.arn
desired_count = 2
launch_type = "FARGATE"
network_configuration {
subnets = [aws_subnet.h4b_public_subnet_1.id, aws_subnet.h4b_public_subnet_2.id]
security_groups = [aws_security_group.h4b_sg.id]
assign_public_ip = true
}
load_balancer {
target_group_arn = aws_lb_target_group.h4b_target_group.arn
container_name = "apache-helloworld"
container_port = 80
}
depends_on = [aws_lb_listener.h4b_listener]
}
作成を確認
さらに接続テストを実施(DNS名より)
Hello World!を確認
ECSの運用負担軽減を体験
目的
①コンテナの自動復旧の様子を体験する
②コンテナの数をスケールアウト/インする操作を体験する
自動復旧
VSCODEにて下記コマンドで1秒に1回アクセスした結果を表示実施しておく
url=http://<your alb dns name>/
while true; do TZ=JST-9 date; curl $url; sleep 1s; done
2024年 5月 16日 木曜日 13:46:49 JST
Hello World!
2024年 5月 16日 木曜日 13:46:50 JST
Hello World!
2024年 5月 16日 木曜日 13:46:51 JST
Hello World!
2024年 5月 16日 木曜日 13:46:53 JST
コンテナ上の障害を検知したときに自動的に復旧する様子を確認でき、運用負荷が軽減できることを体験
スケールアウト
また上記タスクのスケールアウトも容易である
下記で選択し更新を押下
タスクが2→3に変更されていることを確認
躓いた点
IAMロール(セキュリティ)の見直し
ロールでは以前このハンズオンを実施していた際にすでにECSのためのロールを付与していたためTerraformで付与するように指定した際にエラーが発生してしまった。
→個人利用のためおろそかにしがちだが、セキュリティ面を考慮しIAMユーザーへのロールの付与はせずグループへの付与で使用する。admin権限はなるべく使用せず、サービスごとに付与し、使用しないものを削除するという点を再認識。。少し面倒ではあるが勉強のため。。)
Terraform、コンテナの知識を取得するために上記を実施したわけであるが、結果的に権限、セキュリティというのは常に付きまとうものだと再認識しさらに理解を深める必要があると感じた。