Slide 1

Slide 1 text

DockerCIビルドを 一歩先へ Buildkitを 運用前提で 試食してみた 2019/06/14 タナカヒロキ @dabits

Slide 2

Slide 2 text

自己紹介 { id: ‘dabits’, name: ‘タナカヒロキ’, company: ‘株式会社エイチームライフスタイル’, division: ‘CTO室 (like a SRE)’, hobby: ‘アニソンDJ’, }

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

前回のあらすじ

Slide 5

Slide 5 text

この数ヶ月、 KPIにCI/CDの時間を設定して ビルドの高速化を してきました。

Slide 6

Slide 6 text

その一環でDocker buildの チューニングを 行ってきました。

Slide 7

Slide 7 text

multi stage buildを使って やっと早くなってきたぞ!

Slide 8

Slide 8 text

そんなとき

Slide 9

Slide 9 text

DockerCon ‘19でとある発表が

Slide 10

Slide 10 text

https://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices

Slide 11

Slide 11 text

https://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices

Slide 12

Slide 12 text

今まで調べたこと 全部書いてあるやんけ

Slide 13

Slide 13 text

今からビルドを早くしたい人

Slide 14

Slide 14 text

https://www.slideshare.net/Docker/dcsf19-dockerfile-best-practices

Slide 15

Slide 15 text

絶対読んだ方がいいですよ! 全部詰まってます!

Slide 16

Slide 16 text

というお話でした。

Slide 17

Slide 17 text

その次の改善ポイント

Slide 18

Slide 18 text

昨年発表された 「Buildkit」を使った高速化

Slide 19

Slide 19 text

https://docs.google.com/presentation/d/1fy_xBVY15fNEOs0 DbuY79wKmp_POBBHAeZaGCUNQi-M/edit#slide=id.g3b87 b4748c_0_0

Slide 20

Slide 20 text

が、今回のお話です。

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Buildkit導入対象 ● Ruby on rails ● Assets precompileを使っている ● Webpacker compileも使っている(移行期間中, 併用期)

Slide 23

Slide 23 text

早速Buildkit対応 していきましょう

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

Buildkitでの高速化ポイント ● 並列ビルド ○ multi stage buildになっていれば空気を読んで並列に ● キャッシュマウント ○ RUNの頭に--mount-type=cache,target=/hoge command...と書くと該当のディレクトリをマウントして キャッシュしてくれる

Slide 26

Slide 26 text

今回の並列ビルド対象 ● 1つ目のペア : bundle install vs yarn install ● 2つ目のペア : assets precompile vs webpack compile

Slide 27

Slide 27 text

今回のキャッシュマウント対象 ● apk install ● bundle install ● yarn install ● assets precompile ● webpack compile

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

bundleとyarnの 並列インストール

Slide 30

Slide 30 text

FROM ruby:2.5.5-alpine3.8 as builder RUN apk update && apk upgrade && \ apk add --no-cache git mysql-dev nodejs nodejs-npm libxml2-dev imagemagick-dev && \ npm install -g yarn WORKDIR /app COPY Gemfile Gemfile.lock ./ RUN bundle install -j4 --without development test deployment COPY package.json yarn.lock ./ RUN yarn install --production --frozen-lockfile

Slide 31

Slide 31 text

# syntax = docker/dockerfile:experimental FROM ruby:2.5.5-alpine3.8 as base-builder RUN apk update && apk upgrade && \ apk add --no-cache git mysql-dev nodejs nodejs-npm libxml2-dev imagemagick-dev && \ npm install -g yarn WORKDIR /app FROM base-builder as bundle-builder COPY Gemfile Gemfile.lock ./ RUN bundle install -j4 --without development test deployment FROM base-builder as yarn-builder COPY package.json yarn.lock ./ RUN yarn install --production --frozen-lockfile

Slide 32

Slide 32 text

assetsとwebpackの 並列コンパイル

Slide 33

Slide 33 text

... COPY ./app/assets /app/app/assets RUN bundle exec rails assets:precompile ... COPY frontend ./frontend RUN yarn run webpack --config config/webpack/production.js

Slide 34

Slide 34 text

FROM base-builder as modules-builder COPY --from=bundle-builder /app/Gemfile /app/Gemfile.lock ./ COPY --from=yarn-builder /app/package.json /app/yarn.lock ./ FROM modules-builder as assets-builder ... COPY ./app/assets /app/app/assets RUN bundle exec rails assets:precompile FROM modules-builder as webpack-builder ... COPY frontend ./frontend RUN yarn run webpack --config config/webpack/production.js

Slide 35

Slide 35 text

FROM ruby:2.5.5-alpine3.8 as release … COPY --from=builder /app/vendor/bundle/ /app/vendor/bundle/

Slide 36

Slide 36 text

FROM ruby:2.5.5-alpine3.8 as release … COPY --from=modules-builder /app/vendor/bundle /app/vendor/bundle COPY --from=webpack-builder /app/public /app/public COPY --from=assets-builder /app/public /app/public

Slide 37

Slide 37 text

キャッシュマウント

Slide 38

Slide 38 text

... RUN apk update && apk upgrade && \ apk add --no-cache git mysql-dev nodejs nodejs-npm libxml2-dev imagemagick-dev && \ npm install -g yarn WORKDIR /app

Slide 39

Slide 39 text

... RUN --mount=type=cache,target=/var/cache/apk \ apk update && apk upgrade && \ apk add --no-cache git mysql-dev nodejs nodejs-npm libxml2-dev imagemagick-dev && \ npm install -g yarn WORKDIR /app

Slide 40

Slide 40 text

... FROM base-builder as bundle-builder COPY Gemfile Gemfile.lock ./ RUN bundle install -j4 --without development test deployment FROM base-builder as yarn-builder COPY package.json yarn.lock ./ RUN yarn install --production --frozen-lockfile

Slide 41

Slide 41 text

... FROM base-builder as bundle-builder COPY Gemfile Gemfile.lock ./ RUN --mount=type=cache,target=/app/tmp \ bundle install --path=/app/tmp/bundle -j4 --without development test deployment FROM base-builder as yarn-builder COPY package.json yarn.lock ./ RUN --mount=type=cache,target=/app/tmp \ --mount=type=cache,target=/usr/local/share/.cache/yarn \ yarn install --modules-folder=/app/tmp/node_modules --production --frozen-lockfile

Slide 42

Slide 42 text

FROM base-builder as modules-builder COPY --from=bundle-builder /app/Gemfile /app/Gemfile.lock ./ COPY --from=yarn-builder /app/package.json /app/yarn.lock ./

Slide 43

Slide 43 text

FROM base-builder as modules-builder COPY --from=bundle-builder /app/Gemfile /app/Gemfile.lock ./ COPY --from=yarn-builder /app/package.json /app/yarn.lock ./ RUN --mount=type=cache,target=/app/tmp \ mkdir -p /app/vendor && \ cp -r /app/tmp/bundle /app/vendor/bundle && \ cp -r /app/tmp/node_modules /app/node_modules

Slide 44

Slide 44 text

.. COPY ./app/assets /app/app/assets RUN bundle exec rails assets:precompile ... COPY frontend ./frontend RUN yarn run webpack --config config/webpack/production.js

Slide 45

Slide 45 text

.. COPY ./app/assets /app/app/assets RUN --mount=type=cache,target=/app/tmp \ mkdir -p /app/tmp/assets /app/public && mv /app/tmp/assets /app/public/assets && \ bundle exec rails assets:precompile && \ cp -r /app/public/assets /app/tmp/assets ... COPY frontend ./frontend RUN --mount=type=cache,target=/app/tmp \ mkdir -p /app/tmp/packs /app/public && mv /app/tmp/packs /app/public/packs && \ yarn run webpack --config config/webpack/production.js && \ cp -r /app/public/packs /app/tmp/packs

Slide 46

Slide 46 text

結果

Slide 47

Slide 47 text

結果 ● Dockerfile : 約140行! ● ビルド時間 ○ 初回フルビルド : 853s→683s (x1.25 Faster) ○ packageを追加 : 844s→294s (x2.87 Faster) ○ assetsのみを更新 : 482s→208s (x2.32 Faster) ※AWS EC2 t3.small : 2Core, Memory 2GB, Swap 4GBで検証

Slide 48

Slide 48 text

ここまでが ローカル上でのお話

Slide 49

Slide 49 text

いかにしてCIに組み込むか

Slide 50

Slide 50 text

CIに組み込む際のポイント ● Docker layer cacheを保持できること ○ buildkitは--cache-fromが使えない ○ docker layer cacheに頼らざるを得ない ● mountしたデータを保持できること ○ dindで都度立ち上げるとmountデータが消えてしまう

Slide 51

Slide 51 text

考えうる選択肢 ● dockerdを共通で使う・・・✗ ○ 並列で複数サービスのビルドが走ると詰まる ● dindの/var/lib/dockerを保持させる・・・✗ ○ 実装が大変すぎる ● buildkit対応しているクラウドサービスを使う・・・△ ○ AWS:cacheが途中でexpire, GCP:非対応, CircleCIなら

Slide 52

Slide 52 text

うちはGitlab-CIを使っているので

Slide 53

Slide 53 text

諦めました

Slide 54

Slide 54 text

みんなどうしてるんだろう?

Slide 55

Slide 55 text

今後試してみようと思うこと ● 1サービス1dockerdをCI用に立てたままにする ○ pros : 手軽にキャッシュを保持できる ○ cons : サービス増えるたびにdockerd増やすの...? ● Buildkitを捨ててGCP+Kanikoにする ○ pros : CI周りの面倒なことを考えなくて済む ○ cons : 並列vsKanikoの最適化はどれだけ差があるか?

Slide 56

Slide 56 text

と、この資料 書いている途中に

Slide 57

Slide 57 text

https://medium.com/nttlabs/buildkit-on-kubernetes-d37a0 3150192

Slide 58

Slide 58 text

事例出てきたやんけ

Slide 59

Slide 59 text

NTT須田さんいつも ありがとうございます!

Slide 60

Slide 60 text

No content

Slide 61

Slide 61 text

まとめ ● Buildkitでビルドを高速化するには ○ 並列ビルド+キャッシュマウント ● CIのフローに組み込むには ○ 規模が小さければdockerd使い回しでOK ○ 規模が大きければお金払うor実装する必要ありかも ● Dockerfile Best Practices はバイブル ● 最近のBuildkit事情はNTT須田さんの資料をみる

Slide 62

Slide 62 text

ありがとうございました

Slide 63

Slide 63 text

Any Questions?