CicleCIでDockerイメージを再利用する - かまたま日記3
こちらの記事の最新版です。
現在CircleCIはバージョン2で、Docker Layer Cachingという機能がありますが、残念ながら追加のフィーが必要です。というわけで、会社とかで使っててフィーを払える方はそちらを使うとして、個人のOSS活動などで払うのが厳しい方用に普通にCircleCI 2.0のファイルのキャッシュ機能を使った方法を解説します*1
前回に比べて以下の点が変わっています
- GoのようにMulti stage buildを使って多段ビルドを行う前提 (最初のビルドのステージは
as buider
でbuilderという名前がついてます)
- Docker image を完全に再利用はしないで中間イメージを再利用する (
docker build
は毎回やる)
docker save
後のtarファイルを更にgzに圧縮してリストアの時間短縮を図る
注意として、自分の環境では、数百メガのキャッシュをload cacheとsave cacheするので2~3分かかるのでキャッシュを使うことによって、それ以上短縮出来なければ、総時間は変わらないか悪くなる可能性もあります。
1. キャッシュ用のディレクトリとキャッシュキーを決める
ここではディレクトリは /home/circleci/docker-cache
、キャッシュキーは毎回変えたいので {{ .Branch }}-{{ .Revision }}
を使います
- restore_cache:
keys:
- v1-docker-{{ .Branch }}-{{ .Revision }}
- v1-docker-{{ .Branch }}-
- v1-docker-
- save_cache:
paths:
- "/home/circleci/docker-cache"
key: v1-docker-{{ .Branch }}-{{ .Revision }}
2. イメージをビルドする
今回は builder
のイメージを取っておきたいので、builderの部分は別にビルドしてbuilerタグを付けています。
IMAGE_NAME=my_app
CACHE_FROM="--cache-from ${IMAGE_NAME}:builder --cache-from ${IMAGE_NAME}"
docker build --pull ${CACHE_FROM} --target builder -t ${IMAGE_NAME}:builder .
docker build --pull ${CACHE_FROM} -t ${IMAGE_NAME} .
3. イメージを保存する
docker save
で保存するイメージを docker history
コマンドで取得します。 builder
を取ってるのがミソです。
mkdir -p /home/circleci/docker-cache
image_ids=$(docker history -q my_app:builder | grep -v '<missing>')
docker save ${image_ids} | gzip > ${DOCKER_CACHE_FILE}
4. イメージを展開する
Gzip化しているのでgunzipコマンドで解答して docker load
に渡します
if [ -f /home/circleci/docker-cache/image.tar.gz ]; then
gunzip -c /home/circleci/docker-cache/image.tar.gz | docker load
fi
全体
キャッシュファイルのパスを変数に入れて、以下のような感じになります。関係ない部分*2は略してます。
version: 2
jobs:
build:
environment:
DOCKER_CACHE_FILE: /home/circleci/docker-cache/image.tar.gz
steps:
- checkout
- restore_cache:
keys:
- v1-docker-{{ .Branch }}-{{ .Revision }}
- v1-docker-{{ .Branch }}-
- v1-docker-
- run: |
name: Load Docker cache
command: |
if [ -f ${DOCKER_CACHE_FILE} ]; then
gunzip -c ${DOCKER_CACHE_FILE} | docker load
fi
- run: |
name: Docker build
command: |
IMAGE_NAME=my_app
CACHE_FROM="--cache-from ${IMAGE_NAME}:builder --cache-from ${IMAGE_NAME}"
docker build --pull ${CACHE_FROM} --target builder -t ${IMAGE_NAME}:builder .
docker build --pull ${CACHE_FROM} -t ${IMAGE_NAME} .
- run:
name: Save Docker cache
command: |
mkdir -p $(dirname ${DOCKER_CACHE_FILE})
image_ids=$(docker history -q my_app:${t} | grep -v '<missing>')
docker save ${image_ids} | gzip > ${DOCKER_CACHE_FILE}
- save_cache:
paths:
- ${DOCKER_CACHE_FILE}
key: v1-docker-{{ .Branch }}-{{ .Revision }}