Docker COPY/ADD は差異をコピーしなくなりましたか?

Docker COPY/ADD は差異をコピーしなくなりましたか?

私は長い間、中間コンテナを使用して 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

これは既知の問題しかし、十分な数の人々が関心を持っているわけではありません。

私は結局、コメントバグレポート内:

#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

関連情報