如何在 Docker 中獲取依賴子鏡像列表
1. 概述
在本教程中,我們將學習如何在 Docker 中獲取依賴子鏡像的列表。首先,我們將了解何時尋求此類信息。然後,我們將根據我們使用的 Docker 構建器來檢索它。
2. 動機
當一個 Docker 鏡像是基於另一個鏡像構建時,前者稱為子鏡像,後者稱為父鏡像。
獲取給定父級的所有子映像通常很有幫助,特別是當Docker 阻止刪除parent
時:
$ docker rmi 645c04d243f1
Failed to remove image (a3550c143d4e): Error response from daemon: conflict: unable to delete a3550c143d4e (cannot be forced) - image has dependent child images
在這裡,Docker 敦促我們刪除父級a3550c143d4e
的子映像。使用–force
標誌繞過錯誤不會有太大作用。這就是為什麼找到這些兒童圖像變得至關重要。我們將在以下部分中解決此錯誤。
查找父映像的依賴子映像取決於所使用的 Docker 構建器。自 Docker Desktop 和 Docker Engine 23.0 起, BuildKit成為Linux 映像的新默認構建器。以前的版本使用舊版構建器。我們將區分這兩個構建器。
3. 使用 Docker Legacy Builder
舊版構建器是低於 23.0 的 Docker 版本上的默認構建器。無論如何,我們可以通過使用DOCKER_BUILDKIT=0.
讓我們重現上一節中的錯誤。
3.1.案例分析
首先,我們將定義一個parent
圖像:
$ DOCKER_BUILDKIT=0 docker build -t parent -<<EOF
FROM scratch
LABEL kind=parent
EOF
值得注意的是,遺留構建器將在未來的版本中被刪除:
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
BuildKit is currently disabled; enable it by removing the DOCKER_BUILDKIT=0
environment-variable.
我們需要牢記該警告並準備遷移到 BuildKit。
接下來,讓我們根據parent
創建一個子圖像:
$ DOCKER_BUILDKIT=0 docker build -t child -<<EOF
FROM parent:latest
LABEL kind=child
EOF
現在一切就緒,讓我們檢索parent
ID:
$ docker images ls --filter reference=parent
REPOSITORY TAG IMAGE ID CREATED SIZE
parent latest a3550c143d4e 4 minutes ago 0B
嘗試刪除parent
時,我們將面臨初始錯誤:
$ docker rmi 645c04d243f1
Failed to remove image (a3550c143d4e): Error response from daemon: conflict: unable to delete a3550c143d4e (cannot be forced) - image has dependent child images
這是由於遺留構建器的工作方式造成的。它緩存用於構建其他圖像的圖像並防止它們被刪除。該信息保存在child
圖像的Parent
數據中:
$ docker inspect --format '{{json .Parent}}' child
"sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b"
遺留構建器跟踪parent
。我們將使用此信息根據parent
映像 ID 獲取從屬子映像。
3.2.獲取受撫養兒童的圖像
讓我們創建一個get_children_of.sh
腳本來獲取依賴的子圖像:
#!/bin/sh
set -e
parent=$1
echo "Dependent Child IDs of $parent "
docker inspect --format='{{.Id}} {{.Parent}}' $(docker images --all --quiet --filter since=$parent) \
awk -v parent=$parent '{ if($2 == parent) print $1 }'
讓我們來分析一下到底發生了什麼。首先,該腳本將parent
圖像 ID 作為參數。接下來,我們列出在parent
之後構建的所有圖像:
docker images --all --quiet --filter since=$parent
–all
標誌對於列出隱藏的圖像也很重要。 –quiet
標誌僅顯示圖像 ID。接下來,我們檢查這些圖像的元數據:
docker inspect --format='{{.Id}} {{.Parent}}'
docker images
命令的結果用作docker inspect
的參數。我們縮小了輸出格式,僅獲取子圖像 ID 和parent
ID。繼續,我們使用awk
打印依賴的子圖像:
awk -v parent=$parent '{ if($2 == parent) print $1 }'
在這裡,條件檢查至關重要,僅打印相關parent
ID 的子代。
最後,該腳本獲取parent
圖像a3550c143d4e
的依賴子圖像:
$ ./get_children_of.sh sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b
Dependent Child IDs of sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b
sha256:ddfecb5979b759ff56c1a730e5fc957e963cfd5bbe2108c72244b65182857bab
必須將長格式 ID 傳遞給腳本。我們可以在描述parent
圖像時通過傳遞–no-trunc
標誌來檢索它:
$ docker images ls --filter reference=parent --no-trunc
REPOSITORY TAG IMAGE ID CREATED SIZE
parent latest sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b 40 minutes ago 0B
有了這些子圖像 ID,我們可以刪除它們來解決我們最初的錯誤。
4.使用BuildKit
自 23.0 版本以來, BuildKit一直是 Linux 鏡像的默認 Docker 構建器。它對遺留構建器進行了許多改進。
特別是,它不緩存父圖像。這意味著我們不會遇到之前使用 BuildKit 時看到的錯誤。
讓我們在之前的案例研究中使用DOCKER_BUILDKIT=1
激活 Buildkit。另一種實現方法是更新/etc/docker/daemon.json
中的 Docker 守護進程配置:
{
"features":{
"buildkit":true
}
}
現在讓我們重新創建父圖像和子圖像。首先,我們將定義parent
圖像:
$ DOCKER_BUILDKIT=1 docker build -t parent -<<EOF
FROM scratch
LABEL kind=parent
EOF
接下來,讓我們根據parent
創建child
圖像:
$ DOCKER_BUILDKIT=0 docker build -t child -<<EOF
FROM parent:latest
LABEL kind=child
EOF
我們會立即註意到我們無法從child
圖像中檢索有關parent
圖像的任何信息:
$ docker inspect --format '{{json .Parent}}' child
""
BuildKit 不設置Parent
字段。刪除父圖像不會導致任何錯誤。
$ docker rmi sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b
Untagged: parent:latest
Deleted: sha256:a3550c143d4e25331167344afeb842b21780ef7d3f20dabe748390d89c16cf8b
無論構建器如何,我們始終可以從系統中刪除懸空和未使用的圖像:
$ docker image prune --all --force
當我們不需要確認時, –force
標誌很有用。
5. 結論
在本文中,我們了解瞭如何在 Docker 中獲取依賴子鏡像的列表。首先,我們討論了它的主要用例。然後,我們學習瞭如何根據所使用的 Docker 構建器來實現結果。