CloudFormationでFargateに入門するための構成
AWS FargateはサーバーレスでDockerコンテナを実行することができるサービスです。
今回はFargate入門ということで、CloudFormationでFargate上にコンテナを実行する構成をご紹介します。
構築する環境
ECSクラスターを作成し、FargateタイプのECSタスクをパブリックサブネットに関連付けます。
タスクは以下の2種類のイメージを使用して作成します。
- DockerHubで公開されているイメージ
- 自作し、ECRにプッシュしたイメージ
両コンテナでは、Nginxを起動し、パブリックアドレスを付与した上で、HTTPサーバとして動作させます。
環境構築用のCloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置します。
https://github.com/awstut-an-r/awstut-fa/tree/main/018
テンプレートファイルのポイント解説
今回のアーキテクチャを構成するための、各テンプレートファイルのポイントを取り上げます。
ECRリポジトリ
ECRを定義します。
Resources:
Repository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Ref Prefix
Code language: YAML (yaml)
コンテナ2は自作イメージを使用します。
そのため自作イメージを保存するリポジトリを用意します。
特別な設定は行いません。
RegistoryNameプロパティでリポジトリ名を設定するだけです。
ECSクラスターを定義する
ECSクラスター関係のリソースを作成します。
1つ目はクラスターです。
Resources:
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub "${Prefix}-cluster"
Code language: YAML (yaml)
クラスターはサービスやタスクをまとめるグループです。
コンテナが起動する基盤ということになります。
特別な設定は不要です。
ClusterNameプロパティでクラスター名のみ指定します。
タスクを実行するために必要な権限をIAMロールとして定義する
2つ目はIAMロールです。
タスクを実行すること、つまりコンテナを起動すること自体が、デフォルトでは許可されていません。例えばECRからイメージをプルするといったアクションが、タスク実行の内容に含まれています。
そのため専用のIAMロールを用意して、権限を付与する必要があります。
Resources:
FargateTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Code language: YAML (yaml)
AWS管理ポリシーには、タスク実行に関する最低限の権限をまとめた「AmazonECSTaskExecutionRolePolicy」が用意されてあります。
今回はこちらを使用します。
ちなみに同ポリシーで許可されているアクションは以下となります。
- ecr:GetAuthorizationToken
- ecr:BatchCheckLayerAvailability
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- logs:CreateLogStream
- logs:PutLogEvents
ECRに対するイメージやイメージを構成するレイヤーの取得や、CloudWatch Logsに対するデータの書き込みを許可する内容であることがわかります。
タスク定義
タスク定義およびサービスを作成します。
まず2コンテナ用のタスク定義を確認します。
タスク定義はコンテナを実行するパラメータの集合体です。
実行するイメージや、CPU、メモリ等を指定します。
Resources:
TaskDefinition1:
Type: AWS::ECS::TaskDefinition
Properties:
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
NetworkMode: awsvpc
ExecutionRoleArn: !Ref FargateTaskExecutionRole
TaskRoleArn: !Ref TaskRole
ContainerDefinitions:
- Name: !Sub "${Prefix}-task1-container"
Image: nginx:latest
TaskDefinition2:
Type: AWS::ECS::TaskDefinition
Properties:
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
NetworkMode: awsvpc
ExecutionRoleArn: !Ref FargateTaskExecutionRole
TaskRoleArn: !Ref TaskRole
ContainerDefinitions:
- Name: !Sub "${Prefix}-task2-container"
Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${RepositoryName}:latest"
Code language: YAML (yaml)
2つのリソースはほとんど同じです。
両者の違いはコンテナを元となるイメージです。
前者はDocker Hubに公開されている公式のnginxイメージです。
後者は先述のECRリポジトリを指定します。
ContainerDefinitions内のImageプロパティをイメージ名を指定します。
RequiresCompatibilitiesプロパティに「FARGATE」を指定しました。
本リソースで定義したタスクは、Fargateタイプのサービス上で動作させる必要があるということになります。
CpuプロパティおよびMemoryプロパティで、1つのタスクのCPUおよびメモリの割り当てを指定します。
今回は、CPUに512(0.5vCPU)、メモリに1024(1GB)を指定しました。
これ以下の値に設定すると、今回動作させるコンテナでは、正常にタスクが起動しなかったためご注意ください。
NetworkModeプロパティでは、タスクのネットワークモードを指定します。Fargateの場合、「awsvpc」に指定する必要があります。
If you are using the Fargate launch type, the awsvpc network mode is required.
AWS::ECS::TaskDefinition NetworkMode
タスク定義では、2つのIAMロールに関するパタメータがあります。
ExecutionRoleArnプロパティとTaskRoleArnプロパティです。
前者は先述の通りですが、改めて以下に整理します。
- タスク実行IAMロール(ExecutionRoleArn):タスクを実行すること自体に必要な権限。ECRからDockerイメージをPullする権限など。
- タスク用のロール(TaskRoleArn):タスク内で実行するコンテナに割り当てる権限。後述します。
それぞれ用意したIAMロールのARNを指定します。
サービスを用意する
次に2コンテナ用のサービスを定義します。
サービスはタスク数を管理・調整する機能です。
例えばタスクのスケーリング設定は、サービスに対して行います。
Resources:
Service1:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
LaunchType: FARGATE
DesiredCount: 1
TaskDefinition: !Ref TaskDefinition1
ServiceName: !Sub "${Prefix}-service1"
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref ContainerSecurityGroup
Subnets:
- !Ref PublicSubnet1
Service2:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
LaunchType: FARGATE
DesiredCount: 1
TaskDefinition: !Ref TaskDefinition2
ServiceName: !Sub "${Prefix}-service2"
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref ContainerSecurityGroup
Subnets:
- !Ref PublicSubnet2
Code language: YAML (yaml)
Clusterプロパティで、本サービスを起動させるクラスターを指定します。
LaunchTypeプロパティでサービスの起動タイプを指定します。
今回はFargateタイプで起動しますので、「FARGATE」とします。
DesiredCountプロパティでサービス上で起動するタスクの希望数を指定できます。
今回は1つのタスクを起動させるように「1」とします。
仮にタスクが何らかの理由で停止した場合は、新たなタスクが自動的に起動して、希望数を満たすようにサービスが調整を行います。
TaskDefinitionプロパティで実行するタスク定義を指定します。
NetworkConfigurationプロパティ内のAwsvpcConfigurationプロパティで、タスクに割り当てられるセキュリティグループや配置されるサブネットを指定します。
今回は2つのパブリックサブネットを作成しますが、1つずつコンテナを配置するように指定します。
タスクが実行する内容のためのIAMロールを用意する
最後にタスク用のIAMロールを定義します。
Resources:
TaskRole1:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
Action:
- sts:AssumeRole
Code language: YAML (yaml)
中身は空っぽです。
今回作成するコンテナはWebサーバとしてだけ動作させ、特にAWSサービスにアクセスすることがないためです。
Dockerfileなど
自作するイメージ用のファイルを用意します。
Dockerfileです。
FROM nginx:latest
COPY index.html /usr/share/nginx/html
EXPOSE 80
Code language: Dockerfile (dockerfile)
nginxの公式イメージをベースとして、自作のindex.htmlファイルをメインページに配置します.
index.htmlです。
<html>
<head>
</head>
<body>
<h1>fa-018 index.html</h1>
</body>
</html>
Code language: HTML, XML (xml)
シンプルなHTMLファイルです。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
今回は2回に分けてCloudFormationスタックを作成します。
ECRリポジトリを作成する
まずECRリポジトリを作成します。
以下はS3バケットに設置したテンプレートファイルからスタックを作成する例です。
$ aws cloudformation create-stack \
--stack-name fa-018-ecr \
--template-url https:/[bucket-name].s3.[region].amazonaws.com/fa-018-ecr.yaml
Code language: Bash (bash)
次に作成したECRリポジトリにDockerイメージをプッシュします。
必要なコマンドはAWS Management Consoleから確認できます。
上記コマンドを実行した結果は以下の通りです。
正常にイメージがプッシュされていることが確認できます。
残りのCloudFormationスタックを作成する
引き続きCloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- ECSクラスター:fa-018-cluster
- ECSサービス1名:fa-018-service1
- ECSサービス2名:fa-018-service2
作成されたリソースをAWS Management Consoleから確認します。まずクラスターを確認します。
確かにクラスターが作成されていることがわかります。
次にクラスターの詳細を確認します。
クラスター内に2つのサービスが動作していることがわかります。
それぞれのサービス上で動作しているタスクの詳細を確認します。
それぞれのタスクに割り当てられたパブリックアドレスが確認できます。
コンテナへアクセス
準備が整いましたので、実際にブラウザからアクセスします。
正常に各コンテナにアクセスすることができました。
前者はNginxの公式イメージのトップページ、後者は自作イメージのHTMLファイルです。
まとめ
CloudFormationを使用して、FargateタイプのECSコンテナを作成することができました。