大家好,我是張晉濤。
這篇文章中我將介紹 OCI 及 Docker 映象相關的內容,歡迎留言討論。
OCI 的前世今生
2013 年 3 月 dotCloud 公司在 PyCon 上進行了 Docker 的首次展示,隨後宣佈開源。自此 Docker 開始被眾人知曉,隨後掀起了一股容器化的熱潮。
在 2014 年 6 月 Docker 1.0 正式釋出,有近 460 位貢獻者和超過 8700 次提交,這也標誌著 Docker 達到了生產可用的狀態。
在當時,提到容器化第一想法就是用 Docker 。而當時 Docker 的實現或者說發展方向主要是由 Docker Inc. 公司控制的,並沒有一個統一的工業標準。這對於一些頭部公司而言,顯然是不能接受的,沒有統一的工業標準意味著如果選擇了使用 Docker 的容器化技術,便會被 Docker Inc. 公司所繫結;加上隨著 Docker 軟體的升級,某些功能或者特性必然會進行變動,沒人能保證不發生破壞性變更。
所以,為了推進容器化技術的工業標準化,2015 年 6 月在 DockerCon 上 Linux 基金會與 Google,華為,惠普,IBM,Docker,Red Hat,VMware 等公司共同宣佈成立開放容器專案(OCP),後更名為 OCI。它的主要目標便是 建立容器格式和執行時的工業開放通用標準。
發展至今, OCI 制定的主要標準有三個分別是 runtime-spec
、image-spec
和 distribution-spec
這三個標準分別定義了容器執行時,容器映象還有分發的規範,後面會展開介紹。
為了支援 OCI 容器執行時標準的推進,Docker 公司起草了映象格式和執行時規範的草案,並將 Docker 專案的相關實現捐獻給了 OCI 作為容器執行時的基礎實現,現在專案名為 runc
。
後來 Docker 將其容器執行時獨立成了一個專案,名為 containerd
並將此專案捐獻給了 CNCF ,現在已經是 CNCF 畢業專案了。
OCI image vs Docker image
OCI 的建立推動了容器技術的工業標準化,但是否此標準就是唯一呢?其實不然。在成立 OCI 並制定 image-spec
標準的時候 Docker 已經空前繁榮,並得到了廣泛的應用。
由於標準只定義了最基本的內容,想要將 Docker 的實現全部按照標準進行改造的話,會對 Docker 造成破壞性變更,也不利於 Docker 功能的迭代。
所以,Docker 為了支援 OCI 標準的普及,已經推進了 registry 對 OCI 映象的支援,現在也正在給 Docker 自身增加適配中,目標是讓 Docker 支援兩種映象格式,分別是符合 Docker 標準的映象和符合 OCI 標準的映象。
那這兩者有什麼異同呢? 我們來逐步看下。
Docker Image 和 OCI Image 的區別和聯絡
在我以前的文章中我們已經詳細的從根本上介紹了 Docker image 是什麼,這裡我們就快速的介紹下。
每個 Docker 映象都是由一系列的配置清單和相應的層進行組織的。每個層一般都是 tar 格式的歸檔,配置清單中描述了對應的層應該按何種順序進行組織,以及映象的一些元屬性。比如映象所支援的架構,例如 amd64
之類的,還有 ENV 等提前配置好的一些引數等。
當然,在 Docker Image 中也包含著構建映象時候所用的 Docker 版本 docker_version
以及構建映象的歷史記錄 history
等資訊。所以你在 DockerHub
或者其他的映象倉庫上可以看到構建映象所用的 Docker 版本, 或者可通過 docker history <IMAGE>
的方式來檢視構建歷史。
那麼 OCI Image 是什麼呢? 首先我們需要有一個 OCI Image 才好探究它到底是什麼。
這裡介紹一個工具 skopeo 可以很方便的從映象倉庫或者本地 Docker daemon 甚至是通過 docker save
儲存的 Docker Image tar 檔案轉換為 OCI Image 。
關於 skopeo 的安裝過程就不再贅述了,參考專案主頁的文件說明即可。這裡直接開始使用。
我們使用 debian
的映象為例。
(MoeLove) ➜ skopeo copy docker://debian:stretch oci:debian:stretch
Getting image source signatures
Copying blob a4d8138d0f6b done
Copying config 45f82268e3 done
Writing manifest to image destination
Storing signatures
通過上面的命令便會得到一個 OCI Image 了, 我們看下它的目錄結構。
(MoeLove) ➜ tree debian
debian
├── blobs
│ └── sha256
│ ├── 0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155
│ ├── 45f82268e32180cb1839f90467d9b8a8258953d68b7221199976653308d92ef5
│ └── a4d8138d0f6b5a441aaa533faf5fe0c3996a6ca42643c46f4402c7e8bda53742
├── index.json
└── oci-layout
2 directories, 5 files
是不是有種似曾相識的感覺?沒錯 OCI Image 的規範是在 Docker Image 的基礎上建立的,所以大致看起來差異不是特別大。我們看看其中具體的內容。
oci-layout
這個檔案是 OCI Image 的佈局檔案,也是用於說明它所使用或者遵循的映象規範。
(MoeLove) ➜ debian cat oci-layout| jq
{
"imageLayoutVersion": "1.0.0"
}
可以看到此處的內容寫的是 1.0.0
這便說明該映象遵循 OCI 1.0.0 版本的佈局規範。
index.json
index.json
檔案中的 manifest
欄位類似於 Docker Image 中的 manifest.json
作為 OCI Image 的頂級配置, 也是映象的一個入口配置。
(MoeLove) ➜ debian cat index.json | jq
{
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155",
"size": 349,
"annotations": {
"org.opencontainers.image.ref.name": "stretch"
},
"platform": {
"architecture": "amd64",
"os": "linux"
}
}
]
}
從它的內容可以看到它其中的 mediaType
欄位與 Docker Image 中的型別形式相同,但是將 docker
都換成了 oci
。從這個配置檔案,我們可以找到第一個 blob 是 sha256:0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155
我們看看它的內容。
(MoeLove) ➜ debian cat blobs/sha256/0043cd2a654fe86258f43f5b1dbbb4e6c582cc4bb6e505e9c5171c124150d155 | jq
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:45f82268e32180cb1839f90467d9b8a8258953d68b7221199976653308d92ef5",
"size": 579
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:a4d8138d0f6b5a441aaa533faf5fe0c3996a6ca42643c46f4402c7e8bda53742",
"size": 45337510
}
]
}
這個入口檔案描述了 OCI 映象的實際配置和其中的 Layer 配置。如果有多層那 layers
也會相應增加。
注意:layers 中 mediaType
使用了 application/vnd.oci.image.layer.v1.tar+gzip
說明資料內容是經過 gzip 壓縮的 如果有興趣你可以將它用 tar 解壓一下,你會發現很有趣的內容。
這裡先將結果說出來,解壓後你會得到一個 rootfs
這與 Docker Image 是類似的。
小結
我們通過 skopeo 工具,從本地的 Docker daemon 中由 debian 的 Docker Image 得到了 OCI Image,並分析了它其中的內容。
最主要的區別在於它們的目錄結構不完全相同,配置資訊尤其是 mediaType
的規範是不相同的。
而它們的聯絡也在於此,OCI Image 的規範是由 Docker Image 的規範修改而來的,所以類似它們的 blob 的組織形式大致是相同的,配置檔案中很多的引數也相似。
另外,我們也可以很容易的得到另一個結論,那便是我們可以很方便的將 Docker Image 轉換為 OCI Image 。
OCI image 和 Docker image 的轉換
上面我們已經看到,使用 skopeo 工具,可以將 Docker Image 轉換為 OCI Image ,當然它也可以將 OCI Image 轉換為 Docker Image 。下面給出了方法:
# 從 DockerHub 將 debian 的 Docker Image 拉取並轉換為 OCI Image
(MoeLove) ➜ skopeo copy docker://debian:stretch oci:debian:stretch
Getting image source signatures
Copying blob a4d8138d0f6b done
Copying config 45f82268e3 done
Writing manifest to image destination
Storing signatures
# 將當前目錄下的 debian 的 OCI Image 轉換為 Docker Image 並儲存到本地 docker daemon 中
(MoeLove) ➜ skopeo copy oci:debian:stretch docker-daemon:local/debian:oci
Getting image source signatures
Copying blob 0e350e141713 done
Copying config aae58a37cf done
Writing manifest to image destination
Storing signatures
# 驗證
(MoeLove) ➜ oci docker images local/debian
REPOSITORY TAG IMAGE ID CREATED SIZE
local/debian oci ac6bcf605d82 6 months ago 101MB
映象構建工具
在 CI/CD 環境中,雖然我們可以使用 DinD (Docker in Docker) 的方式啟動一個 docker daemon 或者使用掛載的方式,將外部的 /var/run/docker.sock
掛載進容器內部,亦或者將 Docker API 使用 HTTP 的方式暴露出來,直接使用該地址進行構建。
但這些方式你是否會覺得比較重?是否有考慮安全問題,或者壓力及負載的問題?
這裡的壓力及負載主要是指當所有的任務都共用同一個 docker daemon 提供服務的話,對該 docker daemon 造成的壓力。
這裡我們來介紹一些其他的映象構建工具,使用這些工具可以讓你在無 Docker 的環境下構建出映象並上傳至 Docker 映象倉庫中。
到目前為止,我們可以有很多種選擇:
這些工具側重點各有不同,當然也不僅有上面列到的這些工具,只是這些工具比較典型罷了。
通常情況下,在網路上比較容易見到宣傳為下一代映象構建工具的是 buildah
,最主要原因是因為它可以直接構建 OCI 標準的映象或 Docker 映象,也可以直接使用 Dockerfile
。並且它還可以 pull
/push
映象,可以說在映象構建方面與 Docker 是完全相容,甚至可以說它在構建映象方面可以作為 Docker 的替代品了。
並且 buildah
構建映象的時候不需要任何 root
許可權,也不依賴 Docker, 它使用了簡單的 fork-exec
模型,同時它也可以作為一個庫包含在其他的工具中。它的最終目標便是提供一個更低層次的核心工具集,來完成構建映象相關的事情。
說完這個典型的替代品,我們再來說下 BuildKit
和 img
, img
這個工具是構建在 BuildKit
之上的,所以有很多相似性。它們使用非 root 使用者來構建映象。當然 BuildKit
我在之前的文章中詳細介紹過了,它是 Docker 內建的下一代構建工具,獨立使用也是可以的。稱它為“下一代映象構建工具” 也並不為過。
kaniko
是 Google 推出的,它主要的宣傳語為 “在 Kubernetes 中構建容器映象” 實際上無論是在 K8S 叢集中或者在容器中它都是可以工作的。它也可以使用 Dockerfile
構建映象。當然還有很重要的一點,它所有的構建命令都是執行在使用者態的,並且也可以很好的與 Kubernetes 結合,在雲原生時代下,它也佔據了一定的優勢。
以上工具都只是大致介紹了下,如果對它們感興趣,可直接進入專案主頁檢視 README.md
基礎使用都有比較詳細的說明,這裡不再進行贅述了。
總結
本篇為大家介紹了 OCI 的前世今生,以及 OCI Image 的規範和特點,另外也介紹了一個可用於在 OCI Image 和 Docker Image 之間映象轉換的工具 skopeo
。另外介紹了一些可用於在 CI 環境或其他有特定場景環境下替代 Docker build 的工具,請大家按實際需求進行選擇。
歡迎訂閱我的文章公眾號【MoeLove】