AWS CodeBuildでdocker image をビルドするハンズオン!
はじめに
この記事では AWSのビルドサービスであるAWS CodeBuildについて解説した記事です。
記事の途中ではハンズオンがあります。
想定している読者としてはAWSのアカウントを既に持っており、Codeシリーズに興味がある人
を対象にしています。
注意事項
-
AWS初学者向けかと問われると若干怪しいところがあります
- AWSのアソシエイトレベルはクリアできる/クリアできる見込みのある人であれば、概ねできるように書いています
- 上記に該当する人で難しいと感じてしまったのであれば、ごめんなさい
- AWSのアソシエイトレベルはクリアできる/クリアできる見込みのある人であれば、概ねできるように書いています
-
記事の内容につきましてはある程度が時間が経過しても読めるように努力します
-
できる限り
というベストエフォートな対応になりますのでご了承下さい - 最新の情報はAWSの公式ドキュメントを見ていただくようにお願いできればと思います
-
-
本記事のハンズオンで発生した料金については一切責任を負いません
- 利用しないサービスについては作成後に必ず削除することをお勧めします。
CodeBuild とは
AWSのドキュメントには以下のように説明があります。
AWS CodeBuild is a fully managed build service in the cloud. CodeBuild compiles your source code, runs unit tests, and produces artifacts that are ready to deploy. CodeBuild eliminates the need to provision, manage, and scale your own build servers. It provides prepackaged build environments for popular programming languages and build tools such as Apache Maven, Gradle, and more. You can also customize build environments in CodeBuild to use your own build tools. CodeBuild scales automatically to meet peak build requests.
訳:AWS CodeBuildは、クラウド上で完全に管理されたビルドサービスです。CodeBuildは、ソースコードのコンパイル、ユニットテストの実行、デプロイ可能なアーティファクトの生成を行います。CodeBuildは、独自のビルドサーバーをプロビジョニング、管理、スケールアップする必要性を排除しています。一般的なプログラミング言語や、Apache Maven、Gradleなどのビルドツール用のビルド環境があらかじめパッケージ化されています。また、CodeBuildでビルド環境をカスタマイズして、独自のビルドツールを使用することも可能です。CodeBuildは、ピーク時のビルド要求に対応するために自動的にスケールします。
AWSで数あるCodeシリーズの中ではビルドを担当するサービスであり、フルマネージドでソースコードのビルドができます。
CodeBuildの使い方や仕組み
ここまででCodeBuildがCodeシリーズの中でビルドを担当するものであることを理解できたと思います。
ただし、CodeBuildにはビルドの設定ファイルとしてbuildspec.yml
というビルドの方法を記録した設定ファイルが必要です。
buildspec.yml
をCodeBuildでビルドするリポジトリに配置しておくことでCodeBuildがbuildspec.yml
の内容に従ってビルドを実行します。
CodeBuildの料金体系
CodeBuildでビルドを実行する前に料金について解説します。
※最新の料金体系を把握したい場合はAWS公式ドキュメントを参照してください。
CodeBuildはビルド時間とコンピューティングタイプ(インスタンスタイプ)に応じて課金が発生します。
無料利用枠には1か月あたり100分のビルド時間があります。
以下、AWS公式ドキュメントから抜粋
AWS CodeBuild の無料利用枠には、general1.small または arm1.small のインスタンスタイプで 1 か月あたり 100 分の総ビルド時間が含まれています。CodeBuild の無料利用枠は、12 か月間の AWS 無料利用枠の期間が終了しても自動的に期限切れになることはありません。新規または既存の AWS のお客様が利用できます。
利用環境
前提
ハンズオンではIAM Identity Centerを使って解説します。シングルサインオンを実行します。
事前準備
リポジトリを作成する
※CloudFormation で作成する場合は以下
AWSTemplateFormatVersion: 2010-09-09
Description: cicd_handson
Parameters:
PjName:
Type: String
Default: cicdhandson
Resources:
CICDHandsonRepository:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryDescription: !Sub "${PjName} CodeCommit Repositroy"
RepositoryName: !Sub "${PjName}"
Tags:
- Key: Name
Value: !Sub "${PjName}"
Outputs:
CodeCommitRepositoryName:
Value: !GetAtt "CICDHandsonRepository.Name"
Export:
Name: CodeRepositoryName
CodeCommitRepositoryArn:
Value: !GetAtt CICDHandsonRepository.Arn
Export:
Name: CodeRepositoryArn
※既にリポジトリをクローンしている場合
デスクトップ上にリポジトリをクローン済みの場合はカレントディレクトリを変更してIAM Identity Centerに対してシングルサインオンを実行します。
cd ~/Desktop/cicd_handson
aws sso login --profile {Profile名}
mainブランチを切る
git checkout -b main
git push --set-upstream origin main
code_build_handsonブランチを切る
新しいブランチでビルドを実行する為にCodeBuild用に新しくブランチを切ります。
git checkout -b code_build_handson
リモートリポジトリにブランチを追加します。
git push --set-upstream origin code_build_handson
buildspec.yamlを作成する
buildspec.yamlを作成します。
touch buildspec.yml
以下の内容でbuildspec.yamlを修正します。
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- 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`
- echo Pushing the Docker image...
- docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
リポジトリにbuildspecをpushします。
git add .
git commit -m "buildspec.yml"
git push -u
dockerfileを作成する
dockerfileを作成します。
touch dockerfile
以下の内容で修正します。
FROM httpd@sha256:2326ba7ae9bff1c55a618051b86c7d71401712898afe1a833734076962a231e5
dockerfileを追加します。
git add .
git commit -m "dockerfile"
git push -u
CodePipeline の環境構築
以下のCloudFormationでCodePipelineを構築します。
AWSTemplateFormatVersion: 2010-09-09
Description: cicd_handson
Parameters:
PjName:
Type: String
Default: cicdhandson
Resources:
# Save Artifact
CICDHandsonBuket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: "Suspended"
BucketName: !Sub "${PjName}-bucket-${AWS::AccountId}"
AccessControl: "Private"
Tags:
- Key: "Name"
Value: !Sub "${PjName}"
# ECR
CICDHandsonCodeBuildECR:
Type: "AWS::ECR::Repository"
Properties:
RepositoryName: !Sub "${PjName}"
# CodeBuild
CICDHandsonCodeBuildPj:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
Description: CodeBuild
Environment:
EnvironmentVariables:
- Name: AWS_DEFAULT_REGION
Type: PLAINTEXT
Value: !Ref AWS::Region
- Name: AWS_ACCOUNT_ID
Type: PLAINTEXT
Value: !Ref AWS::AccountId
- Name: IMAGE_REPO_NAME
Type: PLAINTEXT
Value: !Sub "${PjName}"
- Name: IMAGE_TAG
Type: PLAINTEXT
Value: latest
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
Type: LINUX_CONTAINER
PrivilegedMode: true
Name: !Sub "${PjName}"
ServiceRole: CiCdHandsonCodeBuildRole
Source:
BuildSpec: buildspec.yml
Type: CODEPIPELINE
Tags:
- Key: Name
Value: cicd_handson
DependsOn:
- CiCdHandsonCodeBuildRole
- CICDHandsonCodeBuildECR
- CICDHandsonBuket
# CodeBuildRole
CiCdHandsonCodeBuildRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: CiCdHandsonCodeBuildRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: "codebuild.amazonaws.com"
Action: "sts:AssumeRole"
Policies:
- PolicyName: codebuild-role
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- "ecr:GetDownloadUrlForLayer"
- "ecr:BatchGetImage"
- "ecr:BatchCheckLayerAvailability"
Resource:
- !GetAtt CICDHandsonCodeBuildECR.Arn
- Effect: Allow
Action:
- "ecr:CompleteLayerUpload"
- "ecr:InitiateLayerUpload"
- "ecr:UploadLayerPart"
- "ecr:PutImage"
Resource:
- !GetAtt CICDHandsonCodeBuildECR.Arn
- Effect: Allow
Action:
- "ecr:GetAuthorizationToken"
Resource:
- "*"
- Effect: Allow
Action:
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "logs:CreateLogGroup"
Resource: "*"
- Effect: Allow
Action:
- "s3:PutObject"
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketAcl"
- "s3:GetBucketLocation"
Resource:
- !Join
- ""
- - !GetAtt CICDHandsonBuket.Arn
- "/*"
- !GetAtt CICDHandsonBuket.Arn
# CloudWatch Logs
CICDHandsonCloudWatchLogs:
Type: "AWS::Logs::LogGroup"
DeletionPolicy: Delete
UpdateReplacePolicy: Retain
Properties:
LogGroupName: !Sub "${PjName}"
RetentionInDays: 60
Tags:
- Key: Name
Value: !Sub "${PjName}"
CICDHandsonCodePipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
ArtifactStore:
Location: !Ref CICDHandsonBuket
Type: S3
Name: !Sub "${PjName}-pipeline"
RoleArn: !GetAtt CICDHandsonCodePipelineIAMRole.Arn
Stages:
- Actions:
- ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
RepositoryName: !ImportValue "CodeRepositoryName"
BranchName: main
PollForSourceChanges: false
OutputArtifactFormat: CODE_ZIP
Name: Source
Namespace: SourceVariables
OutputArtifacts:
- Name: SourceArtifact
Region: ap-northeast-1
RunOrder: 1
Name: Source
- Actions:
- ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref CICDHandsonCodeBuildPj
InputArtifacts:
- Name: SourceArtifact
Name: Build
Namespace: BuildVariables
OutputArtifacts:
- Name: BuildArtifact
Region: ap-northeast-1
RunOrder: 1
Name: Build
Tags:
- Key: Name
Value: !Sub "${PjName}"
CICDHandsonCodePipelineIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "codecommit:CancelUploadArchive"
- "codecommit:GetBranch"
- "codecommit:GetCommit"
- "codecommit:GetRepository"
- "codecommit:GetUploadArchiveStatus"
- "codecommit:UploadArchive"
Resource:
- "*"
- Effect: Allow
Action:
- "codebuild:BatchGetBuilds"
- "codebuild:StartBuild"
Resource:
- "*"
- Effect: Allow
Action:
- "s3:PutObject"
- "s3:GetObject"
- "s3:GetObjectVersion"
- "s3:GetBucketAcl"
- "s3:GetBucketLocation"
Resource:
- !Join
- ""
- - !GetAtt CICDHandsonBuket.Arn
- "/*"
- !GetAtt CICDHandsonBuket.Arn
ManagedPolicyName: iam-policy-codepipeline
CICDHandsonCodePipelineIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- codepipeline.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- !Ref CICDHandsonCodePipelineIAMPolicy
RoleName: iam-role-codepipeline
Tags:
- Key: Name
Value: !Sub "${PjName}"
# EventBridge
EventBridgeIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- "codepipeline:StartPipelineExecution"
Resource:
- !Join
- ""
- - "arn:aws:codepipeline:ap-northeast-1:"
- !Sub "${AWS::AccountId}:"
- !Sub "${PjName}-pipeline"
ManagedPolicyName: iam-policy-eventbridge
EventBridgeIAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action:
- "sts:AssumeRole"
ManagedPolicyArns:
- !Ref EventBridgeIAMPolicy
RoleName: iam-role-eventbridge
Tags:
- Key: Name
Value: !Sub "${PjName}"
EventBridge:
Type: AWS::Events::Rule
Properties:
Description: for codepipeline
EventPattern:
source:
- aws.codecommit
detail-type:
- "CodeCommit Repository State Change"
resources:
- !ImportValue "CodeRepositoryArn"
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- main
Name: cicdhandson-codepipeline
State: ENABLED
Targets:
- Arn: !Join
- ""
- - "arn:aws:codepipeline:ap-northeast-1:"
- !Sub "${AWS::AccountId}:"
- !Sub "${PjName}-pipeline"
Id: !Sub "${PjName}-pipeline"
RoleArn: !GetAtt EventBridgeIAMRole.Arn
Outputs:
CodePipelineIAMPolicy:
Value: !Ref CICDHandsonCodePipelineIAMPolicy
Export:
Name: CodePipelineIAMPolicyArn
ビルドされたイメージを確認する
CloudFormationで作成されたリポジトリを確認します。
aws ecr describe-repositories --profile {プロファイル名} --output json
コマンドを実行すると以下のようにリポジトリの詳細が出力されます。
{
"repositories": [
{
"repositoryArn": "arn:aws:ecr:ap-northeast-1:{アカウント}:repository/cicdhandson",
"registryId": "{アカウントID}",
"repositoryName": "cicdhandson",
"repositoryUri": "{アカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/cicdhandson",
"createdAt": "2023-05-24T00:14:05+09:00",
"imageTagMutability": "MUTABLE",
"imageScanningConfiguration": {
"scanOnPush": false
},
"encryptionConfiguration": {
"encryptionType": "AES256"
}
}
]
}
イメージダイジェストを確認します。
aws ecr list-images --profile {プロファイル名} --repository-name cicdhandson --query "imageIds[*].imageTag" --output table
-----------------------------------------------------------------------------
| ListImages |
+---------------------------------------------------------------------------+
| sha256:2326ba7ae9bff1c55a618051b86c7d71401712898afe1a833734076962a231e5 |
+---------------------------------------------------------------------------+
イメージのタグを確認します。
aws ecr list-images --profile {プロファイル名} --repository-name cicdhandson --query "imageIds[*].imageDigest" --output table
------------
|ListImages|
+----------+
| latest |
+----------+
片付け
S3バケットを空にする
aws s3 ls --profile {プロファイル名} | grep cicdhandson | awk '{print $3}'
aws s3 rm s3://cicdhandson-bucket-{アカウント}/ --recursive --profile {プロファイル名}
中身を確認します。
aws s3 ls s3://cicdhandson-bucket-{アカウントID} --profile {プロファイル名}
aws s3 rb s3://cicdhandson-bucket-{アカウントID} --force
まとめ
これでハンズオンは以上です。上記の構成でCodeCommit にDockerfileをおくことにより
buildspec.ymlの設定に従ってCodeBuildでイメージをビルドできます。これでイメージをリポジトリにpushしたことをトリガーに
CodeDeployによるデプロイやApp Runnerへのアプリケーションデプロイができます。
Discussion