Learning Objectives
- 分辨 registry、repository(倉庫)與 tag(標籤),看懂映像檔的完整名稱
- 分辨官方映像檔與社群使用者的映像檔,判斷可不可以信任
- 用 docker search 與 docker image pull 搜尋、下載指定版本的映像檔
- 說明映像檔的分層(layer)與共用,用 image ls、history、rm 管理本機映像檔
映像檔從哪裡來
前兩課跑 hello-world、ubuntu:24.04 時,Docker 都會自動「下載映像檔」。這些映像檔放在哪裡?
| 名詞 | 比喻 | 說明 |
|---|---|---|
| Registry | 圖書館 | 存放映像檔的服務。預設的公用 registry 是 Docker Hub(hub.docker.com),由 Docker 公司經營 |
| Repository(倉庫) | 書架上的一套書 | 同一個軟體的映像檔放在同一個倉庫,例如 ubuntu 倉庫 |
| Tag(標籤) | 第幾版 | 區分同一個倉庫裡的不同版本,例如 24.04、22.04 |
所以 ubuntu:24.04 的意思是「ubuntu 倉庫裡標籤為 24.04 的映像檔」。它的完整名稱其實是:
docker.io/library/ubuntu:24.04
└registry┘└命名空間┘└倉庫┘└標籤┘
Docker Hub(docker.io)是預設值,官方映像檔的命名空間是 library,平常都省略不寫。
Docker Hub 不是唯一的 registry:GitHub 有 GitHub Container Registry(ghcr.io)、Red Hat 有 Quay(quay.io),
各家雲端也有自己的 registry;registry 的程式本身是開放原始碼,學校或公司也可以自己架一個私有的。
用別的 registry 時,名稱前面要寫上它的網址,例如 quay.io/jupyter/base-notebook(下一課會用到)。
官方映像檔與社群映像檔:可以信任嗎
Docker Hub 上的倉庫分成兩種命名方式:
| 類型 | 名稱長相 | 誰維護 | 信任程度 |
|---|---|---|---|
| 官方映像檔(Official Images,top-level) | 只有倉庫名稱:ubuntu、python、mysql |
Docker 公司與該軟體的維護團隊共同管理(例如 Fedora 團隊提供 fedora) |
經過審查,持續更新安全修補 |
| 使用者倉庫 | 使用者名稱/倉庫名稱:ncuedu/static_web |
任何註冊 Docker Hub 的人 | 沒有經過 Docker 驗證,要自己判斷 |
網站上還會看到 Docker Official Image 與 Verified Publisher(經驗證的軟體公司)等標章。
映像檔裡的程式會在你的電腦上執行,挑選社群映像檔前先檢查:
- 有沒有對應的官方映像檔或驗證過的發行者?有就優先用
- 維護者是誰、有沒有公開原始碼或 Dockerfile、最近一次更新是什麼時候
- 下載次數與星星數只能參考,不代表安全
- 不要拉來路不明、說明空白的映像檔來處理帳號密碼或重要資料
搜尋映像檔
兩種方法:
- 網站:到 hub.docker.com 搜尋,可以篩選只看官方映像檔,並在 Tags 分頁看到所有可用的標籤與說明文件。
- 指令:
docker search python
NAME DESCRIPTION STARS OFFICIAL
python Python is an interpreted, interactive, objec… 10000 [OK]
someone/python-tools … 3
| 欄位 | 意思 |
|---|---|
| NAME | 倉庫名稱;沒有斜線的就是官方映像檔 |
| DESCRIPTION | 簡短說明 |
| STARS | 熱門程度(只是參考) |
| OFFICIAL | [OK] 代表官方映像檔 |
(星星數是示意。舊版還有 AUTOMATED 欄位,現在已經拿掉了。)
docker search 不會列出標籤;想知道有哪些版本,還是要去網站看 Tags 分頁。
下載映像檔與標籤
docker container run 遇到本機沒有的映像檔會自動下載;也可以先用 docker image pull 下載好,
之後啟動容器就不用等:
docker image pull ubuntu:24.04 # 指定標籤
docker image pull alpine # 沒寫標籤,等於 alpine:latest
Using default tag: latest
latest: Pulling from library/alpine
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
已經下載過、而且 registry 上沒有更新時,會顯示 Status: Image is up to date for …。
latest 只是一個標籤名稱,不是 Docker 自動幫你挑「最新版」:
- 沒寫標籤時,Docker 就用
latest這個名字去找 - 維護者通常讓
latest指向最新的穩定版,但這是維護者的習慣,不是規則 latest會隨時間改變指向:今天拉到的和半年後拉到的可能是不同版本
所以作業、專題與正式服務裡,請寫明確的版本標籤(python:3.12、ubuntu:24.04),
這樣環境才會固定,也才能真正解決「在我電腦上可以跑」的問題。
| 新式寫法 | 舊寫法 |
|---|---|
docker image pull ubuntu:24.04 |
docker pull ubuntu:24.04 |
映像檔是一層一層疊起來的
映像檔不是一個虛擬硬碟檔,而是由好幾個唯讀的層(layer)疊起來的,每一層記錄「和下面那一層相比改了什麼」。 Docker 用聯合檔案系統(Union File System)把這些層疊在一起,從上面看起來就像一個完整的檔案系統。
投影片的例子,一個資料分析用的映像檔可能是這樣疊的:
| 層(由下往上) | 內容 |
|---|---|
| 第 1 層:基底映像檔(base image) | Ubuntu 的系統檔案 |
| 第 2 層 | 安裝 Python |
| 第 3 層 | 安裝 pip |
| 第 4 層 | 安裝 numpy、pandas、matplotlib |
- 最底層叫基底映像檔(base image),例如
ubuntu、debian、alpine;它上面的每一層都以下面那層為「父層」(parent)。 - 容器啟動時,Docker 在最上面再加一層可寫入的容器層;容器裡新增或修改檔案都寫在這一層, 要改到下面唯讀層的檔案時,先複製一份上來再改,這叫寫入時複製(Copy-on-Write)。 所以很多個容器可以共用同一個映像檔,彼此不會互相影響。
層可以共用:python:3.12 和 python:3.11 都建立在同一個 Debian 基底上,
下載完 3.12 再下載 3.11 時,相同的層顯示 Already exists,只下載不同的部分,也只佔一份磁碟空間。
也因為這樣,docker image ls 每個映像檔的 SIZE 是「各自完整的大小」,直接加總會比實際用掉的磁碟空間多。
管理本機的映像檔
| 指令 | 作用 | 舊寫法 |
|---|---|---|
docker image ls |
列出本機映像檔(REPOSITORY、TAG、IMAGE ID、CREATED、SIZE) | docker images |
docker image ls python |
只列出 python 倉庫的映像檔 |
|
docker image history python:3.12 |
看映像檔由哪些層組成、每層是哪個指令建立的、多大 | docker history |
docker image rm ubuntu:24.04 |
刪除映像檔 | docker rmi |
docker image prune |
清掉沒有名稱、沒人使用的懸空映像檔 |
docker image history 的 CREATED BY 欄位會顯示建立該層的指令(例如 ADD file:…、RUN apt-get install …、CMD ["/bin/bash"]),
SIZE 為 0B 的層只改了設定、沒有新增檔案。加 -H(human readable,預設已開啟)會用易讀的單位顯示大小與時間。
正在被容器使用的映像檔不能刪,即使那個容器已經停止:
$ docker image rm ubuntu:24.04
Error response from daemon: conflict: unable to remove repository reference "ubuntu:24.04"
(must force) - container a3f9c2e1b7d4 is using its referenced image
要先用 docker container rm 移除相關的容器,再刪映像檔。這也呼應第 02 課的生命週期:
容器的「結束」(rm)在前,映像檔的「消失」(image rm)在後。
想一想:倉庫與標籤
執行 docker image pull nginx(沒有寫標籤),Docker 會下載哪一個?
下面哪一個名稱是 Docker Hub 的使用者倉庫,而不是官方映像檔?
為什麼做專題時建議寫 python:3.12 而不是 python:latest?
想一想:層與刪除
已經下載 python:3.12,再下載 python:3.11 時,有幾層顯示 Already exists,代表什麼?
docker image rm ubuntu:24.04 出現 container … is using its referenced image 的錯誤,應該怎麼做?
重點精華回顧
- 映像檔放在 registry 的倉庫裡,用標籤區分版本;完整名稱是
registry/命名空間/倉庫:標籤,預設 registry 是 Docker Hub。 - 只有倉庫名稱的是官方映像檔;
使用者/倉庫是社群上傳的,使用前檢查維護者、原始碼與更新時間。 docker search找倉庫、docker image pull下載;沒寫標籤就是latest,但latest只是標籤名稱,正式使用請寫明確版本。- 映像檔由唯讀的層疊成,最底層是基底映像檔;容器在最上面加一層可寫入的層(寫入時複製)。
- 相同的層可以共用,下載時顯示
Already exists,磁碟上只存一份。 docker image ls、history、rm管理本機映像檔;有容器在用的映像檔要先移除容器才能刪。