課題
元々、PlayFrameworkアプリケーション(Scala)のビルドを、Docker ImageのビルドからECRへのImage Push、EKSへのデプロイまでをSkaffoldに内包する形で行なっていました。
これらをGithubへのTagプッシュを契機にCodeBuild上で動かしていたのですが、新たに機械学習アプリケーション(Python)が加わり、ビルド時間が12分から20分まで伸びてしまったことで遅さが目についたので、改善に踏み切りました。
環境
- プラットフォーム: EKS(PlayFramework + Python)
- ビルド環境: CodeBuild + Skaffold
改善施策
改善施策として以下の二点について対応しました。
- 並列ビルドの導入
- ビルドキャッシュの有効化
並列ビルドの導入
Skaffoldではデフォルトでは並列度1、直列でビルドが行われるのですが、Concurrencyを設定することで並列度を増やすことができます。今回の場合はビルドする対象が1から2に増えたので、2を設定しました。(当然のことながら、それ以上増やしてもビルド時間は向上しませんでした。)
apiVersion: skaffold/v2alpha3
kind: Config
build:
artifacts:
- image: scala/api
custom:
buildCommand: ./build.sh api
dependencies:
paths:
- docker/api
- image: python/ml
custom:
buildCommand: ./build.sh ml
dependencies:
paths:
- docker/ml
local:
concurrency: 2
tagPolicy:
gitCommit: {}
deploy:
kustomize: {}
- name: development
deploy:
kustomize:
paths:
- kubernetes/development
patches:
- op: replace
path: /build/artifacts/0/image
value: 000000000000.dkr.ecr.us-east-1.amazonaws.com/scala/api
- op: replace
path: /build/artifacts/1/image
value: 000000000000.dkr.ecr.us-east-1.amazonaws.com/python/ml
- name: development
deploy:
kustomize:
paths:
- kubernetes/staging
patches:
- op: replace
path: /build/artifacts/0/image
value: 111111111111.dkr.ecr.us-east-1.amazonaws.com/scala/api
- op: replace
path: /build/artifacts/1/image
value: 111111111111.dkr.ecr.us-east-1.amazonaws.com/python/ml
参考:https://skaffold.dev/docs/references/yaml/
これを設定したことで20分→12分、単一のアプリケーションをビルドしていた時点まで改善しました。
ビルドキャッシュの有効化
次にCodeBuildのキャッシュの有効化を行いました。元々、Dockerレイヤーキャッシュは有効化していたのですが、今回、新たにカスタムキャッシュを有効化しました。カスタムキャッシュはbuildspec.ymlで指定した特定のディレクトリ以下をキャッシュする機能になります。
CFnテンプレートは以下のようになります。- LOCAL_CUSTOM_CACHE
が追加した設定になります。
CodeBuildProject:
Type: 'AWS::CodeBuild::Project'
Properties:
Artifacts:
Type: 'CODEPIPELINE'
BadgeEnabled: false
Cache:
Modes:
- LOCAL_DOCKER_LAYER_CACHE
- LOCAL_CUSTOM_CACHE
Type: LOCAL
Description: !Sub 'created by ${AWS::StackName}'
Name: !Ref ApplicationName
ServiceRole: !GetAtt IAMRoleCodeBuild.Arn
Environment:
ComputeType: 'BUILD_GENERAL1_SMALL'
Image: 'aws/codebuild/standard:3.0'
ImagePullCredentialsType: 'CODEBUILD'
EnvironmentVariables:
- Name: 'EKS_CLUSTER_NAME'
Value: !Ref EKSCluster
Type: 'PLAINTEXT'
- Name: 'ENVIRONMENT_NAME'
Value: !Ref EnvironmentName
Type: 'PLAINTEXT'
PrivilegedMode: true
Type: 'LINUX_CONTAINER'
Source:
Type: 'CODEPIPELINE'
TimeoutInMinutes: 30
buildspec.ymlにはsbtのビルドキャッシュを利用するため、 /root/.sbt/**/*
、/root/.ivy2/**/*
を追加し、Skaffoldのキャッシュを利用するため、/root/.skaffold/**/*
を新規に追加しました。Skaffoldでは、skaffold.ymlに記載した dependencies
に指定したディレクトリ配下の依存関係を元にキャッシュを生成します。(今回記載したskaffold.ymlはあくまでサンプルであり、実際にはDockerfile以外にも指定する必要があります。)
version: 0.2
phases:
install:
runtime-versions:
docker: 18
java: openjdk8
commands:
## Install kubectl
- wget -O /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.14.7/bin/linux/amd64/kubectl
- chmod +x /usr/local/bin/kubectl
## Install kustomize
- wget -O /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v3.2.3/kustomize_kustomize.v3.2.3_linux_amd64
- chmod +x /usr/local/bin/kustomize
## Install skaffold
- wget -O /usr/local/bin/skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
- chmod +x /usr/local/bin/skaffold
pre_build:
commands:
- aws eks update-kubeconfig --name ${EKS_CLUSTER_NAME} --region ${AWS_DEFAULT_REGION}
- aws eks get-token --cluster-name ${EKS_CLUSTER_NAME}
- $(aws ecr get-login --no-include-email --region ${AWS_DEFAULT_REGION})
build:
commands:
- skaffold run -p ${ENVIRONMENT_NAME}
cache:
paths:
- '/root/.sbt/**/*'
- '/root/.ivy2/**/*'
- '/root/.skaffold/**/*'
この設定を行なった結果、ビルド時間が3分40秒程度に改善し、アプリケーションを変更せずにk8sマニフェストファイルの変更のみ適用する場合は30秒程度まで改善することができました。