Published
- 7 min read
ECSで運用していた社内ツールをFargate化したときに、ハマりやすかった3つのポイント
AWS Fargate Advent Calendar 2017の25日目の記事になります。
他の方が詳細な見解や調査など行われているので、大トリの記事がこれぐらいの内容で大丈夫なのかビビりながら書いています。
ひとまず、年末年始でFargateを試してみようかなあという方の参考になれば。
1.どんな環境をFargate化したか
上記のような構成でECSで運用していた社内ツールのprprをFargate化しました。
prprについては、下記のブログを参照
prprでGithubのPullRequestレビュー依頼をSlack通知する
2017/12時点のFargateの制限としては、
- 東京リージョンがない
SLAがない1- 知見が少ない
ということで、production環境にいきなり入れるというよりは、こうしたサービスレベルの低い社内ツールから移行するのがよいかと思います。
2.ハマったところ
2-1.FargateがECRのコンテナイメージをpullできない
デプロイしたECSのステータスが、延々とSTOPPEDを繰り返して、ECSのログを見ると、下記のようなエラーが出力され続けているときがありました。
残念ながら、Fargate化されても、デプロイ失敗したときなど、ECSが再起動しまくるのは、自前で何とか検知する仕組みを作らないといけなさそう…
解決例:Fargate側にPublicIPを付与する
Fargate: CannotPullContainer located on ECS registryにもあるように、FargateはVPC内部で起動してくるため、VPC外部への通信経路を確保しておかないと、FargateがECRからコンテナイメージをおとしてくることができません。特にセキュリティ上などで問題なければ、AssignPublicIp
を有効化しておきましょう。
Service:
Type: AWS::ECS::Service
Properties:
ServiceName: !Ref RoleName
Cluster: !Ref ECSCluster
DesiredCount: 1
LaunchType: FARGATE
TaskDefinition: !Ref ECSTask
LoadBalancers:
- ContainerName: !Sub ContainerName
ContainerPort: 3000
TargetGroupArn: !Ref ALBTargetGroup
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref ECSSecurityGroup
Subnets: !Ref SubnetIds
2-2.ECSの動的ポートマッピングは使えない
Fargateのデプロイ中は、下記の画像のような感じで、同一ポートでプライベートIPが異なるという状況になる。
Fargateが使用するサブネットでプライベートIPが枯渇したときにどうなるかは未検証。Fargateの起動コンテナ数の制限とかないのであれば、サブネットマスクの設計とかはちょっと注意しておいた方がよさそう。
解決例:ホスト側のポートを固定する
ECSTask:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Ref FamilyName
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: 256
Memory: 512
ExecutionRoleArn: !Sub 'arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole'
ContainerDefinitions:
- Name: !Ref TaskName
Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${RegistoryName}:${ImageTag}'
PortMappings:
- ContainerPort: 3000
HostPort: 3000
Essential: 'true'
Ulimits:
- Name: nofile
SoftLimit: 65535
HardLimit: 65535
Environment:
- Name: PORT
Value: 3000
- Name: RACK_ENV
Value: production
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref CloudWatchLogGroup
awslogs-region: !Sub ${AWS::Region}
awslogs-stream-prefix: !Ref ImageTag
2-3.CodePipelineでFargateのデプロイを行う、CFnの記述方法がわからない
AWS CodePipeline に Amazon ECS および AWS Fargate のサポートを追加 CodePipeline で ECS にデプロイできるようになり、Docker 環境の継続的デリバリも簡単になりました にもあるのですが、12/12に、CodePipeline上でFargateのデプロイがサポートされています。
ただ、上記のようなイメージで、CodePipelineとFargateを連携させようとしたときに、CFnのドキュメントからだとCFnでのサンプルが見つけられませんでした。 ひとまず、下記のように書いたら、CFnでも何とか通ったけど、合ってるのかしら(どこかに公式チュートリアルとか準備されてるかな)
解決例:CodeBuildでimagedefinitions.jsonを出力して、CodePipelineのDeployフェーズと連携させる
version: 0.2
phases:
pre_build:
commands:
- $(aws ecr get-login --region $AWS_DEFAULT_REGION)
- REPOSITORY_URI="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_REPO_NAME}"
- IMAGE_TAG=${CODEBUILD_RESOLVED_SOURCE_VERSION}
build:
commands:
- echo Build started on `date`
- docker build -t "${IMAGE_REPO_NAME}:${IMAGE_TAG}" .
- docker tag "${IMAGE_REPO_NAME}:${IMAGE_TAG}" "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_REPO_NAME}:${IMAGE_TAG}"
post_build:
commands:
- echo Build completed on `date`
- docker push "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_REPO_NAME}:${IMAGE_TAG}"
- printf '[{"name":"container-name-sample","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
discard-paths: yes
imagedefinitions.jsonをCodeBuildで生成したフォルダ直下においておけば、あとは下記のようなCodePipelineの書き方で、Fargateでもデプロイが可能になる。
CodePipeline:
Type: AWS::CodePipeline::Pipeline
DependsOn: CodePipelineS3
Properties:
Name: codepipeline-sample
ArtifactStore:
Type: S3
Location: !Ref S3BucketName
RoleArn: !Ref RoleArn
Stages:
- Name: Source
Actions:
- Name: Source
RunOrder: 1
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: 1
Provider: GitHub
Configuration:
Owner: hoge
Repo: fuga
Branch: master
OAuthToken: xxxxxxxxxxxx
OutputArtifacts:
- Name: Source
- Name: Build
Actions:
- Name: CodeBuild
RunOrder: 1
InputArtifacts:
- Name: Source
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
Configuration:
ProjectName: !Ref CodeBuild
OutputArtifacts:
- Name: Build
- Name: Deploy
Actions:
- Name: Deploy
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: ECS
InputArtifacts:
- Name: Build
Configuration:
ClusterName: !Ref ClusterName
ServiceName: !Ref ServiceName
3.参考記事
他の方のアドベントカレンダーがすごく参考になったので、CFnまわりの実装で参考にさせていただいた記事をいくつか紹介させていただこうと思います。
- Fargate を試した感想とecs-deployでFargateにデプロイできるようにする話
- AWS CloudFormationを使ってAWS Fargateの環境を作成してみる
- ECS+EC2で動いているサービスをFargateにのせ替える
4.まとめ
社内で使っていたECSをFargate化したことで、EC2の管理(障害対応、およびセキュリティアップデート対応)をなくすことができました。
VPCのサブネット設計など、Fargateにしてもインフラ面を意識しないといけないところはありそうなので、また知見がたまれば共有させていただこうと思います。
それでは、皆様メリークリスマス!