ふと、AWS CodeBuild で大きめのコンテナイメージを作成する機会があったので、どーにかして処理時間や転送量を少なくできないかなと、考える前に、基本的な処理時間を計測してみました。
んでそれに関わる細かい情報をまとめて、さぁどうするかというと、別にどうもしない。けど大切な土台データだと思います多分。
検証する前の経緯
十数GB ~ 数十GB クラスの Git データを、丸っとコンテナイメージに収めて、WEBサーバーコンテナと並列してECSタスクを起動して、ファイル共有して静的コンテンツとして返させる。みたいなヤツやろうとしていて、デカすぎてヤバそうという印象から、git clone した master を含むベースイメージを定期的に更新して、短期的には差分だけ pull する形で最新イメージを作る、とかしたら無駄がなさそうじゃね?って思ったものの、
その仕込みとか構成の複雑さとか、あまりクールじゃねぇなと思い直し、まずはそもそもデータがデカいとどれくらいマズそうなのか、マズくなさそうなのか具合を知ることにしました。
検証内容
今回は CodeCommit に、0 ~ 16GB の空ファイルを入れて、それを CodeBuild で source に指定し、buildspec で docker build、ECR へ push という流れです。で、処理時間を確認できるのでポイントをまとめていきます。空データ
dd で作るだけです。実際にはもっと細かいファイル群になって、転送速度とか落ちると思うので、最速でこれって感覚でやってます。
1 |
dd if=/dev/zero of=tmp/dummy01 bs=1M count=1024 |
buildspec
普通の内容なので、無駄な出力消してこんな感じで。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
version: 0.2 phases: install: commands: pre_build: commands: - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION) build: commands: - DOCKER_BUILDKIT=1 docker build --rm --no-cache -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: - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG |
Dockerfile
DOCKER_BUILDKIT 有効にしているので、こう。
1 2 3 4 5 6 7 8 9 10 |
# syntax = docker/dockerfile:experimental FROM alpine:latest WORKDIR /static ADD . . RUN chmod +x entrypoint.sh ENTRYPOINT /asset/entrypoint.sh |
entrypoint はこんだけ。
1 2 3 4 |
#/bin/sh echo "Start tail -f" tail -f /dev/null |
CodeBuild
CodeBuild 以外に ECR, CodeCommit もそうですが、terraform で作成しています。本件とたいして関係ないので省略。管理画面で、手動で開始をポチって、結果をフェーズ詳細で確認します。
データ容量と処理時間の関係
では、細かいことは後回しにしてデータをまとめます。コンピューティングタイプ
Build 処理のために動かす Linux はタイプがこんな感じで最初は一番小さい general1.small (vCPU=2, mem=3GB) でやろうとしたら、データ容量 1GBの 時点で download source のフェーズで out of memory が出ちゃったので、1つ上の general1.medium (vCPU=4, mem=7GB) で全部やりました。ちなみに非VPCです。
計測データ
Total | Provisioning | Download | Build | Push | |
00 GB | 01:15 | 00:57 | 00:01 | 00:11 | 00:01 |
01 GB | 01:34 | 00:50 | 00:26 | 00:48 | 00:07 |
02 GB | 03:35 | 00:51 | 00:44 | 01:28 | 00:23 |
04 GB | 05:22 | 00:42 | 01:10 | 02:50 | 00:33 |
06 GB | 06:24 | 00:05 | 01:18 | 04:06 | 00:49 |
08 GB | 08:12 | 00:05 | 01:29 | 05:27 | 01:05 |
10 GB | 11:16 | 00:54 | 02:08 | 06:49 | 01:30 |
12 GB | 12:20 | 00:42 | 02:17 | 08:05 | 01:47 |
14 GB | 14:53 | 00:06 | 02:45 | 09:27 | 01:52 |
16 GB | 15:18 | 00:05 | 02:14 | 10:44 | 02:09 |
MB/s 概算
平均 | 範囲 | |
Total | 016 MB/s | 012 ~ 018 MB/s |
Download | 085 MB/s | 060 ~ 120 MB/s |
Build | 024 MB/s | 022 ~ 025 MB/s |
Push | 115 MB/s | 111 ~ 125 MB/s |
考察
容量と速度の程度
CodeCommit から CodeBuild への Download が 80 MB/s 以上、Docker Build はただの COPY だけなのでアレだけど 25 MB/s までは出そう、
CodeBuild から ECR への Push が 110 MB/s 以上、
とすると、ダウンロード速度としては十分以上、
docker build の処理時間も悪くない、
ECR への転送はかなり速め、
ということで、これだけみた満足度は高めになりそうです。
Gitソースのダウンロードに工夫をするべきか否か
仮に、データの大半はすでに ECR に用意して、Git からは差分のみ取得するような工夫をしたとして、10GB が 120秒 必要なところを、
差分だけにすることで 10秒 くらいになったとすると、
110秒は Download フェーズが縮むことにはなります。
ふむ……と思いきや!Build フェーズで結局は大半データを含むイメージのダウンロードがあるわけで、これだと転送が CodeCommit or ECR になるだけで、工夫とは言い難い。Git が外部サービスだったら、多少は意義があるかもしれないけど。
データファイルの細かさや総容量、大半データの保管場所の転送速度、によって時間短縮の効果が変わりそうなのでやってみないとって部分はあるものの、印象ではほぼボツ案。これもAWS内での転送速度がある程度速いおかげ、ということもあるんですがなんかくやちぃ。
補足情報
キャッシュ
Build 時にキャッシュの機能があるので、当然検討するのですが、>キャッシュ作成後のビルドでは、コミット間の変更のみプルされます
ってーのに、少しずつファイルを増やしても、ダウンロード時間が比例して増えていく一方だったし、ただの再試行でも時間が変わらないしで、
>Git リポジトリ (GitHub、GitHub Enterprise、または Bitbucket) を使用していない場合、このオプションは無視
やっぱ CodeCommit はダメなのねってことでした。そんなに AWS 内での処理速度に自信があんのなら、正面切って使ったろーじゃねーかという気分です。
タイムアウト
CodeBuild の処理時間タイムアウトに、timeoutInMinutes 、terraform でいうところの build_timeout があるのですが、10分に設定していたときに、POST_BUILD の push で TIMEOUT したことがありました。Total 時間としては 11:27 でエラーになったので、分かりづらかったのですが、Build フェーズだけとかじゃなく、普通に全てのフェーズを合わせて、の制限時間と考えてよさそうです。設定時間を超えた Total 時間になるのは、色々停止したりのお片付けタイムも含んでいるからかな、と想像しておきます。
コンピューティングタイプ
Out of memory
メモリ3GB にて データ1GB で out of memory が出たので、まぁそんなもんなのかなと 7GB に上げたら、データ16GB でもエラーが出ずに終わったのはなんだったのか。という素朴な疑問が残りました。まぁこのへんの処理は本番と密に繋がるわけじゃないから、エラーが出たら上位に変更する、くらいで良いとは思いますけども。
CPUモデル
一応、CPUとメモリを表示してチェックしてみましたが、vCPU と メモリは当然ながら表記通り。CPUモデルについては、1回ずつしか見てないですが、いつもどおりランダムガシャっぽいですね。build.general1.small | Intel(R) Xeon(R) CPU E5-2666 v3 @ 2.90GHz |
build.general1.medium | Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz |
build.general1.large | Intel(R) Xeon(R) Platinum 8275CL CPU @ 3.00GHz |
build.general1.2xlarge | Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz |
一番大きなスペックだけディスクが SSD だからかなんなのか、ローカルキャッシュは使えないようなので、NO_CACHE で立ち上げました。
どれも 1vCPU あたりの性能は基本的に近いということは、Build 処理としては単純なCPUパワーで速くするという選択はないということで。docker-compose の –parallel とか BuildKit で マルチステージビルド などの並列化を使える場合なら、vCPU数を気にして調整するのが楽しそう。
Pipeline Source
Pipeline から Build を実行した場合、必須である Source ステージの source が使われるのですが、Pipeline の Source ステージの段階でソースをダウンロードしてしまうので、CodeBuild の方の Download フェーズでは 4秒 とかでスルーされます。という豆。
料金
費用はこんな感じ。general1.medium が 0.01 USD/minute なので、超大雑把に 10分 Build したら 10円!ということで身の引き締まる思いです。
ECR への push は無料なのでいいとして、CodeCommit も転送に関する費用説明がないので、無料。
ということで、Build Total Time の短縮を頑張れば、四方よろしく収まる、ということでよさげですね。
Git は色んな場所におけるのでアレですが、AWSでコンテナを動かすとなると ECR が基本になって、そのため CodeBuild がセットでほぼ必須になるところがあるので、こーゆーとこ抑えておくと
,. -‐”~´ _,/ ) _,. -‐ミミ
| ̄ ̄ ̄`~/ヽヽ_ノ____,,,._-=’_二-ヘミミ/
ヽ;;;;;;;;;;;;/,_ レ’<弋;;;ッ、 ヽ_,/,./i;;;;;;ラヽ .//|
`'''''/ `ヽY/ . ̄ ̄/| /ヽ `'―'''´‐ !/ |
/ ノ! !_ _;;;| | | |;';;; ,| |//./ 安心するんじゃ…
l´/´‐'''‐'-‐'''~ヽ' ̄ ヽ__i'''ヽ__ノ  ̄| | |/
.// (´`´ _,.ノ彡彡 ,`ヾ''´'´ミミ_ / //ミミ ポルナレフ
/ / '‐''~ )/''‐-----‐''~´|川 iミ/川ヽ
/ / j‐' _,. く :;;;,,,,,,,,,,,,,, /川 /|川
./ / '´ ノ彡〃川川ヽミ川,.-'´/lll/
/ / )) /ノ〃川川川ヽ,.-'´ |/
,.-''''~~~''-、 ノ~´ ヽ,,,,,,__/ /
| ̄ ̄ ̄`~/ヽヽ_ノ____,,,._-=’_二-ヘミミ/
ヽ;;;;;;;;;;;;/,_ レ’<弋;;;ッ、 ヽ_,/,./i;;;;;;ラヽ .//|
`'''''/ `ヽY/ . ̄ ̄/| /ヽ `'―'''´‐ !/ |
/ ノ! !_ _;;;| | | |;';;; ,| |//./ 安心するんじゃ…
l´/´‐'''‐'-‐'''~ヽ' ̄ ヽ__i'''ヽ__ノ  ̄| | |/
.// (´`´ _,.ノ彡彡 ,`ヾ''´'´ミミ_ / //ミミ ポルナレフ
/ / '‐''~ )/''‐-----‐''~´|川 iミ/川ヽ
/ / j‐' _,. く :;;;,,,,,,,,,,,,,, /川 /|川
./ / '´ ノ彡〃川川ヽミ川,.-'´/lll/
/ / )) /ノ〃川川川ヽ,.-'´ |/
,.-''''~~~''-、 ノ~´ ヽ,,,,,,__/ /