黄色网址大全免费-黄色网址你懂得-黄色网址你懂的-黄色网址有那些-免费超爽视频-免费大片黄国产在线观看

Docker教程
Docker安裝
Docker使用
Docker實例

Docker鏡像

如果曾經(jīng)做過 VM 管理員,則可以把 Docker 鏡像理解為 VM 模板,VM 模板就像停止運行的 VM,而 Docker 鏡像就像停止運行的容器;而作為一名研發(fā)人員,則可以將鏡像理解為類(Class)。

首先需要先從鏡像倉庫服務(wù)中拉取鏡像。常見的鏡像倉庫服務(wù)是 Docker Hub,但是也存在其他鏡像倉庫服務(wù)。

拉取操作會將鏡像下載到本地 Docker 主機,可以使用該鏡像啟動一個或者多個容器。

鏡像由多個層組成,每層疊加之后,從外部看來就如一個獨立的對象。鏡像內(nèi)部是一個精簡的操作系統(tǒng)(OS),同時還包含應(yīng)用運行所必須的文件和依賴包。

因為容器的設(shè)計初衷就是快速和小巧,所以鏡像通常都比較小。

前面多次提到鏡像就像停止運行的容器(類)。實際上,可以停止某個容器的運行,并從中創(chuàng)建新的鏡像。

在該前提下,鏡像可以理解為一種構(gòu)建時(build-time)結(jié)構(gòu),而容器可以理解為一種運行時(run-time)結(jié)構(gòu),如下圖所示。

鏡像和容器

上圖從頂層設(shè)計層面展示了鏡像和容器間的關(guān)系。通常使用docker container run和docker service create命令從某個鏡像啟動一個或多個容器。

一旦容器從鏡像啟動后,二者之間就變成了互相依賴的關(guān)系,并且在鏡像上啟動的容器全部停止之前,鏡像是無法被刪除的。嘗試刪除鏡像而不停止或銷毀使用它的容器,會導(dǎo)致出錯。

鏡像通常比較小

容器目的就是運行應(yīng)用或者服務(wù),這意味著容器的鏡像中必須包含應(yīng)用/服務(wù)運行所必需的操作系統(tǒng)和應(yīng)用文件。

但是,容器又追求快速和小巧,這意味著構(gòu)建鏡像的時候通常需要裁剪掉不必要的部分,保持較小的體積。

例如,Docker 鏡像通常不會包含 6 個不同的 Shell 讓讀者選擇——通常 Docker 鏡像中只有一個精簡的Shell,甚至沒有 Shell。

鏡像中還不包含內(nèi)核——容器都是共享所在 Docker 主機的內(nèi)核。所以有時會說容器僅包含必要的操作系統(tǒng)(通常只有操作系統(tǒng)文件和文件系統(tǒng)對象)。

提示:Hyper-V 容器運行在專用的輕量級 VM 上,同時利用 VM 內(nèi)部的操作系統(tǒng)內(nèi)核。

Docker 官方鏡像 Alpine Linux 大約只有 4MB,可以說是 Docker 鏡像小巧這一特點的比較典型的例子。

但是,鏡像更常見的狀態(tài)是如 Ubuntu 官方的 Docker 鏡像一般,大約有 110MB。這些鏡像中都已裁剪掉大部分的無用內(nèi)容。

Windows 鏡像要比 Linux 鏡像大一些,這與 Windows OS 工作原理相關(guān)。比如,未壓縮的最新 Microsoft .NET 鏡像(microsoft/dotnet:latest)超過 1.7GB。Windows Server 2016 Nano Server 鏡像(microsoft/nanoserver:latest)在拉取并解壓后,其體積略大于 1GB。

鏡像倉庫服務(wù)

Docker 鏡像存儲在鏡像倉庫服務(wù)(Image Registry)當(dāng)中。

Docker 客戶端的鏡像倉庫服務(wù)是可配置的,默認使用 Docker Hub。

鏡像倉庫服務(wù)包含多個鏡像倉庫(Image Repository)。同樣,一個鏡像倉庫中可以包含多個鏡像。

可能這聽起來讓人有些迷惑,所以下圖展示了包含 3 個鏡像倉庫的鏡像倉庫服務(wù),其中每個鏡像倉庫都包含一個或多個鏡像。

官方和非官方鏡像倉庫

Docker Hub 也分為官方倉庫(Official Repository)和非官方倉庫(Unofficial Repository)。

顧名思義,官方倉庫中的鏡像是由 Docker 公司審查的。這意味著其中的鏡像會及時更新,由高質(zhì)量的代碼構(gòu)成,這些代碼是安全的,有完善的文檔和最佳實踐。

非官方倉庫更像江湖俠客,其中的鏡像不一定具備官方倉庫的優(yōu)點,但這并不意味著所有非官方倉庫都是不好的!非官方倉庫中也有一些很優(yōu)秀的鏡像。

在信任非官方倉庫鏡像代碼之前需要我們保持謹慎。說實話,讀者在使用任何從互聯(lián)網(wǎng)上下載的軟件之前,都要小心,甚至是使用那些來自官方倉庫的鏡像時也應(yīng)如此。

大部分流行的操作系統(tǒng)和應(yīng)用在 Docker Hub 的官方倉庫中都有其對應(yīng)鏡像。這些鏡像很容易找到,基本都在 Docker Hub 命名空間的頂層。

鏡像命名和標(biāo)簽

只需要給出鏡像的名字和標(biāo)簽,就能在官方倉庫中定位一個鏡像(采用“:”分隔)。從官方倉庫拉取鏡像時,docker image pull 命令的格式如下。

docker image pull :

在之前的 Linux 示例中,通過下面的兩條命令完成 Alpine 和 Ubuntu 鏡像的拉取。

docker image pull alpine:latest
docker image pull ubuntu:latest

這兩條命令從 alpine 和 ubuntu 倉庫拉取了標(biāo)有“latest”標(biāo)簽的鏡像。

下面來介紹一下如何從官方倉庫拉取不同的鏡像。

$ docker image pull mongo:3.3.11
//該命令會從官方Mongo庫拉取標(biāo)簽為3.3.11的鏡像

$ docker image pull redis:latest
//該命令會從官方Redis庫拉取標(biāo)簽為latest的鏡像

$ docker image pull alpine
//該命令會從官方Alpine庫拉取標(biāo)簽為latest的鏡像

關(guān)于上述命令,需要注意以下幾點。

首先,如果沒有在倉庫名稱后指定具體的鏡像標(biāo)簽,則 Docker 會假設(shè)用戶希望拉取標(biāo)簽為 latest 的鏡像。

其次,標(biāo)簽為 latest 的鏡像沒有什么特殊魔力!標(biāo)有 latest 標(biāo)簽的鏡像不保證這是倉庫中最新的鏡像!例如,Alpine 倉庫中最新的鏡像通常標(biāo)簽是 edge。通常來講,使用 latest 標(biāo)簽時需要謹慎!

從非官方倉庫拉取鏡像也是類似的,讀者只需要在倉庫名稱面前加上 Docker Hub 的用戶名或者組織名稱。

下面通過示例來展示如何從 tu-demo 倉庫中拉取 v2 這個鏡像,其中鏡像的擁有者是 Docker Hub 賬戶 nigelpoulton,一個不應(yīng)該被信任的賬戶。

$ docker image pull nigelpoulton/tu-demo:v2
//該命令會從以我自己的 Docker Hub 賬號為命名空間的 tu-demo 庫中下載標(biāo)簽為 v2 的鏡像

在之前的 Windows 示例中,使用下面的兩條命令拉取了 PowerShell 和 .NET 鏡像。

> docker image pull microsoft/powershell:nanoserver

> docker image pull microsoft/dotnet:latest

第一條命令從 microsoft/powershell 倉庫中拉取了標(biāo)簽為 nanoserver 的鏡像,第二條命令從 microsoft/dotnet 倉庫中拉取了標(biāo)簽為 latest 的鏡像。

如果希望從第三方鏡像倉庫服務(wù)獲取鏡像(非 Docker Hub),則需要在鏡像倉庫名稱前加上第三方鏡像倉庫服務(wù)的 DNS 名稱。

假設(shè)上面的示例中的鏡像位于 Google 容器鏡像倉庫服務(wù)(GCR)中,則需要在倉庫名稱前面加上 gcr.io,如 docker pull gcr.io/nigelpoulton/tu-demo:v2(這個倉庫和鏡像并不存在)。

可能需要擁有第三方鏡像倉庫服務(wù)的賬戶,并在拉取鏡像前完成登錄。

為鏡像打多個標(biāo)簽

關(guān)于鏡像有一點不得不提,一個鏡像可以根據(jù)用戶需要設(shè)置多個標(biāo)簽。這是因為標(biāo)簽是存放在鏡像元數(shù)據(jù)中的任意數(shù)字或字符串。一起來看下面的示例。

在 docker image pull 命令中指定 -a 參數(shù)來拉取倉庫中的全部鏡像。接下來可以通過運行 docker image ls 查看已經(jīng)拉取的鏡像。

如果使用 Windows 示例,則可以將 Linux 示例中的鏡像倉庫 nigelpoulton/tu-demo 替換為 microsoft/nanoserver。

如果拉取的鏡像倉庫中包含用于多個平臺或者架構(gòu)的鏡像,比如同時包含 Linux 和 Windows 的鏡像,那么命令可能會失敗。

$ docker image pull -a nigelpoulton/tu-demo

latest: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Pull complete
a3ed95caeb02: Pull complete

Digest: sha256:42e34e546cee61adb1...3a0c5b53f324a9e1c1aae451e9
v1: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Already exists
a3ed95caeb02: Already exists

Digest: sha256:9ccc0c67e5c5eaae4b...624c1d5c80f2c9623cbcc9b59a
v2: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Already exists
a3ed95caeb02: Already exists

Digest: sha256:d3c0d8c9d5719d31b7...9fef58a7e038cf0ef2ba5eb74c
Status: Downloaded newer image for nigelpoulton/tu-demo

$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nigelpoulton/tu-demo v2 6ac21e..bead 1 yr ago 211.6 MB
nigelpoulton/tu-demo latest 9b915a..1e29 1 yr ago 211.6 MB
nigelpoulton/tu-demo v1 9b915a..1e29 1 yr ago 211.6 MB

剛才發(fā)生了如下幾件事情。

首先,該命令從 nigelpoulton/tu-demo 倉庫拉取了 3 個鏡像:latest、v1 以及 v2。

其次,注意看 docker image ls 命令輸出中的 IMAGE ID 這一列。發(fā)現(xiàn)只有兩個不同的 Image ID。這是因為實際只下載了兩個鏡像,其中有兩個標(biāo)簽指向了相同的鏡像。

換句話說,其中一個鏡像擁有兩個標(biāo)簽。如果仔細觀察會發(fā)現(xiàn) v1 和 latest 標(biāo)簽指向了相同的 IMAGE ID,這意味著這兩個標(biāo)簽屬于相同的鏡像。

這個示例也完美證明了前文中關(guān)于 latest 標(biāo)簽使用的警告。latest 標(biāo)簽指向了 v1 標(biāo)簽的鏡像。這意味著 latest 實際指向了兩個鏡像中較早的那個版本,而不是最新的版本!latest 是一個非強制標(biāo)簽,不保證指向倉庫中最新的鏡像!

過濾 docker image ls 的輸出內(nèi)容

Docker 提供 --filter 參數(shù)來過濾 docker image ls 命令返回的鏡像列表內(nèi)容。

下面的示例只會返回懸虛(dangling)鏡像。

$ docker image ls --filter dangling=true
REPOSITORY TAG IMAGE ID CREATED SIZE
  4fd34165afe0 7 days ago 14.5MB

那些沒有標(biāo)簽的鏡像被稱為懸虛鏡像,在列表中展示為<none>:<none>。

通常出現(xiàn)這種情況,是因為構(gòu)建了一個新鏡像,然后為該鏡像打了一個已經(jīng)存在的標(biāo)簽。

當(dāng)此情況出現(xiàn),Docker 會構(gòu)建新的鏡像,然后發(fā)現(xiàn)已經(jīng)有鏡像包含相同的標(biāo)簽,接著 Docker 會移除舊鏡像上面的標(biāo)簽,將該標(biāo)簽標(biāo)在新的鏡像之上。

例如,首先基于 alpine:3.4 構(gòu)建一個新的鏡像,并打上 dodge:challenger 標(biāo)簽。然后更新 Dockerfile,將 alpine:3.4 替換為 alpine:3.5,并且再次執(zhí)行 docker image build 命令,該命令會構(gòu)建一個新的鏡像,并且標(biāo)簽為 dodge:challenger,同時移除了舊鏡像上面對應(yīng)的標(biāo)簽,舊鏡像就變成了懸虛鏡像。

可以通過 docker image prune 命令移除全部的懸虛鏡像。如果添加了 -a 參數(shù),Docker 會額外移除沒有被使用的鏡像(那些沒有被任何容器使用的鏡像)。

Docker 目前支持如下的過濾器。

? dangling:可以指定 true 或者 false,僅返回懸虛鏡像(true),或者非懸虛鏡像(false)。

? before:需要鏡像名稱或者 ID 作為參數(shù),返回在之前被創(chuàng)建的全部鏡像。

? since:與 before 類似,不過返回的是指定鏡像之后創(chuàng)建的全部鏡像。

? label:根據(jù)標(biāo)注(label)的名稱或者值,對鏡像進行過濾。docker image ls命令輸出中不顯示標(biāo)注內(nèi)容。

其他的過濾方式可以使用 reference。

下面就是使用 reference 完成過濾并且僅顯示標(biāo)簽為 latest 的示例。

$ docker image ls --filter=reference="*:latest"
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 3fd9065eaf02 8 days ago 4.15MB
test latest 8426e7efb777 3 days ago 122MB

可以使用 --format 參數(shù)來通過 Go 模板對輸出內(nèi)容進行格式化。例如,下面的指令將只返回 Docker 主機上鏡像的大小屬性。

$ docker image ls --format "{{.Size}}"
99.3MB
111MB
82.6MB
88.8MB
4.15MB
108MB

使用下面命令返回全部鏡像,但是只顯示倉庫、標(biāo)簽和大小信息。

$ docker image ls --format "{{.Repository}}: {{.Tag}}: {{.Size}}"
dodge: challenger: 99.3MB
ubuntu: latest: 111MB
python: 3.4-alpine: 82.6MB
python: 3.5-alpine: 88.8MB
alpine: latest: 4.15MB
nginx: latest: 108MB

如果讀者需要更復(fù)雜的過濾,可以使用 OS 或者 Shell 自帶的工具,比如 Grep 或者 AWK 。

通過 CLI 方式搜索 Docker Hub

docker search 命令允許通過 CLI 的方式搜索 Docker Hub。可以通過“NAME”字段的內(nèi)容進行匹配,并且基于返回內(nèi)容中任意列的值進行過濾。

簡單模式下,該命令會搜索所有“NAME”字段中包含特定字符串的倉庫。例如,下面的命令會查找所有“NAME”包含“nigelpoulton”的倉庫。

$ docker search nigelpoulton
NAME DESCRIPTION STARS AUTOMATED
nigelpoulton/pluralsight.. Web app used in... 8 [OK]
nigelpoulton/tu-demo 7
nigelpoulton/k8sbook Kubernetes Book web app 1
nigelpoulton/web-fe1 Web front end example 0
nigelpoulton/hello-cloud Quick hello-world image 0

“NAME”字段是倉庫名稱,包含了 Docker ID,或者非官方倉庫的組織名稱。例如,下面的命令會列出所有倉庫名稱中包含“alpine”的鏡像。

$ docker search alpine
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
alpine A minimal Docker.. 2988 [OK]
mhart/alpine-node Minimal Node.js.. 332
anapsix/alpine-java Oracle Java 8... 270 [OK]

需要注意,上面返回的鏡像中既有官方的也有非官方的。讀者可以使用 --filter "is-official=true",使命令返回內(nèi)容只顯示官方鏡像。

$ docker search alpine --filter "is-official=true"
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
alpine A minimal Docker.. 2988 [OK]

重復(fù)前面的操作,但這次只顯示自動創(chuàng)建的倉庫。

$ docker search alpine --filter "is-automated=true"
NAME DESCRIPTION OFFICIAL AUTOMATED
anapsix/alpine-java Oracle Java 8 (and 7).. [OK]
frolvlad/alpine-glibc Alpine Docker image.. [OK]
kiasaki/alpine-postgres PostgreSQL docker.. [OK]
zzrot/alpine-caddy Caddy Server Docker.. [OK]

關(guān)于 docker search 需要注意的最后一點是,默認情況下,Docker 只返回 25 行結(jié)果。但是,可以通過指定 --limit 參數(shù)來增加返回內(nèi)容行數(shù),最多為 100 行。

鏡像和分層

Docker 鏡像由一些松耦合的只讀鏡像層組成。如下圖所示。

Docker 負責(zé)堆疊這些鏡像層,并且將它們表示為單個統(tǒng)一的對象。

查看鏡像分層的方式可以通過 docker image inspect 命令。下面同樣以 ubuntu:latest 鏡像為例。

$ docker image inspect ubuntu:latest
[
{
"Id": "sha256:bd3d4369ae.......fa2645f5699037d7d8c6b415a10",
"RepoTags": [
"ubuntu:latest"



"RootFS": {
  "Type": "layers",
  "Layers": [
   "sha256:c8a75145fc...894129005e461a43875a094b93412",
   "sha256:c6f2b330b6...7214ed6aac305dd03f70b95cdc610",
   "sha256:055757a193...3a9565d78962c7f368d5ac5984998",
   "sha256:4837348061...12695f548406ea77feb5074e195e3",
   "sha256:0cad5e07ba...4bae4cfc66b376265e16c32a0aae9"
  ]
  }
}
]

縮減之后的輸出也顯示該鏡像包含 5 個鏡像層。只不過這次的輸出內(nèi)容中使用了鏡像的 SHA256 散列值來標(biāo)識鏡像層。不過,兩中命令都顯示了鏡像包含 5 個鏡像層。

docker history 命令顯示了鏡像的構(gòu)建歷史記錄,但其并不是嚴格意義上的鏡像分層。例如,有些 Dockerfile 中的指令并不會創(chuàng)建新的鏡像層。比如 ENV、EXPOSE、CMD 以及 ENTRY- POINT。不過,這些命令會在鏡像中添加元數(shù)據(jù)。

所有的 Docker 鏡像都起始于一個基礎(chǔ)鏡像層,當(dāng)進行修改或增加新的內(nèi)容時,就會在當(dāng)前鏡像層之上,創(chuàng)建新的鏡像層。

舉一個簡單的例子,假如基于 Ubuntu Linux 16.04 創(chuàng)建一個新的鏡像,這就是新鏡像的第一層;如果在該鏡像中添加 Python 包,就會在基礎(chǔ)鏡像層之上創(chuàng)建第二個鏡像層;如果繼續(xù)添加一個安全補丁,就會創(chuàng)建第三個鏡像層。

該鏡像當(dāng)前已經(jīng)包含 3 個鏡像層,如下圖所示(這只是一個用于演示的很簡單的例子)。

在添加額外的鏡像層的同時,鏡像始終保持是當(dāng)前所有鏡像的組合,理解這一點非常重要。下圖中舉了一個簡單的例子,每個鏡像層包含 3 個文件,而鏡像包含了來自兩個鏡像層的 6 個文件。

上圖中的鏡像層跟之前圖中的略有區(qū)別,主要目的是便于展示文件。

下圖中展示了一個稍微復(fù)雜的三層鏡像,在外部看來整個鏡像只有 6 個文件,這是因為最上層中的文件 7 是文件 5 的一個更新版本。

這種情況下,上層鏡像層中的文件覆蓋了底層鏡像層中的文件。這樣就使得文件的更新版本作為一個新鏡像層添加到鏡像當(dāng)中。

Docker 通過存儲引擎(新版本采用快照機制)的方式來實現(xiàn)鏡像層堆棧,并保證多鏡像層對外展示為統(tǒng)一的文件系統(tǒng)。

Linux 上可用的存儲引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顧名思義,每種存儲引擎都基于 Linux 中對應(yīng)的文件系統(tǒng)或者塊設(shè)備技術(shù),并且每種存儲引擎都有其獨有的性能特點。

Docker 在 Windows 上僅支持 windowsfilter 一種存儲引擎,該引擎基于 NTFS 文件系統(tǒng)之上實現(xiàn)了分層和 CoW[1]。

下圖展示了與系統(tǒng)顯示相同的三層鏡像。所有鏡像層堆疊并合并,對外提供統(tǒng)一的視圖。

共享鏡像層

多個鏡像之間可以并且確實會共享鏡像層。這樣可以有效節(jié)省空間并提升性能。

回顧一下之前用于拉取 nigelpoulton/tu-demo 倉庫下全部包含標(biāo)簽的 docker image pull 命令(包含 -a 參數(shù))。

$ docker image pull -a nigelpoulton/tu-demo

latest: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Pull complete
a3ed95caeb02: Pull complete

Digest: sha256:42e34e546cee61adb100...a0c5b53f324a9e1c1aae451e9

v1: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Already exists
a3ed95caeb02: Already exists

Digest: sha256:9ccc0c67e5c5eaae4beb...24c1d5c80f2c9623cbcc9b59a

v2: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Already exists
a3ed95caeb02: Already exists

eab5aaac65de: Pull complete
Digest: sha256:d3c0d8c9d5719d31b79c...fef58a7e038cf0ef2ba5eb74c

Status: Downloaded newer image for nigelpoulton/tu-demo

$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nigelpoulton/tu-demo v2 6ac...ead 4 months ago 211.6 MB
nigelpoulton/tu-demo latest 9b9...e29 4 months ago 211.6 MB
nigelpoulton/tu-demo v1 9b9...e29 4 months ago 211.6 MB

注意那些以 Already exists 結(jié)尾的行。

由這幾行可見,Docker 很聰明,可以識別出要拉取的鏡像中,哪幾層已經(jīng)在本地存在。

在本例中,Docker 首先嘗試拉取標(biāo)簽為 latest 的鏡像。然后,當(dāng)拉取標(biāo)簽為 v1 和 v2 的鏡像時,Docker 注意到組成這兩個鏡像的鏡像層,有一部分已經(jīng)存在了。出現(xiàn)這種情況的原因是前面 3 個鏡像相似度很高,所以共享了很多鏡像層。

如前所述,Docker 在 Linux 上支持很多存儲引擎(Snapshotter)。每個存儲引擎都有自己的鏡像分層、鏡像層共享以及寫時復(fù)制(CoW)技術(shù)的具體實現(xiàn)。

但是,其最終效果和用戶體驗是完全一致的。盡管 Windows 只支持一種存儲引擎,還是可以提供與 Linux 相同的功能體驗。

根據(jù)摘要拉取鏡像

咱們前面介紹了通過標(biāo)簽來拉取鏡像,這也是常見的方式。但問題是,標(biāo)簽是可變的!這意味著可能偶爾出現(xiàn)給鏡像打錯標(biāo)簽的情況,有時甚至?xí)o新鏡像打一個已經(jīng)存在的標(biāo)簽。這些都可能導(dǎo)致問題!

假設(shè)鏡像 golftrack:1.5 存在一個已知的 Bug。因此可以拉取該鏡像后修復(fù)它,并使用相同的標(biāo)簽將更新的鏡像重新推送回倉庫。

一起來思考下剛才發(fā)生了什么。鏡像 golftrack:1.5 存在 Bug,這個鏡像已經(jīng)應(yīng)用于生產(chǎn)環(huán)境。如果創(chuàng)建一個新版本的鏡像,并修復(fù)了這個 Bug。

那么問題來了,構(gòu)建新鏡像并將其推送回倉庫時使用了與問題鏡像相同的標(biāo)簽!原鏡像被覆蓋,但在生產(chǎn)環(huán)境中遺留了大量運行中的容器,沒有什么好辦法區(qū)分正在使用的鏡像版本是修復(fù)前還是修復(fù)后的,因為兩個鏡像的標(biāo)簽是相同的!

Docker 1.10 中引入了新的內(nèi)容尋址存儲模型。作為模型的一部分,每一個鏡像現(xiàn)在都有一個基于其內(nèi)容的密碼散列值。

為了討論方便,用摘要代指這個散列值。因為摘要是鏡像內(nèi)容的一個散列值,所以鏡像內(nèi)容的變更一定會導(dǎo)致散列值的改變。這意味著摘要是不可變的。這種方式可以解決前面討論的問題。

每次拉取鏡像,摘要都會作為 docker image pull 命令返回代碼的一部分。只需要在 docker image ls 命令之后添加 --digests 參數(shù)即可在本地查看鏡像摘要。

接下來通過示例進行相關(guān)演示。

$ docker image pull alpine
Using default tag: latest
latest: Pulling from library/alpine
e110a4a17941: Pull complete
Digest: sha256:3dcdb92d7432d56604d...6d99b889d0626de158f73a
Status: Downloaded newer image for alpine:latest

$ docker image ls --digests alpine
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
alpine latest sha256:3dcd...f73a 4e38e38c8ce0 10 weeks ago 4.8 MB

從上面的代碼片段中可知,Alpine 鏡像的簽名值如下。

sha256:3dcdb92d7432d56604d... 6d99b889d0626de158f73a。

現(xiàn)在已知鏡像的摘要,那么可以使用摘要值再次拉取這個鏡像。這種方式可以確保準(zhǔn)確拉取想要的鏡像。

沒有原生 Docker 命令支持從遠端鏡像倉庫服務(wù)(如Docker Hub)中獲取鏡像簽名。這意味著只能先通過標(biāo)簽方式拉取鏡像到本地,然后自己維護鏡像的摘要列表。鏡像摘要在未來絕對不會發(fā)生變化。

下面通過示例首先在 Docker 主機上刪除 alpine:latest 鏡像,然后顯示如何通過摘要(而不是標(biāo)簽)來再次拉取該鏡像。

$ docker image rm alpine:latest
Untagged: alpine:latest
Untagged: alpine@sha256:c0537...7c0a7726c88e2bb7584dc96
Deleted: sha256:02674b9cb179d...abff0c2bf5ceca5bad72cd9
Deleted: sha256:e154057080f40...3823bab1be5b86926c6f860

$ docker image pull alpine@sha256:c0537...7c0a7726c88e2bb7584dc96
sha256:c0537...7726c88e2bb7584dc96: Pulling from library/alpine
cfc728c1c558: Pull complete
Digest: sha256:c0537ff6a5218...7c0a7726c88e2bb7584dc96
Status: Downloaded newer image for alpine@sha256:c0537...bb7584dc96

鏡像散列值(摘要)

從 Docker 1.10 版本開始,鏡像就是一系列松耦合的獨立層的集合。

鏡像本身就是一個配置對象,其中包含了鏡像層的列表以及一些元數(shù)據(jù)信息。

鏡像層才是實際數(shù)據(jù)存儲的地方(比如文件等,鏡像層之間是完全獨立的,并沒有從屬于某個鏡像集合的概念)。

鏡像的唯一標(biāo)識是一個加密 ID,即配置對象本身的散列值。每個鏡像層也由一個加密 ID 區(qū)分,其值為鏡像層本身內(nèi)容的散列值。

這意味著修改鏡像的內(nèi)容或其中任意的鏡像層,都會導(dǎo)致加密散列值的變化。所以,鏡像和其鏡像層都是不可變的,任何改動都能很輕松地被辨別。

這就是所謂的內(nèi)容散列(Content Hash)。

到目前為止,事情都很簡單。但是接下來的內(nèi)容就有點兒復(fù)雜了。

在推送和拉取鏡像的時候,都會對鏡像層進行壓縮來節(jié)省網(wǎng)絡(luò)帶寬以及倉庫二進制存儲空間。

但是壓縮會改變鏡像內(nèi)容,這意味著鏡像的內(nèi)容散列值在推送或者拉取操作之后,會與鏡像內(nèi)容不相符!這顯然是個問題。

例如,在推送鏡像層到 Docker Hub 的時候,Docker Hub 會嘗試確認接收到的鏡像沒有在傳輸過程中被篡改。

為了完成校驗,Docker Hub 會根據(jù)鏡像層重新計算散列值,并與原散列值進行比較。

因為鏡像在傳輸過程中被壓縮(發(fā)生了改變),所以散列值的校驗也會失敗。

為避免該問題,每個鏡像層同時會包含一個分發(fā)散列值(Distribution Hash)。這是一個壓縮版鏡像的散列值,當(dāng)從鏡像倉庫服務(wù)拉取或者推送鏡像的時候,其中就包含了分發(fā)散列值,該散列值會用于校驗拉取的鏡像是否被篡改過。

這個內(nèi)容尋址存儲模型極大地提升了鏡像的安全性,因為在拉取和推送操作后提供了一種方式來確保鏡像和鏡像層數(shù)據(jù)是一致的。

該模型也解決了隨機生成鏡像和鏡像層 ID 這種方式可能導(dǎo)致的 ID 沖突問題。

多層架構(gòu)的鏡像

Docker 最值得稱贊的一點就是使用方便。例如,運行一個應(yīng)用就像拉取鏡像并運行容器這么簡單。無須擔(dān)心安裝、依賴或者配置的問題。開箱即用。

但是,隨著 Docker 的發(fā)展,事情開始變得復(fù)雜——尤其是在添加了新平臺和架構(gòu)之后,例如 Windows、ARM 以及 s390x。

這是會突然發(fā)現(xiàn),在拉取鏡像并運行之前,需要考慮鏡像是否與當(dāng)前運行環(huán)境的架構(gòu)匹配,這破壞了 Docker 的流暢體驗。

多架構(gòu)鏡像(Multi-architecture Image)的出現(xiàn)解決了這個問題!

Docker(鏡像和鏡像倉庫服務(wù))規(guī)范目前支持多架構(gòu)鏡像。這意味著某個鏡像倉庫標(biāo)簽(repository:tag)下的鏡像可以同時支持 64 位 Linux、PowerPC Linux、64 位 Windows 和 ARM 等多種架構(gòu)。

簡單地說,就是一個鏡像標(biāo)簽之下可以支持多個平臺和架構(gòu)。下面通過實操演示該特性。

為了實現(xiàn)這個特性,鏡像倉庫服務(wù) API 支持兩種重要的結(jié)構(gòu):Manifest 列表(新)和 Manifest。

Manifest 列表是指某個鏡像標(biāo)簽支持的架構(gòu)列表。其支持的每種架構(gòu),都有自己的 Mainfest 定義,其中列舉了該鏡像的構(gòu)成。

下圖使用 Golang 官方鏡像作為示例。圖左側(cè)是 Manifest 列表,其中包含了該鏡像支持的每種架構(gòu)。

Manifest 列表的每一項都有一個箭頭,指向具體的 Manifest,其中包含了鏡像配置和鏡像層數(shù)據(jù)。

在具體操作之前,先來了解一下原理。

假設(shè)要在 Raspberry Pi(基于 ARM 架構(gòu)的 Linux)上運行 Docker。

在拉取鏡像的時候,Docker 客戶端會調(diào)用 Docker Hub 鏡像倉庫服務(wù)相應(yīng)的 API 完成拉取。

如果該鏡像有 Mainfest 列表,并且存在 Linux on ARM 這一項,則 Docker Client 就會找到 ARM 架構(gòu)對應(yīng)的 Mainfest 并解析出組成該鏡像的鏡像層加密 ID。

然后從 Docker Hub 二進制存儲中拉取每個鏡像層。

下面的示例就展示了多架構(gòu)鏡像是如何在拉取官方 Golang 鏡像(支持多架構(gòu))時工作的,并且通過一個簡單的命令展示了 Go 的版本和所在主機的 CPU 架構(gòu)。

需要注意的是,兩個例子都使用相同的命令 docker container run。不需要告知 Docker 具體的鏡像版本是 64 位 Linux 還是 64 位 Windows。

示例中只運行了普通的命令,選擇當(dāng)前平臺和架構(gòu)所需的正確鏡像版本是有由 Docker 完成的。

64 位 Linux 示例如下。

$ docker container run --rm golang go version

Unable to find image 'golang:latest' locally
latest: Pulling from library/golang
723254a2c089: Pull complete
<Snip>
39cd5f38ffb8: Pull complete
Digest: sha256:947826b5b6bc4...
Status: Downloaded newer image for golang:latest
go version go1.9.2 linux/amd64

64 位 Windows 示例如下。

PS> docker container run --rm golang go version

Using default tag: latest
latest: Pulling from library/golang
3889bb8d808b: Pull complete
8df8e568af76: Pull complete
9604659e3e8d: Pull complete
9f4a4a55f0a7: Pull complete
6d6da81fc3fd: Pull complete
72f53bd57f2f: Pull complete
6464e79d41fe: Pull complete
dca61726a3b4: Pull complete
9150276e2b90: Pull complete
cd47365a14fb: Pull complete
1783777af4bb: Pull complete
3b8d1834f1d7: Pull complete
7258d77b22dd: Pull complete
Digest: sha256:e2be086d86eeb789...e1b2195d6f40edc4
Status: Downloaded newer image for golang:latest
go version go1.9.2 windows/amd64

前面的操作包括從 Docker Hub 拉取 Golang 鏡像,以容器方式啟動,執(zhí)行 go version 命令,并且輸出 Go 的版本和主機 OS / CPU 架構(gòu)信息。

每個示例的最后一行都展示了 go version 命令的輸出內(nèi)容。可以看到兩個示例使用了完全相同的命令,但是 Linux 示例中拉取的是 linux/amd64 鏡像,而 Windows 示例中拉取的是 windows/amd64 鏡像。

所有官方鏡像都支持 Manifest 列表。但是,全面支持各種架構(gòu)的工作仍在推進當(dāng)中。

創(chuàng)建支持多架構(gòu)的鏡像需要鏡像的發(fā)布者做更多的工作。同時,某些軟件也并非跨平臺的。在這個前提下,Manifest 列表是可選的——在沒有 Manifest 列表的情況下,鏡像倉庫服務(wù)會返回普通的 Manifest。

全部教程
主站蜘蛛池模板: 无码中文资源在线播放 | 天天爽夜夜| 久久精品视频一区二区三区 | 精品国产一区二区三区麻豆小说 | 欧美性极品xxxxx | bl男男全肉高h车 | 中文字幕精品视频在线观 | 男女后进式猛烈xx00动态图片 | 国产综合亚洲专区在线 | 五月亚洲综合 | 怡红院在线视频精品观看 | 国产黄色一级毛片 | 97免费公开视频 | 在线免费视频网站 | 中文字幕欧美激情 | 人人添人人澡人人澡人人诱 | 亚洲婷婷网 | 视频黄色片 | 成人福利在线免费观看 | 毛片网站有哪些 | 日韩国产欧美精品综合二区 | 亚洲 欧美 日韩在线一区 | 成人免费国产欧美日韩你懂的 | 久久九九视频 | 欧美性猛交一区二区三区精品 | 91短视频在线观看 | 免费观看黄a一级视频 | 日韩h在线 | 日韩中文在线观看 | 亚洲成人xxx| 成人免费激情视频 | 国产欧美日韩视频在线观看 | 欧美国产小视频 | 亚洲精品在线免费观看视频 | 国产不卡精品一区二区三区 | 日韩在线视频不卡 | 免费看欧美一级特黄a大片 免费看欧美一级特黄α大片 | 免费一级国产生活片 | 一个人看的www高清视频 | 特黄aaaaaaaaa及毛片 | 久久99精品麻豆国产 |