#はじめに
本記事では、AWS CloudFormation管理コンソールを使って、AWS Fargateの基本的な環境を構築する手順を説明しています。(初心者向け)
本記事で掲載しているテンプレートの最新版は、下記に置いてます。
https://github.com/okubo-t/aws-cloudformation
#構成図
#前提条件
下記の記事の構築手順で、VPCを構築していること。
[CloudFormationを使ってVPCを構築する]
(https://qiita.com/okubot55/items/b18a5dd5166f1ec2696c)
作業端末においては、AWS CLIとDockerの環境が構築済みであること。
PJPrefixの値は、同一にすること。
#構築手順
1 Dockerfile を準備します。
echo "FROM nginx:alpine" > Dockerfile
2 AWS ECSの管理コンソールで、リポジトリを作成します。
ここでは、リポジトリ名は、nginx と設定します。
3 作成されるとプッシュコマンドが表示されますので、メモしておきます。
4 AWS 認証情報を設定しておきます。
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXX # アクセスキー
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX # シークレットアクセスキー
export AWS_DEFAULT_REGION=ap-northeast-1 # デフォルトリージョン
5 レジストリに対して Docker クライアントを認証するために使用するログインコマンドを実行します。(手順3 でメモしたコマンドです。)
$(aws ecr get-login --no-include-email --region ap-northeast-1)
6 Docker イメージを構築します。(手順3 でメモしたコマンドです。)
docker build -t nginx .
7 このリポジトリにイメージをプッシュできるように、イメージにタグを付けます。(手順3 でメモしたコマンドです。)
docker tag nginx:latest XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest
8 このリポジトリにこのイメージをプッシュします。(手順3 でメモしたコマンドです。)
docker push XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/nginx:latest
9 AWS CloudFormation管理コンソールから、スタックの作成をクリックします。
パラメータ名 | 用途 | 備考 |
---|---|---|
スタックの名前 | テンプレートから作成するリソース一式の名前 | 例 prd-stack-vpc-20180801 |
PJPrefix | 構築するプロジェクトの環境を識別するために各コンポーネントの先頭に付与する識別子 | 例 qiita-prd |
InternetALBName | TagのNameに設定するALB名 | alb(デフォルト) |
TargetGroupName | TagのNameに設定するターゲットグループ名 | tg(デフォルト) |
ECSClusterName | ECSのクラスター名 | cluster(デフォルト) |
ECSTaskName | ECSのタスク定義名 | task(デフォルト) |
ECSTaskCPUUnit | タスクで使用するCPUのユニットの数 | 256(デフォルト) |
ECSTaskMemory | タスクが使用するメモリの量 | 512(デフォルト) |
ECSContainerName | ECSのコンテナ名 | container(デフォルト) |
ECSImageName | コンテナに使用するイメージ名 | nginx(デフォルト) |
ECSServiceName | ECSのサービス名 | service(デフォルト) |
ECSTaskDesiredCount | クラスターで実行する同時タスクの数 | 1(デフォルト) |
12 後続は、デフォルトのまま次へ次へで、作成します。
13 状況が CREATE COMPLETEになれば、ALBとFargateの環境の構築が完了です。
14 管理コンソールの下部の出力から、構築したALBの情報を確認できます。
ここで、キーがALBDNSNameの値をメモしておきます。
15 EC2の管理コンソールのターゲットグループにアタッチされたコンテナのステータスがhealthyになっていることを確認します。
16 ブラウザから、先ほどメモしたALBDNSNameの値にWebアクセスしてみます。
下記のような画面が表示されれば完了です。
例)
#テンプレート
AWSTemplateFormatVersion: "2010-09-09"
Description:
Fargate for ECS Create
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Project Name Prefix"
Parameters:
- PJPrefix
- Label:
default: "InternetALB Configuration"
Parameters:
- InternetALBName
- TargetGroupName
- Label:
default: "Fargate for ECS Configuration"
Parameters:
- ECSClusterName
- ECSTaskName
- ECSTaskCPUUnit
- ECSTaskMemory
- ECSContainerName
- ECSImageName
- ECSServiceName
- ECSTaskDesiredCount
ParameterLabels:
InternetALBName:
default: "InternetALBName"
TargetGroupName:
default: "TargetGroupName"
ECSClusterName:
default: "ECSClusterName"
ECSTaskName:
default: "ECSTaskName"
ECSTaskCPUUnit:
default: "ECSTaskCPUUnit"
ECSTaskMemory:
default: "ECSTaskMemory"
ECSContainerName:
default: "ECSContainerName"
ECSImageName:
default: "ECSImageName"
ECSServiceName:
default: "ECSServiceName"
ECSTaskDesiredCount:
default: "ECSTaskDesiredCount"
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
PJPrefix:
Type: String
#InternetALB
InternetALBName:
Type: String
Default: "alb"
#TargetGroupName
TargetGroupName:
Type: String
Default: "tg"
#ECSClusterName
ECSClusterName:
Type: String
Default: "cluster"
#ECSTaskName
ECSTaskName:
Type: String
Default: "task"
#ECSTaskCPUUnit
ECSTaskCPUUnit:
AllowedValues: [ 256, 512, 1024, 2048, 4096 ]
Type: String
Default: "256"
#ECSTaskMemory
ECSTaskMemory:
AllowedValues: [ 256, 512, 1024, 2048, 4096 ]
Type: String
Default: "512"
#ECSContainerName
ECSContainerName:
Type: String
Default: "container"
#ECSImageName
ECSImageName:
Type: String
Default: "nginx"
#ECSServiceName
ECSServiceName:
Type: String
Default: "service"
#ECSTaskDesiredCount
ECSTaskDesiredCount:
Type: Number
Default: 1
Resources:
# ------------------------------------------------------------#
# SecurityGroup for ALB
# ------------------------------------------------------------#
ALBSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
GroupName: !Sub "${PJPrefix}-alb-sg"
#ECSContainerName
ECSContainerName:
Type: String
Default: "container"
#ECSImageName
ECSImageName:
Type: String
Default: "nginx"
#ECSImageName
ECSServiceName:
Type: String
Default: "service"
#ECSTaskDesiredCount
ECSTaskDesiredCount:
Type: Number
Default: 1
Resources:
# ------------------------------------------------------------#
# SecurityGroup for ALB
# ------------------------------------------------------------#
ALBSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
GroupName: !Sub "${PJPrefix}-alb-sg"
GroupDescription: "-"
Tags:
- Key: "Name"
Value: !Sub "${PJPrefix}-alb-sg"
# Rule
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: "0.0.0.0/0"
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: "0.0.0.0/0"
# ------------------------------------------------------------#
# SecurityGroup for ECS Service
# ------------------------------------------------------------#
ECSSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
GroupName: !Sub "${PJPrefix}-ecs-sg"
GroupDescription: "-"
Tags:
- Key: "Name"
Value: !Sub "${PJPrefix}-ecs-sg"
# Rule
ECSSecurityGroupIngress:
Type: "AWS::EC2::SecurityGroupIngress"
Properties:
IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !GetAtt [ ALBSecurityGroup, GroupId ]
GroupId: !GetAtt [ ECSSecurityGroup, GroupId ]
# ------------------------------------------------------------#
# Target Group
# ------------------------------------------------------------#
TargetGroup:
Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
Properties:
VpcId: { "Fn::ImportValue": !Sub "${PJPrefix}-vpc" }
Name: !Sub "${PJPrefix}-${TargetGroupName}"
Protocol: HTTP
Port: 80
TargetType: ip
# ------------------------------------------------------------#
# Internet ALB
# ------------------------------------------------------------#
InternetALB:
Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
Properties:
Name: !Sub "${PJPrefix}-${InternetALBName}"
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-${InternetALBName}"
Scheme: "internet-facing"
LoadBalancerAttributes:
- Key: "deletion_protection.enabled"
Value: false
- Key: "idle_timeout.timeout_seconds"
Value: 60
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets:
- { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-a" }
- { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-c" }
ALBListener:
Type: "AWS::ElasticLoadBalancingV2::Listener"
Properties:
DefaultActions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
LoadBalancerArn: !Ref InternetALB
Port: 80
Protocol: HTTP
# ------------------------------------------------------------#
# ECS Cluster
# ------------------------------------------------------------#
ECSCluster:
Type: "AWS::ECS::Cluster"
Properties:
ClusterName: !Sub "${PJPrefix}-${ECSClusterName}"
# ------------------------------------------------------------#
# ECS LogGroup
# ------------------------------------------------------------#
ECSLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: !Sub "/ecs/logs/${PJPrefix}-ecs-group"
# ------------------------------------------------------------#
# ECS TaskDefinition
# ------------------------------------------------------------#
ECSTaskDefinition:
Type: "AWS::ECS::TaskDefinition"
Properties:
Cpu: !Ref ECSTaskCPUUnit
ExecutionRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole"
Family: !Sub "${PJPrefix}-${ECSTaskName}"
Memory: !Ref ECSTaskMemory
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
#ContainerDefinitions
ContainerDefinitions:
- Name: !Sub "${PJPrefix}-${ECSContainerName}"
Image: !Ref ECSImageName
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ECSLogGroup
awslogs-region: !Ref "AWS::Region"
awslogs-stream-prefix: !Ref PJPrefix
MemoryReservation: 128
PortMappings:
- HostPort: 80
Protocol: tcp
ContainerPort: 80
# ------------------------------------------------------------#
# ECS Service
# ------------------------------------------------------------#
ECSService:
Type: AWS::ECS::Service
DependsOn: ALBListener
Properties:
Cluster: !Ref ECSCluster
DesiredCount: !Ref ECSTaskDesiredCount
LaunchType: FARGATE
LoadBalancers:
-
TargetGroupArn: !Ref TargetGroup
ContainerPort: 80
ContainerName: !Sub "${PJPrefix}-${ECSContainerName}"
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref ECSSecurityGroup
Subnets:
- { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-a" }
- { "Fn::ImportValue": !Sub "${PJPrefix}-public-subnet-c" }
ServiceName: !Sub "${PJPrefix}-${ECSServiceName}"
TaskDefinition: !Ref ECSTaskDefinition
# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#
Outputs:
#InternetALB
ALBDNSName:
Value: !GetAtt InternetALB.DNSName
Export:
Name: !Sub "${PJPrefix}-${InternetALBName}-dnsname"
#ECSClusterName
ECSClusterName:
Value: !Sub "${PJPrefix}-${ECSClusterName}"
Export:
Name: !Sub "${PJPrefix}-${ECSClusterName}-name"
#ECSClusterARN
ECSClusterARN:
Value: !GetAtt ECSCluster.Arn
Export:
Name: !Sub "${PJPrefix}-${ECSClusterName}-arn"
#ECSLogGroup
ECSLogGroupName:
Value: !Sub "/ecs/logs/${PJPrefix}-ecs-group"
Export:
Name: !Sub "${PJPrefix}-ecs-group-name"
ECSLogGroupARN:
Value: !GetAtt ECSLogGroup.Arn
Export:
Name: !Sub "${PJPrefix}-ecs-group-arn"
#ECSTaskDefinitionName
ECSTaskDefinitionName:
Value: !Sub "${PJPrefix}-${ECSTaskName}"
Export:
Name: !Sub "${PJPrefix}-${ECSTaskName}-name"
#ECSTaskDefinition
ECSTaskDefinitionARN:
Value: !Ref ECSTaskDefinition
Export:
Name: !Sub "${PJPrefix}-${ECSTaskName}-arn"
#ECSTaskCPUUnit
ECSTaskCPUUnit:
Value: !Ref ECSTaskCPUUnit
Export:
Name: !Sub "${PJPrefix}-${ECSTaskName}-cpuunit"
#ECSTaskMemory
ECSTaskMemory:
Value: !Ref ECSTaskMemory
Export:
Name: !Sub "${PJPrefix}-${ECSTaskName}-memory"
#ECSContainer
ECSContainerName:
Value: !Sub "${PJPrefix}-${ECSContainerName}"
Export:
Name: !Sub "${PJPrefix}-${ECSContainerName}-name"
#ECSImage
ECSImageName:
Value: !Ref ECSImageName
Export:
Name: !Sub "${ECSImageName}-name"
#ECSServiceName
ECSService:
Value: !Sub "${PJPrefix}-${ECSServiceName}"
Export:
Name: !Sub "${PJPrefix}-${ECSServiceName}-name"
#ECSServiceARN
ECSServiceARN:
Value: !Ref ECSService
Export:
Name: !Sub "${PJPrefix}-${ECSServiceName}-arn"
#ECSTaskDesiredCount
ECSTaskDesiredCount:
Value: !Ref ECSTaskDesiredCount
Export:
Name: !Sub "${PJPrefix}-${ECSTaskName}-count"