feat(ci/cd): Add artifact bucket and ECS deployment support

- Create S3 artifact bucket with encryption and versioning
- Add ECR lifecycle policy to maintain maximum 5 images
- Add OutputArtifacts to build stage for deployment
- Add Deploy stage with ECS provider
- Update CodePipeline artifact store to use ArtifactBucket
- Replace hardcoded bucket names with parameterized references
- Add IAM permissions for ECS task definition and service management
- Add buildspec commands to generate image definitions file
This commit is contained in:
Daisuke Nakahara 2026-01-10 19:39:15 +09:00
parent 53271302e2
commit 058d1be93f
2 changed files with 99 additions and 5 deletions

View file

@ -16,3 +16,6 @@ phases:
- set -e - set -e
- docker push ${REPOSITORY_URI}:${GIT_TAG} - docker push ${REPOSITORY_URI}:${GIT_TAG}
- docker push ${REPOSITORY_URI}:latest - docker push ${REPOSITORY_URI}:latest
- printf '[{"name":"forgejo","imageUri":"%s"}]' $REPOSITORY_URI:$GIT_TAG > imagedefinitions.json
artifacts:
files: imagedefinitions.json

View file

@ -10,6 +10,10 @@ Parameters:
Type: String Type: String
Default: forgejo-source.zip Default: forgejo-source.zip
ArtifactBucketName:
Type: String
Default: forgejo-artifact-bucket
ForgejoRepositoryName: ForgejoRepositoryName:
Type: String Type: String
Default: forgejo-repository Default: forgejo-repository
@ -29,12 +33,49 @@ Resources:
EventBridgeConfiguration: EventBridgeConfiguration:
EventBridgeEnabled: true EventBridgeEnabled: true
ArtifactBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub "${AWS::Region}-${AWS::AccountId}-${ArtifactBucketName}"
Tags:
- Key: Project
Value: Git-server
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
ForgejoRepository: ForgejoRepository:
Type: AWS::ECR::Repository Type: AWS::ECR::Repository
Properties: Properties:
RepositoryName: !Ref ForgejoRepositoryName RepositoryName: !Ref ForgejoRepositoryName
ImageScanningConfiguration: ImageScanningConfiguration:
ScanOnPush: true ScanOnPush: true
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"rulePriority": 1,
"description": "Expire images to keep maximum 5",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 5
},
"action": {
"type": "expire"
}
}
]
}
CodeBuildRole: CodeBuildRole:
Type: AWS::IAM::Role Type: AWS::IAM::Role
@ -76,8 +117,8 @@ Resources:
- s3:PutObject - s3:PutObject
- s3:ListBucket - s3:ListBucket
Resource: Resource:
- !Sub "arn:aws:s3:::codebuild-${AWS::Region}-${AWS::AccountId}-input-bucket" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${ArtifactBucketName}"
- !Sub "arn:aws:s3:::codebuild-${AWS::Region}-${AWS::AccountId}-input-bucket/*" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${ArtifactBucketName}/*"
- !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}"
- !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}/*" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}/*"
@ -127,8 +168,8 @@ Resources:
- s3:GetBucketLocation - s3:GetBucketLocation
- s3:GetBucketVersioning - s3:GetBucketVersioning
Resource: Resource:
- !Sub "arn:aws:s3:::codebuild-${AWS::Region}-${AWS::AccountId}-input-bucket" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${ArtifactBucketName}"
- !Sub "arn:aws:s3:::codebuild-${AWS::Region}-${AWS::AccountId}-input-bucket/*" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${ArtifactBucketName}/*"
- !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}"
- !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}/*" - !Sub "arn:aws:s3:::${AWS::Region}-${AWS::AccountId}-${SourceBucketName}/*"
- Effect: Allow - Effect: Allow
@ -143,6 +184,41 @@ Resources:
- codepipeline:PutApprovalResult - codepipeline:PutApprovalResult
- codepipeline:StartPipelineExecution - codepipeline:StartPipelineExecution
Resource: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:*" Resource: !Sub "arn:aws:codepipeline:${AWS::Region}:${AWS::AccountId}:*"
- Sid: TaskDefinitionPermissions
Effect: Allow
Action:
- ecs:DescribeTaskDefinition
- ecs:RegisterTaskDefinition
Resource:
- "*"
- Sid: ECSServicePermissions
Effect: Allow
Action:
- ecs:DescribeServices
- ecs:UpdateService
Resource:
- !Sub "arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:service/*/*"
- Sid: ECSTagResource
Effect: Allow
Action:
- ecs:TagResource
Resource:
- !Sub "arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:task-definition/*:*"
Condition:
StringEquals:
ecs:CreateAction:
- RegisterTaskDefinition
- Sid: IamPassRolePermissions
Effect: Allow
Action:
- iam:PassRole
Resource:
- !Sub "arn:aws:iam::${AWS::AccountId}:role/*"
Condition:
StringEquals:
iam:PassedToService:
- ecs.amazonaws.com
- ecs-tasks.amazonaws.com
ForgejoPipeline: ForgejoPipeline:
Type: AWS::CodePipeline::Pipeline Type: AWS::CodePipeline::Pipeline
@ -151,7 +227,7 @@ Resources:
RoleArn: !GetAtt CodePipelineRole.Arn RoleArn: !GetAtt CodePipelineRole.Arn
ArtifactStore: ArtifactStore:
Type: S3 Type: S3
Location: !Sub "codebuild-ap-northeast-1-${AWS::AccountId}-input-bucket" Location: !Ref ArtifactBucket
Stages: Stages:
- Name: Source - Name: Source
Actions: Actions:
@ -177,8 +253,23 @@ Resources:
Version: "1" Version: "1"
InputArtifacts: InputArtifacts:
- Name: SourceOutput - Name: SourceOutput
OutputArtifacts:
- Name: BuildOutput
Configuration: Configuration:
ProjectName: !Ref ForgejoBuildProject ProjectName: !Ref ForgejoBuildProject
- Name: Deploy
Actions:
- Name: DeployECS
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: "1"
InputArtifacts:
- Name: BuildOutput
Configuration:
ClusterName: my-forgejo-cluster
ServiceName: forgejo-service
S3SourceChangeRule: S3SourceChangeRule:
Type: AWS::Events::Rule Type: AWS::Events::Rule