
私は長い間、中間コンテナを使用して Docker でアプリを構築してきました。たとえば、myapp:base
すべてのコア ファイルをコピーしたビルドを作成します。
FROM ubuntu:17.10
ADD app /app
さて、メインコンテナはmyapp:release
これで簡単に作成できます
FROM myapp:base
ADD app /app
ディレクトリ内のいくつかのファイルが変更されapp
、小さな追加レイヤーが作成される可能性があります。
しかし最近、この最終版ADD
ではレイヤーがかなり大きくなり、Docker のアップデートに関連しているのではないかと考えています (私は Docker バージョン 18.02.0-ce、ビルド fc4de44 を使用しています)
Docker が違いを認識する方法に何か変更がありましたか? レイヤー内の少数の更新されたファイルだけを含む効率的なビルドに戻すにはどうすればよいですか?
再現する手順:
# make a dummy dir with a 64kb file in it
mkdir -p files
truncate -s 64k files/64k.file
# base container has a copy of the files
cat << EOF > Dockerfile.base
FROM ubuntu:16.04
COPY files/ /root/
EOF
# derived container should just have any updates
cat << EOF > Dockerfile.derived
FROM q899941:base
COPY files/ /root/
EOF
# build them....
docker build --file Dockerfile.base -t q899941:base .
docker build --file Dockerfile.derived -t q899941:derived .
# now let's review the layers
docker history q899941:derived
この結果を得る
IMAGE CREATED CREATED BY SIZE
4e1eb5168d55 Less than a second ago /bin/sh -c #(nop) COPY dir:8e20ede288278c71e… 65.5kB
022626ac5cf0 Less than a second ago /bin/sh -c #(nop) COPY dir:8e20ede288278c71e… 65.5kB
0458a4468cbc 5 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 5 weeks ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B
<missing> 5 weeks ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$… 2.76kB
<missing> 5 weeks ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B
<missing> 5 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 745B
<missing> 5 weeks ago /bin/sh -c #(nop) ADD file:a3344b835ea6fdc56… 112MB
ファイルが変更されていないにもかかわらず、最上位レイヤーは 64kb です。
答え1
これは既知の問題しかし、十分な数の人々が関心を持っているわけではありません。
- docker commit に頼らずに、変更されたファイルのみを新しいレイヤーとして docker イメージに追加する方法はありますか?同じ内容を扱う StackOverflow の質問です。
- オーバーレイストレージドライバーでは期待した動作が機能したようですが、システムアップデート後に、変更されたファイルだけでなくすべてのファイルをレイヤーにコピーするoverlay2を使用するようになりました。
- 1 つの解決策はオーバーレイに戻すことですが、現時点ではかなり非推奨になっているようです。「diff」レイヤーを構築する別の方法については、こちらで詳しく説明しています。
私は結局、コメントバグレポート内:
#clean up any previous attempt...
docker rm -f uniquename 2> /dev/null
# now take your base container, mount the updated dir as /src
# then rsync from /src to the target dir - only updated files will
# actually be written, and we use --delete to ensure removed files are
# taken out...
docker run --name uniquename \
-v ~/repo/mycode:/src \
${REPO}/${IMAGE}:${BASE} \
rsync -ar --no-owner --no-group \
--exclude-from '/src/.dockerignore' --delete \
/src/ /app/
# we can commit that updated container with a tag
docker commit uniquename ${REPO}/${IMAGE}:${NEW_TAG}
もう 1 つ、このソリューションは、CMD
コンテナーのデフォルトの起動コマンドを提供する既存のものを消去するようです。そのため、この diff レイヤーを追加した後、上記の 'diff' ビルドからコンテナーを作成するための別の Dockerfile を追加し直しましたCMD
。