
很長一段時間以來,我使用 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 映像中 - 而無需求助於 docker commit?是一個涵蓋相同基礎的 StackOverflow 問題。
- 似乎我期望的行為與覆蓋存儲驅動程式一起工作,但在一些系統更新之後,我開始使用overlay2,它將所有文件複製到一個層中,而不僅僅是更改的文件
- 雖然一種解決方案將恢復為覆蓋,但目前它似乎已被強烈棄用。此處詳細介紹了建造「差異」層的替代方法
我最終做了其中一個中提到的一件簡單的事情評論在錯誤報告中:
#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}
另一件事 - 該解決方案似乎消除了為CMD
我的容器提供預設啟動命令的現有解決方案。因此,在添加此 diff 層後,我有另一個 Dockerfile 來從上面的“diff”構建創建一個容器,並添加CMD
回來。