
ECS Fargate 楽々構築テンプレート
この記事は電通デジタルアドベントカレンダー2020の22日目の記事になります。前回の記事は「ADH APIを効率的に呼び出すために開発したHooksの紹介」でした。
改めましてこんにちは!
Docker使ってますか?
AWSでDockerを使おうと思うと以下の3つの選択肢があります。
・Elastic Container Service
・Elastic Kubernetes Service
・EC2に構築する
この中でもECSいいですよね、僕も好きです。運用に手間もかからなくて気軽に使えるところに好感もてます。さすがAWSのマネージドサービス。
ただし実際にECSで構築しようとすると周辺のリソースが色々と必要になるので初心者にとってハードルが高く見えるのも事実です。そんなわけで初心者にも使えるようなテンプレートを提供したいと思います。
このテンプレートでは最低限の機能しか提供しません。何番煎じかもわかりませんしありふれた内容なので初心者以外スルー推奨です。AppMeshやCodeDeployにも触れませんしね。
ECSでFargateを利用するために必要なリソース群
それではFargateの起動に必要な表面上のリソースです。実際にはもう少しリソースが必要になりますが、概念程度の理解を目指します。
Case1:インターネットアクセスを伴う場合
・ALB
・ECS Cluster
・IAMロール(Fargate起動時に必要なロールとアプリが必要とするロール)
・タスク定義(アプリを動かす環境変数などの定義)
・ECSサービス
Case2:VPCのみでアクセスが行われる場合
・Cloud Map(VPC内でのみ利用できるPrivateDNSNameを設定する)
・ECS Cluster
・IAMロール(Fargate起動時に必要なロールとアプリが必要とするロール)
・タスク定義(アプリを動かす環境変数などの定義)
・ECSサービス
Case3:スケジュールで起動するバッチ利用の場合
・ECS Cluster
・IAMロール(Fargate起動時に必要なロールとアプリが必要とするロール)
・タスク定義(アプリを動かす環境変数などの定義)
・CloudWatch イベントルール
ECSサービスの構築
それではCloudFormationのテンプレートファイルです。
前提
・ネットワークが構築済み(VPCやSubnet等)
・アプリケーションはDBと通信しない
Case1:インターネットアクセスを伴う場合
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ProjectName:
Type: String
Default: 'sample1'
VpcId:
Type: AWS::EC2::VPC::Id
PublicSubnets:
Type: List<AWS::EC2::Subnet::Id>
# Descriotion: 'インターネットゲートウェイがアタッチされたSubnet'
ProtectedSubnets:
Type: List<AWS::EC2::Subnet::Id>
# Descriotion: 'NATゲートウェイがアタッチされたSubnet。なかったらPublicSubnetsと同じ値で。'
AllowEcsPolicy:
Type: List<String>
Default: 's3:List*,s3:Get*,s3:Put*'
# Descriotion: 'アプリケーションが必要なAWSリソースのポリシー'
TaskCpu:
Type: Number
Default: 256
TaskMemory:
Type: Number
Default: 512
DesiredCount:
Type: Number
Default: 0 # 作成時はイメージがないので起動しないように設定
# Descriotion: 'ECSサービスの常時起動タスク数'
Resources:
# -------------------------------------
# 外からのアクセスを許可するSG
# -------------------------------------
AllowFromWeb:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: Name
Value: !Sub allow-from-web-for-${ProjectName}
GroupName: !Sub allow-from-web-for-${ProjectName}
GroupDescription: Security group for the service
VpcId: !Ref VpcId
AllowFromWebIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref AllowFromWeb
IpProtocol: -1
SourceSecurityGroupId: !Ref AllowFromWeb
# -------------------------------------
# LBとFargateの通信を許可するSG
# -------------------------------------
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: Name
Value: !Ref ProjectName
GroupName: !Ref ProjectName
GroupDescription: Security group for the service
VpcId: !Ref VpcId
SecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref SecurityGroup
IpProtocol: -1
SourceSecurityGroupId: !Ref SecurityGroup
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub ${ProjectName}-alb
Scheme: internet-facing
Subnets: !Ref PublicSubnets
Type: application
SecurityGroups:
- !Ref SecurityGroup
- !Ref AllowFromWeb
HttpListnener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: fixed-response
FixedResponseConfig:
ContentType: text/plain
StatusCode: 503
LoadBalancerArn: !Ref LoadBalancer
Port: 80
Protocol: HTTP
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref ProjectName
Repository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Ref ProjectName
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /ecs/${ProjectName}
# -------------------------------------
# タスク起動時に必要なロールを定義
# -------------------------------------
EcsTaskExecutionRole:
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
RoleName: !Sub ${ProjectName}-task-execution-role
EcsTaskExecutionRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-task-execution-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ecr:GetLifecyclePolicyPreview
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- ecr:DescribeImages
- ecr:ListTagsForResource
- ecr:BatchCheckLayerAvailability
- ecr:GetLifecyclePolicy
- ecr:GetRepositoryPolicy
Resource: !Sub "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/*"
- Effect: Allow
Action:
- ecr:GetAuthorizationToken
- ssm:GetParameters
- secretsmanager:GetSecretValue
Resource:
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/*"
Roles:
- Ref: EcsTaskExecutionRole
# -------------------------------------
# アプリケーションに必要なロールを定義
# -------------------------------------
EcsTaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- events.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceEventsRole
RoleName: !Sub ${ProjectName}-task-role
EcsTaskRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-task-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: !Ref AllowEcsPolicy
Resource: '*'
Roles:
- Ref: EcsTaskRole
# --------------------------------------------------------------------------
# 1つのALBに複数のサービスを起動する場合は以下のリソースを複数作成する必要があります
# --------------------------------------------------------------------------
# -------------------------------------
# Fargate タスク定義
# -------------------------------------
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Ref ProjectName
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
NetworkMode: awsvpc
ExecutionRoleArn: !GetAtt EcsTaskExecutionRole.Arn
TaskRoleArn: !GetAtt EcsTaskRole.Arn
ContainerDefinitions:
- Name: app
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Repository}
PortMappings:
- ContainerPort: 80
HostPort: 80
Protocol: tcp
Environment:
- Name: TZ
Value: Asia/Tokyo
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref LogGroup
awslogs-stream-prefix: app
Essential: true
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 30
HealthCheckPath: /
HealthCheckPort: 80
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 6
HealthyThresholdCount: 3
Name: !Ref ProjectName
Port: 80
Protocol: HTTP
UnhealthyThresholdCount: 3
TargetType: ip
VpcId: !Ref VpcId
ListnenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
Order: 1
Conditions:
- Field: path-pattern
Values:
- "*"
ListenerArn: !Ref HttpListnener
Priority: 100
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DesiredCount: !Ref DesiredCount
LaunchType: FARGATE
LoadBalancers:
- ContainerName: app
ContainerPort: 80
TargetGroupArn: !Ref TargetGroup
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED # PublicSubnetを利用する場合はENABLEDにする必要があります。
SecurityGroups:
- !Ref SecurityGroup
Subnets: !Ref ProtectedSubnets
ServiceName: !Ref ProjectName
TaskDefinition: !Ref TaskDefinition
DependsOn:
- ListnenerRule
Case2:VPCのみでアクセスが行われる場合
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ProjectName:
Type: String
Default: 'sample2'
VpcId:
Type: AWS::EC2::VPC::Id
ProtectedSubnets:
Type: List<AWS::EC2::Subnet::Id>
# Descriotion: 'NATゲートウェイがアタッチされたSubnet。なかったらPublicSubnetsと同じ値で。'
Namespace:
Type: String
Default: 'sample.local'
AllowEcsPolicy:
Type: List<String>
Default: 's3:List*,s3:Get*,s3:Put*'
# Descriotion: 'アプリケーションが必要なAWSリソースのポリシー'
TaskCpu:
Type: Number
Default: 256
TaskMemory:
Type: Number
Default: 512
ServiceDiscoveryName:
Type: String
Default: 'app'
DesiredCount:
Type: Number
Default: 0 # 作成時はイメージがないので起動しないように設定
# Descriotion: 'ECSサービスの常時起動タスク数'
Resources:
# -------------------------------------
# Fargate同士の通信を許可するSG
# -------------------------------------
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: Name
Value: !Ref ProjectName
GroupName: !Ref ProjectName
GroupDescription: Security group for the service
VpcId: !Ref VpcId
SecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref SecurityGroup
IpProtocol: -1
SourceSecurityGroupId: !Ref SecurityGroup
PrivateDnsNamespace:
Type: AWS::ServiceDiscovery::PrivateDnsNamespace
Properties:
Vpc: !Ref VpcId
Name: !Ref Namespace
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref ProjectName
Repository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Ref ProjectName
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /ecs/${ProjectName}
# -------------------------------------
# タスク起動時に必要なロールを定義
# -------------------------------------
EcsTaskExecutionRole:
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
RoleName: !Sub ${ProjectName}-task-execution-role
EcsTaskExecutionRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-task-execution-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ecr:GetLifecyclePolicyPreview
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- ecr:DescribeImages
- ecr:ListTagsForResource
- ecr:BatchCheckLayerAvailability
- ecr:GetLifecyclePolicy
- ecr:GetRepositoryPolicy
Resource: !Sub "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/*"
- Effect: Allow
Action:
- ecr:GetAuthorizationToken
- ssm:GetParameters
- secretsmanager:GetSecretValue
Resource:
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/*"
Roles:
- Ref: EcsTaskExecutionRole
# -------------------------------------
# アプリケーションに必要なロールを定義
# -------------------------------------
EcsTaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- events.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceEventsRole
RoleName: !Sub ${ProjectName}-task-role
EcsTaskRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-task-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: !Ref AllowEcsPolicy
Resource: '*'
Roles:
- Ref: EcsTaskRole
# --------------------------------------------------------------------------
# 複数のサービスを起動する場合は以下のリソースを複数作成する必要があります
# --------------------------------------------------------------------------
# -------------------------------------
# Fargate タスク定義
# -------------------------------------
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Ref ProjectName
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
NetworkMode: awsvpc
ExecutionRoleArn: !GetAtt EcsTaskExecutionRole.Arn
TaskRoleArn: !GetAtt EcsTaskRole.Arn
ContainerDefinitions:
- Name: app
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Repository}
PortMappings:
- ContainerPort: 80
HostPort: 80
Protocol: tcp
Environment:
- Name: TZ
Value: Asia/Tokyo
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref LogGroup
awslogs-stream-prefix: app
Essential: true
ServiceDiscovery:
Type: AWS::ServiceDiscovery::Service
Properties:
HealthCheckCustomConfig:
FailureThreshold: 1
DnsConfig:
DnsRecords:
- Type: A
TTL: 60
NamespaceId: !GetAtt PrivateDnsNamespace.Id
Name: !Ref ServiceDiscoveryName # http通信で処理されるアプリケーションの場合、http://app.sample.local で呼び出すことができます。
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
DesiredCount: !Ref DesiredCount
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED # PublicSubnetを利用する場合はENABLEDにする必要があります。
SecurityGroups:
- !Ref SecurityGroup
Subnets: !Ref ProtectedSubnets
ServiceName: !Ref ProjectName
ServiceRegistries:
- RegistryArn: !GetAtt ServiceDiscovery.Arn
TaskDefinition: !Ref TaskDefinition
Case3:スケジュールで起動するバッチ利用の場合
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ProjectName:
Type: String
Default: 'sample3'
VpcId:
Type: AWS::EC2::VPC::Id
ProtectedSubnets:
Type: List<AWS::EC2::Subnet::Id>
# Descriotion: 'NATゲートウェイがアタッチされたSubnet。なかったらPublicSubnetsと同じ値で。'
AllowEcsPolicy:
Type: List<String>
Default: 's3:List*,s3:Get*,s3:Put*'
# Descriotion: 'アプリケーションが必要なAWSリソースのポリシー'
TaskCpu:
Type: Number
Default: 256
TaskMemory:
Type: Number
Default: 512
TaskCount:
Type: Number
Default: 1
# Descriotion: 'スケジュールタスクの起動数'
Resources:
# -------------------------------------
# Fargate同士の通信を許可するSG
# -------------------------------------
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: Name
Value: !Ref ProjectName
GroupName: !Ref ProjectName
GroupDescription: Security group for the service
VpcId: !Ref VpcId
SecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref SecurityGroup
IpProtocol: -1
SourceSecurityGroupId: !Ref SecurityGroup
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Ref ProjectName
Repository:
Type: AWS::ECR::Repository
Properties:
RepositoryName: !Ref ProjectName
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /ecs/${ProjectName}
# -------------------------------------
# タスク起動時に必要なロールを定義
# -------------------------------------
EcsTaskExecutionRole:
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
RoleName: !Sub ${ProjectName}-task-execution-role
EcsTaskExecutionRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-task-execution-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ecr:GetLifecyclePolicyPreview
- ecr:GetDownloadUrlForLayer
- ecr:BatchGetImage
- ecr:DescribeImages
- ecr:ListTagsForResource
- ecr:BatchCheckLayerAvailability
- ecr:GetLifecyclePolicy
- ecr:GetRepositoryPolicy
Resource: !Sub "arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/*"
- Effect: Allow
Action:
- ecr:GetAuthorizationToken
- ssm:GetParameters
- secretsmanager:GetSecretValue
Resource:
- !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/*"
Roles:
- Ref: EcsTaskExecutionRole
# -------------------------------------
# アプリケーションに必要なロールを定義
# -------------------------------------
EcsTaskRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ecs-tasks.amazonaws.com
- events.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceEventsRole
RoleName: !Sub ${ProjectName}-task-role
EcsTaskRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-task-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: !Ref AllowEcsPolicy
Resource: '*'
Roles:
- Ref: EcsTaskRole
# --------------------------------------------------------------------------
# 複数のスケジュールタスクを起動する場合は以下のリソースを複数作成する必要があります
# --------------------------------------------------------------------------
# -------------------------------------
# Fargate タスク定義
# -------------------------------------
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Ref ProjectName
RequiresCompatibilities:
- FARGATE
Cpu: !Ref TaskCpu
Memory: !Ref TaskMemory
NetworkMode: awsvpc
ExecutionRoleArn: !GetAtt EcsTaskExecutionRole.Arn
TaskRoleArn: !GetAtt EcsTaskRole.Arn
ContainerDefinitions:
- Name: app
Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${Repository}
EntryPoint:
- 'sh'
- '-c'
Environment:
- Name: TZ
Value: Asia/Tokyo
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref 'AWS::Region'
awslogs-group: !Ref LogGroup
awslogs-stream-prefix: app
Essential: true
EventRule:
Type: AWS::Events::Rule
Properties:
Name: !Ref ProjectName
State: ENABLED
ScheduleExpression: cron(0 9 * * ? *) # UTCなので+9:00で記載する必要があるため、この設定は00:00で起動する意味になります。
Targets:
- Id: !Ref ProjectName
Arn: !GetAtt Cluster.Arn
RoleArn: !GetAtt EcsTaskExecutionRole.Arn
EcsParameters:
TaskDefinitionArn: !Ref TaskDefinition
TaskCount: !Ref TaskCount
LaunchType: FARGATE
NetworkConfiguration:
AwsVpcConfiguration:
AssignPublicIp: DISABLED # PublicSubnetを利用する場合はENABLEDにする必要があります。
SecurityGroups:
- !Ref SecurityGroup
Subnets: !Ref ProtectedSubnets
Input: !Join [
'',
[
"{",
" \"containerOverrides\": [ ",
" {",
" \"name\": \"app\", ", # タスク定義のコンテナ名を指定する必要があります。
" \"command\": [\"echo hello\"]",
" }",
" ]",
"}",
]
]
ECSにデプロイ
今回は下図で示したように開発環境で動かすためにビルドしたイメージを本番環境にデプロイするところまで書いて行こうと思います。
Fargateをデプロイするために必要なリソース群
AWSにDockerをデプロイするために必要な表面上のリソースです。こちらも実際にはもう少しリソースが必要になります。
・IAMロール(CodeBuildとCodePipelineでそれぞれ必要)
・CodeBuildプロジェクト
・CodePipeline
前提
・ネットワークが構築済み(VPCやSubnet等)
・AWS::ECR::Repositoryが構築済み
・AWS::ECS::Serviceが構築済み
・Secrets Managerに以下の情報を登録済み(Valueが設定されている状態)
{
"GitHubPersonalAccessToken": "",
"GitHubUserName": "",
"DockerHubID": "",
"DockerHubPassword": ""
}
このテンプレートではECR Publicに対応していないためDockerのログイン情報を必要としています。詳しい理由はこちらをご覧ください。
開発環境
GitHubのmainブランチが変更されるとCodePipelineが実行されるように構築します。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ProjectName:
Type: String
Default: 'sample'
VpcId:
Type: AWS::EC2::VPC::Id
ProtectedSubnets:
Type: List<AWS::EC2::Subnet::Id>
# Descriotion: 'NATゲートウェイがアタッチされたSubnet。'
CICredentialArn:
Type: String
# Descriotion: SecretsManagerに登録した機密情報のARN
AccountIdForProduction:
Type: String
# Description: 本番環境のAWSアカウントID
EcrRepository:
Type: String
BuildDir:
Type: String
Default: '.'
ContainerName:
Type: String
Default: 'app'
ClusterName:
Type: String
ServiceName:
Type: String
GitHubOwner:
Type: String
GitHubRepository:
Type: String
GitHubBranch:
Type: String
Default: 'master'
# Description: このブランチの変更をトリガーにCodePipelineが実行されます。
ReleaseVersion:
Type: String
Default: 'v1.0'
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${AWS::AccountId}-arfifacts
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
# -------------------------------------
# CodeBuildにアタッチされます。例えばCodeBuildでDBのマイグレーションを実行する場合に必要になります。
# -------------------------------------
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: Name
Value: !Ref ProjectName
GroupName: !Ref ProjectName
GroupDescription: Security group for the service
VpcId: !Ref VpcId
SecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref SecurityGroup
IpProtocol: -1
SourceSecurityGroupId: !Ref SecurityGroup
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
- arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/CloudWatchFullAccess
- arn:aws:iam::aws:policy/AmazonEC2ContainerServiceFullAccess
RoleName: !Sub ${ProjectName}-codepipeline-role
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
- events.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
- arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
RoleName: !Sub ${ProjectName}-codebuild-role
CodeBuildRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-codebuild-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ecr:GetAuthorizationToken
- ssm:GetParameters
- secretsmanager:GetSecretValue
Resource:
- '*'
- Effect: Allow
Action:
- sts:AssumeRole
Resource:
- '*'
- Effect: Allow
Action:
- ec2:CreateNetworkInterface
- ec2:DescribeDhcpOptions
- ec2:DescribeNetworkInterfaces
- ec2:DeleteNetworkInterface
- ec2:DescribeSubnets
- ec2:DescribeSecurityGroups
- ec2:DescribeVpcs
Resource:
- '*'
- Effect: Allow
Action:
- '*'
Resource:
- !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:network-interface/*"
Roles:
- Ref: CodeBuildRole
AppBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub ${ProjectName}-build
Artifacts:
Type: CODEPIPELINE
Description: !Sub Building stage for ${ProjectName}
Environment:
ComputeType: BUILD_GENERAL1_LARGE
Image: aws/codebuild/standard:4.0
Type: LINUX_CONTAINER
PrivilegedMode: True
EnvironmentVariables:
- Name: REPOSITORY_URI
Value: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrRepository}"
- Name: CONTAINER_NAME
Value: !Ref ContainerName
- Name: BUILD_DIR
Value: !Ref BuildDir
ServiceRole: !Ref CodeBuildRole
Source:
Type: CODEPIPELINE
BuildSpec:
!Join [
"\n",
[
"version: 0.2",
"",
"env:",
" variables:",
" DOCKER_BUILDKIT: \"1\"",
" secrets-manager:",
!Sub " GITHUB_TOKEN: \"${CICredentialArn}:GitHubPersonalAccessToken\"",
!Sub " DOCKERHUB_ID: \"${CICredentialArn}:DockerHubID\"",
!Sub " DOCKERHUB_PASSWORD: \"${CICredentialArn}:DockerHubPassword\"",
"",
"phases:",
" pre_build:",
" commands:",
" - echo Logging in to DockerHub...",
" - docker login -u ${DOCKERHUB_ID} -p ${DOCKERHUB_PASSWORD}",
" - echo Logging in to Amazon ECR...",
" - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)",
" - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)",
" - IMAGE_TAG=${COMMIT_HASH:=latest}",
" build:",
" commands:",
" - echo Build started on `date`",
" - docker build -t $REPOSITORY_URI:latest $BUILD_DIR --build-arg GITHUB_TOKEN=$GITHUB_TOKEN",
" - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG",
" post_build:",
" commands:",
" - echo Build completed on `date`",
" - docker push $REPOSITORY_URI:latest",
" - docker push $REPOSITORY_URI:$IMAGE_TAG",
" - echo \"[{\\\"name\\\":\\\"${CONTAINER_NAME}\\\",\\\"imageUri\\\":\\\"${REPOSITORY_URI}:${IMAGE_TAG}\\\"}]\" > imagedefinitions.json",
"artifacts:",
" files:",
" - imagedefinitions.json",
""
]
]
# VpcConfig:
# VpcId: !Ref VpcId
# Subnets: !Ref ProtectedSubnets
# SecurityGroupIds:
# - !Ref SecurityGroup
TimeoutInMinutes: 30
Cache:
Type: LOCAL # 有効時間が短いためこの効果に過度な期待をしないでください。
Modes:
- LOCAL_DOCKER_LAYER_CACHE
TaggingProject:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub ${ProjectName}-tagging
Artifacts:
Type: CODEPIPELINE
Description: !Sub Tagging stage for ${ProjectName}
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:4.0
Type: LINUX_CONTAINER
PrivilegedMode: True
EnvironmentVariables:
- Name: GITHUB_OWNER
Value: !Ref GitHubOwner
- Name: GITHUB_PROJECT
Value: !Ref GitHubRepository
- Name: RELEASE_VERSION
Value: !Ref ReleaseVersion
ServiceRole: !Ref CodeBuildRole
Source:
Type: CODEPIPELINE
BuildSpec: !Join [
"\n",
[
"version: 0.2",
"",
"env:",
" variables:",
" DOCKER_BUILDKIT: \"1\"",
" secrets-manager:",
!Sub " GITHUB_TOKEN: \"${CICredentialArn}:GitHubPersonalAccessToken\"",
!Sub " DOCKERHUB_ID: \"${CICredentialArn}:DockerHubID\"",
!Sub " DOCKERHUB_PASSWORD: \"${CICredentialArn}:DockerHubPassword\"",
"",
"phases:",
" pre_build:",
" commands:",
" - echo Logging in to DockerHub...",
" - docker login -u ${DOCKERHUB_ID} -p ${DOCKERHUB_PASSWORD}",
" - tag_name=\"${RELEASE_VERSION}\"",
" - description=''",
" - apt-get install -y tzdata",
" - ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime",
" - released=`date '+%Y%m%d%H%M'`",
" build:",
" commands:",
" - authorization=\"Authorization:token $GITHUB_TOKEN\"",
" - content_type=\"Content-Type:application/json\"",
" - release_tag=$tag_name.$released",
" - release_name=$tag_name.$released",
" - params=\"{\\\"tag_name\\\":\\\"$release_tag\\\",\\\"target_commitish\\\":\\\"$CODEBUILD_RESOLVED_SOURCE_VERSION\\\",\\\"name\\\":\\\"$release_name\\\",\\\"body\\\":\\\"$description\\\",\\\"draft\\\":false,\\\"prerelease\\\":false}\"",
" post_build:",
" commands:",
" - curl -X POST -H \"$authorization\" -H \"$content_type\" -d \"$params\" https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_PROJECT}/releases",
"",
]
]
# VpcConfig:
# VpcId: !Ref VpcId
# Subnets: !Ref ProtectedSubnets
# SecurityGroupIds:
# - !Ref SecurityGroup
TimeoutInMinutes: 30
ReleaseProject:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub ${ProjectName}-release
Artifacts:
Type: CODEPIPELINE
Description: !Sub Release stage for ${ProjectName}
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:4.0
Type: LINUX_CONTAINER
PrivilegedMode: True
EnvironmentVariables:
- Name: DEV_APP_CONTAINER_IMAGE_URI
Value: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrRepository}"
- Name: PRD_APP_CONTAINER_IMAGE_URI
Value: !Sub "${AccountIdForProduction}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrRepository}"
- Name: GITHUB_OWNER
Value: !Ref GitHubOwner
- Name: GITHUB_PROJECT
Value: !Ref GitHubRepository
- Name: RELEASE_VERSION
Value: !Ref ReleaseVersion
- Name: PRD_ACCOUNT_ID
Value: !Ref AccountIdForProduction
- Name: ASSUME_ROLE_ARN
Value: !Sub "arn:aws:iam::${AccountIdForProduction}:role/${ProjectName}-release-role" # 本番環境の構築時に作成します。
ServiceRole: !Ref CodeBuildRole
Source:
Type: CODEPIPELINE
BuildSpec: !Join [
"\n",
[
"version: 0.2",
"",
"env:",
" variables:",
" DOCKER_BUILDKIT: \"1\"",
" secrets-manager:",
!Sub " GITHUB_TOKEN: \"${CICredentialArn}:GitHubPersonalAccessToken\"",
!Sub " DOCKERHUB_ID: \"${CICredentialArn}:DockerHubID\"",
!Sub " DOCKERHUB_PASSWORD: \"${CICredentialArn}:DockerHubPassword\"",
"",
"phases:",
" pre_build:",
" commands:",
" - echo Logging in to DockerHub...",
" - docker login -u ${DOCKERHUB_ID} -p ${DOCKERHUB_PASSWORD}",
" - echo Logging in to Amazon ECR...",
" - aws --version",
" - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)",
" - IMAGE_TAG=${COMMIT_HASH:=latest}",
" - RELEASE_TAG=`curl -X GET -H \"Authorization:token ${GITHUB_TOKEN}\" https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_PROJECT}/releases | jq -r '. | select(.[0].tag_name | startswith(\"'$RELEASE_VERSION'\"))' | jq -r .[0].tag_name`",
" - if [ -z $RELEASE_TAG ]; then RELEASE_TAG=$RELEASE_VERSION; fi",
" - echo $RELEASE_TAG",
" build:",
" commands:",
" - echo Build started on `date`",
" - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)",
" - docker pull $DEV_APP_CONTAINER_IMAGE_URI:$IMAGE_TAG",
" - docker tag $DEV_APP_CONTAINER_IMAGE_URI:$IMAGE_TAG $DEV_APP_CONTAINER_IMAGE_URI:$RELEASE_VERSION",
" - docker tag $DEV_APP_CONTAINER_IMAGE_URI:$IMAGE_TAG $DEV_APP_CONTAINER_IMAGE_URI:$RELEASE_TAG",
" - docker push $DEV_APP_CONTAINER_IMAGE_URI:$RELEASE_VERSION",
" - docker push $DEV_APP_CONTAINER_IMAGE_URI:$RELEASE_TAG",
" - docker tag $DEV_APP_CONTAINER_IMAGE_URI:$IMAGE_TAG $PRD_APP_CONTAINER_IMAGE_URI:$RELEASE_VERSION",
" - docker tag $DEV_APP_CONTAINER_IMAGE_URI:$IMAGE_TAG $PRD_APP_CONTAINER_IMAGE_URI:$RELEASE_TAG",
" - docker tag $DEV_APP_CONTAINER_IMAGE_URI:$IMAGE_TAG $PRD_APP_CONTAINER_IMAGE_URI:latest",
" post_build:",
" commands:",
" - echo Pushing the Docker images...",
" - mkdir -p credentials",
" - echo \"[profile production]\" > credentials/config",
" - echo \"role_arn = ${ASSUME_ROLE_ARN}\" >> credentials/config",
" - echo \"credential_source = EcsContainer\" >> credentials/config",
" - export AWS_CONFIG_FILE=${CODEBUILD_SRC_DIR}/credentials/config",
" - aws sts get-caller-identity --profile production",
" - $(aws ecr get-login --registry-ids ${PRD_ACCOUNT_ID} --no-include-email --region $AWS_DEFAULT_REGION --profile production)",
" - docker push $PRD_APP_CONTAINER_IMAGE_URI:$RELEASE_VERSION",
" - docker push $PRD_APP_CONTAINER_IMAGE_URI:$RELEASE_TAG",
" - docker push $PRD_APP_CONTAINER_IMAGE_URI:latest",
"",
]
]
# VpcConfig:
# VpcId: !Ref VpcId
# Subnets: !Ref ProtectedSubnets
# SecurityGroupIds:
# - !Ref SecurityGroup
TimeoutInMinutes: 30
CodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref ArtifactBucket
Type: S3
Name: !Ref ProjectName
RestartExecutionOnUpdate: false
RoleArn: !GetAtt CodePipelineRole.Arn
Stages:
- Name: Source
Actions:
- Name: SourceCode
ActionTypeId:
Category: Source
Owner: ThirdParty
Version: 1
Provider: GitHub
Configuration:
Owner: !Ref GitHubOwner
Repo: !Ref GitHubRepository
Branch: !Ref GitHubBranch
OAuthToken: !Sub '{{resolve:secretsmanager:${CICredentialArn}:SecretString:GitHubPersonalAccessToken}}'
OutputArtifacts:
- Name: SourceCode
RunOrder: 1
- Name: Build
Actions:
- Name: CodeBuild
InputArtifacts:
- Name: SourceCode
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref AppBuildProject
OutputArtifacts:
- Name: BuildImage
RunOrder: 1
- Name: Deploy
Actions:
- Name: Deploy
InputArtifacts:
- Name: BuildImage
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: 1
Configuration:
ClusterName: !Ref ClusterName
FileName: imagedefinitions.json
ServiceName: !Ref ServiceName
OutputArtifacts: []
RunOrder: 1
- Name: Approval
Actions:
- Name: Approval
ActionTypeId:
Category: Approval
Owner: AWS
Version: 1
Provider: Manual
RunOrder: 1
- Name: GitHubTagging
Actions:
- Name: CodeBuild
InputArtifacts:
- Name: SourceCode
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref TaggingProject
RunOrder: 1
- Name: Release
Actions:
- Name: CodeBuild
InputArtifacts:
- Name: SourceCode
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref ReleaseProject
RunOrder: 1
CodeBuildからVPC内のリソースにアクセスしたい場合など、CodeBuildをVPC内に配置する際はVpcConfigのコメントアウトを外す必要があります。ただしNATゲートウェイをアタッチしたSubnetが必要です。
本番環境
開発環境のCodeBuildから本番環境のECRにPushされたことをトリガーにCodePipelineが実行されるように構築します。
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ProjectName:
Type: String
Default: 'sample'
VpcId:
Type: AWS::EC2::VPC::Id
ProtectedSubnets:
Type: List<AWS::EC2::Subnet::Id>
# Descriotion: 'NATゲートウェイがアタッチされたSubnet。'
CICredentialArn:
Type: String
# Descriotion: SecretsManagerに登録した機密情報のARN
AccountIdForDevelopment:
Type: String
# Description: 開発環境のAWSアカウントID
EcrRepository:
Type: String
ContainerName:
Type: String
Default: 'app'
ClusterName:
Type: String
ServiceName:
Type: String
GitHubOwner:
Type: String
GitHubRepository:
Type: String
ReleaseVersion:
Type: String
Default: 'v1.0'
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${AWS::AccountId}-arfifacts
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
# -------------------------------------
# CodeBuildにアタッチされます。例えばCodeBuildでDBのマイグレーションを実行する場合に必要になります。
# -------------------------------------
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
Tags:
- Key: Name
Value: !Ref ProjectName
GroupName: !Ref ProjectName
GroupDescription: Security group for the service
VpcId: !Ref VpcId
SecurityGroupIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref SecurityGroup
IpProtocol: -1
SourceSecurityGroupId: !Ref SecurityGroup
# -------------------------------------
# 開発環境からイメージをPushする際に利用されます。
# -------------------------------------
ReleaseRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- !Sub "arn:aws:iam::${AccountIdForDevelopment}:root"
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
RoleName: !Sub ${ProjectName}-release-role
CodePipelineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
- arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/CloudWatchFullAccess
- arn:aws:iam::aws:policy/AmazonEC2ContainerServiceFullAccess
RoleName: !Sub ${ProjectName}-codepipeline-role
CodeBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
- events.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess
- arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
RoleName: !Sub ${ProjectName}-codebuild-role
CodeBuildRolePolicy:
Type: AWS::IAM::Policy
Properties:
PolicyName: !Sub ${ProjectName}-codebuild-role-policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- ecr:GetAuthorizationToken
- ssm:GetParameters
- secretsmanager:GetSecretValue
Resource:
- '*'
- Effect: Allow
Action:
- sts:AssumeRole
Resource:
- '*'
- Effect: Allow
Action:
- ec2:CreateNetworkInterface
- ec2:DescribeDhcpOptions
- ec2:DescribeNetworkInterfaces
- ec2:DeleteNetworkInterface
- ec2:DescribeSubnets
- ec2:DescribeSecurityGroups
- ec2:DescribeVpcs
Resource:
- '*'
- Effect: Allow
Action:
- '*'
Resource:
- !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:network-interface/*"
Roles:
- Ref: CodeBuildRole
# -------------------------------------
# 開発環境からイメージをPushする際に利用されます。
# -------------------------------------
CodePipelineEventRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action: sts:AssumeRole
Path: /
Policies:
- PolicyName: !Sub ${ProjectName}-cloudwatch-event
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: codepipeline:StartPipelineExecution
Resource: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${ProjectName}"
RoleName: !Sub ${ProjectName}-codepipeline-execution-role
AppBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: !Sub ${ProjectName}-build
Artifacts:
Type: CODEPIPELINE
Description: !Sub Building stage for ${ProjectName}
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:4.0
Type: LINUX_CONTAINER
PrivilegedMode: True
EnvironmentVariables:
- Name: REPOSITORY_URI
Value: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${EcrRepository}"
- Name: CONTAINER_NAME
Value: !Ref ContainerName
- Name: RELEASE_VERSION
Value: !Ref ReleaseVersion
- Name: GITHUB_OWNER
Value: !Ref GitHubOwner
- Name: GITHUB_PROJECT
Value: !Ref GitHubRepository
ServiceRole: {'Fn::ImportValue': !Join [':', [!Ref ProjectName, CodeBuildRole]]}
Source:
Type: CODEPIPELINE
BuildSpec: !Join [
"\n",
[
"version: 0.2",
"",
"env:",
" variables:",
" DOCKER_BUILDKIT: \"1\"",
" secrets-manager:",
!Sub " GITHUB_TOKEN: \"${CICredentialArn}:GitHubPersonalAccessToken\"",
!Sub " DOCKERHUB_ID: \"${CICredentialArn}:DockerHubID\"",
!Sub " DOCKERHUB_PASSWORD: \"${CICredentialArn}:DockerHubPassword\"",
"",
"phases:",
" pre_build:",
" commands:",
" - echo Logging in to Amazon ECR...",
" - aws --version",
" - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)",
" - IMAGE_TAG=`curl -X GET -H \"Authorization:token ${GITHUB_TOKEN}\" https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_PROJECT}/releases | jq -r '. | select(.[0].tag_name | startswith(\"'$RELEASE_VERSION'\"))' | jq -r .[0].tag_name`",
" post_build:",
" commands:",
" - echo Writing image definitions file...",
" - echo \"[{\\\"name\\\":\\\"${CONTAINER_NAME}\\\",\\\"imageUri\\\":\\\"${REPOSITORY_URI}:${IMAGE_TAG}\\\"}]\" > imagedefinitions.json",
"artifacts:",
" files: imagedefinitions.json",
""
]
]
# VpcConfig:
# VpcId: !Ref VpcId
# Subnets: !Ref ProtectedSubnets
# SecurityGroupIds:
# - !Ref SecurityGroup
TimeoutInMinutes: 30
Cache:
Type: LOCAL
Modes:
- LOCAL_DOCKER_LAYER_CACHE
# -------------------------------------
# ECRへのPushイベントを拾います。
# -------------------------------------
CodePipelineEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.ecr
detail:
eventName:
- PutImage
requestParameters:
repositoryName:
- !Ref EcrRepository
imageTag:
- !Ref ReleaseVersion
Targets:
- Arn: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:${CodePipeline}"
RoleArn: !GetAtt CodePipelineEventRole.Arn
Id: !Ref ProjectName
Name: !Ref ProjectName
CodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref ArtifactBucket
Type: S3
Name: !Ref ProjectName
RestartExecutionOnUpdate: false
RoleArn: !GetAtt CodePipelineRole.Arn
Stages:
- Name: Source
Actions:
- Name: SourceImage
ActionTypeId:
Category: Source
Owner: AWS
Version: 1
Provider: ECR
Configuration:
ImageTag: !Ref ReleaseVersion
RepositoryName: !Ref EcrRepository
OutputArtifacts:
- Name: SourceImage
RunOrder: 1
- Name: Build
Actions:
- Name: CodeBuild
InputArtifacts:
- Name: SourceImage
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref AppBuildProject
OutputArtifacts:
- Name: BuildImage
RunOrder: 1
- Name: Deploy
Actions:
- Name: Deploy
InputArtifacts:
- Name: BuildImage
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: 1
Configuration:
ClusterName: !Ref ClusterName
FileName: imagedefinitions.json
ServiceName: !Ref ServiceName
OutputArtifacts: []
RunOrder: 1
おわりに
いかがだったでしょうか?ECSでサービスを構築するさいのお役に立てればと思います。
23日目は「2020年秋、ビルドトラップに浸かりました。」です。次回もよろしくお願いいたします。