大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

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

Docker鏡像

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

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

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

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

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

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

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

鏡像和容器

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

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

鏡像通常比較小

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

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

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

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

提示:Hyper-V 容器運行在專用的輕量級 VM 上,同時利用 VM 內部的操作系統內核。

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

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

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

鏡像倉庫服務

Docker 鏡像存儲在鏡像倉庫服務(Image Registry)當中。

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

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

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

官方和非官方鏡像倉庫

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

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

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

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

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

鏡像命名和標簽

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

docker image pull :

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

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

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

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

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

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

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

關于上述命令,需要注意以下幾點。

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

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

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

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

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

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

> docker image pull microsoft/powershell:nanoserver

> docker image pull microsoft/dotnet:latest

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

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

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

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

為鏡像打多個標簽

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

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

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

如果拉取的鏡像倉庫中包含用于多個平臺或者架構的鏡像,比如同時包含 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

剛才發生了如下幾件事情。

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

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

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

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

過濾 docker image ls 的輸出內容

Docker 提供 --filter 參數來過濾 docker image ls 命令返回的鏡像列表內容。

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

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

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

通常出現這種情況,是因為構建了一個新鏡像,然后為該鏡像打了一個已經存在的標簽。

當此情況出現,Docker 會構建新的鏡像,然后發現已經有鏡像包含相同的標簽,接著 Docker 會移除舊鏡像上面的標簽,將該標簽標在新的鏡像之上。

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

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

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

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

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

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

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

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

下面就是使用 reference 完成過濾并且僅顯示標簽為 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 參數來通過 Go 模板對輸出內容進行格式化。例如,下面的指令將只返回 Docker 主機上鏡像的大小屬性。

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

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

$ 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

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

通過 CLI 方式搜索 Docker Hub

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

簡單模式下,該命令會搜索所有“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",使命令返回內容只顯示官方鏡像。

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

重復前面的操作,但這次只顯示自動創建的倉庫。

$ 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]

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

鏡像和分層

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

Docker 負責堆疊這些鏡像層,并且將它們表示為單個統一的對象。

查看鏡像分層的方式可以通過 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 個鏡像層。只不過這次的輸出內容中使用了鏡像的 SHA256 散列值來標識鏡像層。不過,兩中命令都顯示了鏡像包含 5 個鏡像層。

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

所有的 Docker 鏡像都起始于一個基礎鏡像層,當進行修改或增加新的內容時,就會在當前鏡像層之上,創建新的鏡像層。

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

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

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

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

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

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

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

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

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

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

共享鏡像層

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

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

$ 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 結尾的行。

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

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

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

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

根據摘要拉取鏡像

咱們前面介紹了通過標簽來拉取鏡像,這也是常見的方式。但問題是,標簽是可變的!這意味著可能偶爾出現給鏡像打錯標簽的情況,有時甚至會給新鏡像打一個已經存在的標簽。這些都可能導致問題!

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

一起來思考下剛才發生了什么。鏡像 golftrack:1.5 存在 Bug,這個鏡像已經應用于生產環境。如果創建一個新版本的鏡像,并修復了這個 Bug。

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

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

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

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

接下來通過示例進行相關演示。

$ 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。

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

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

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

$ 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 版本開始,鏡像就是一系列松耦合的獨立層的集合。

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

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

鏡像的唯一標識是一個加密 ID,即配置對象本身的散列值。每個鏡像層也由一個加密 ID 區分,其值為鏡像層本身內容的散列值。

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

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

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

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

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

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

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

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

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

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

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

多層架構的鏡像

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

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

這是會突然發現,在拉取鏡像并運行之前,需要考慮鏡像是否與當前運行環境的架構匹配,這破壞了 Docker 的流暢體驗。

多架構鏡像(Multi-architecture Image)的出現解決了這個問題!

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

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

為了實現這個特性,鏡像倉庫服務 API 支持兩種重要的結構:Manifest 列表(新)和 Manifest。

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

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

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

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

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

在拉取鏡像的時候,Docker 客戶端會調用 Docker Hub 鏡像倉庫服務相應的 API 完成拉取。

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

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

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

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

示例中只運行了普通的命令,選擇當前平臺和架構所需的正確鏡像版本是有由 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 鏡像,以容器方式啟動,執行 go version 命令,并且輸出 Go 的版本和主機 OS / CPU 架構信息。

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

所有官方鏡像都支持 Manifest 列表。但是,全面支持各種架構的工作仍在推進當中。

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

全部教程
主站蜘蛛池模板: 欧美日韩成人高清色视频 | 琪琪色在线视频 | 国产精品亚欧美一区二区三区 | 国产高清不卡 | 成人毛片18女人毛片 | 欧美真人视频一级毛片 | 国产真实强j视频在线观看 国产真实偷乱视频在线观看 | 国产福利在线观看永久视频 | free性欧美喷潮hd | 四虎国产精品影库永久免费 | 黄片毛片大全 | 精品一区二区三区四区 | 免费观看大片bbb | 波多野吉衣一区二区三区四区 | 91精品免费高清在线 | 精品视频自拍 | 国产免费一级精品视频 | 中文毛片 | 国产精品久久久久影院 | 99热热热| 欧美6699在线视频免费 | 国内精品久久久久影院网站 | 九色官网| 性感美女香蕉视频 | 男女车车好快的车车免费网站 | 欧美一区二区三区高清视频 | 奇米第四色在线观看 | 欧美猛妇色xxxxxbbbb | 国产精品h| 日本亚州在线播放精品 | 91精品国产免费久久 | 国产成人女人视频在线观看 | 国产一级淫 | 成人a毛片手机免费播放 | 国产美女久久久亚洲 | 九九九视频 | 伊人色综合久久天天爱 | 婷婷性 | 在线观看年轻的母亲 | 婷婷激情网站 | 久久九九有精品国产23百花影院 |