K8s 從懵圈到熟練 映象拉取這件小事

2021-09-28 15:19:06 字數 4073 閱讀 3883

順序上來說,私有映象自動拉取會首先通過阿里雲 acr credential helper 元件,再經過 k8s 集群的 api server 和 kubelet 元件,最後到 docker 容器執行時。但是我的敘述,會從後往前,從最基本的 docker 映象拉取說起。

映象拉取這件小事

為了討論方便,我們來設想乙個場景。很多人會使用網盤來存放一些檔案,像**,文件之類。當我們訪問檔案的時候,我們需要給網盤提供賬戶密碼,這樣網盤服務就能驗證我們的身份。這時,我們是檔案資源的所有者,而網盤則扮演著資源伺服器的角色。賬戶密碼作為認證方式,保證只有我們自己可以訪問自己的檔案。

這樣的授權方式,優點顯而易見,但缺點也是很明顯的:我們把網盤的使用者名稱密碼給了相簿服務,相簿服務就擁有了讀寫網盤的能力,從資料安全角度,這個是很可怕的。其實這是很多應用都會遇到的乙個一般性場景。私有映象拉取其實也是這個場景。這裡的映象倉庫,就跟網盤一樣,是資源伺服器,而容器集群則是三方服務,它需要訪問映象倉庫獲取映象。

理解 oauth 2.0 協議

oauth 協議是為了解決上述問題而設計的一種標準方案,我們的討論針對 2.0 版本。相比把賬戶密碼直接給三方應用,此協議採用了一種間接的方式來達到同樣的目的。如下圖,這個協議包括六個步驟,分別是三方應用獲取使用者授權,三方應用獲取臨時 token 以及三方應用訪問資源。

這六步理解起來不容易,主要是因為安全協議的設計,需要考慮協議的易證明性,所以我們換一種方式來解釋這個協議。簡單來說,這個協議其實就做了兩件事情:

在使用者授權的情況下,三方應用獲取 token 所表示的臨時訪問許可權;

然後三方應用使用這個 token 去獲取資源。

如果用網盤的例子來說明的話,那就是使用者授權網盤服務給相簿應用建立臨時 token,然後相簿應用使用這個 token 去網盤服務獲取使用者的**。實際上 oauth 2.0 各個變種的核心差別,在於第一件事情,就是使用者授權資源伺服器的方式。

最簡單的一種,適用於三方應用本身就擁有被訪問資源控制許可權的情況。這種情況下,三方應用只需要用自己的賬戶密碼登入資源伺服器並申請臨時 token 即可;

當使用者對三方應用足夠信任的情況下,使用者直接把賬戶密碼給三方應用,三方應用使用賬戶密碼向資源伺服器申請臨時 token;

使用者通過資源伺服器提供的介面,登入資源伺服器並授權資源伺服器給三方應用發放 token;

完整實現 oauth 2.0 協議,也是最安全的。三方應用首先獲取以驗證碼表示的使用者授權,然後用此驗證碼從資源伺服器換取臨時 token,最後使用 token 訪問資源。

從上面的描述我們可以看到,資源伺服器實際上扮演了鑑權和資源管理兩種角色,這兩者分開實現的話,協議流程會變成下圖這樣。

docker 扮演的角色

大圖映象倉庫 registry 的實現,目前使用「把賬戶密碼給三方應用」的方式。即假設使用者對 docker 足夠信任,使用者直接將賬戶密碼交給 docker,然後 docker 使用賬戶密碼跟鑑權伺服器申請臨時 token。

理解 docker login

首先,我們在拉取私有映象之前,要使用 docker login 命令來登入映象倉庫。這裡的登入其實並沒有和映象倉庫建立什麼會話之類的關係。登入主要就做了三件事情:

第一件事情是跟使用者要賬戶密碼。

如下圖,當執行登入命令,這個命會提示輸入賬戶密碼,這件事情對應的是大圖的第一步。

第二件事情,docker 訪問映象倉庫的 https 位址,並通過挑戰 v2 介面來確認,介面是否會返回 docker-distribution-api-version 頭欄位。

第三件事情,docker 使用使用者提供的賬戶密碼,訪問 www-authenticate 頭欄位返回的鑑權伺服器的位址 bearer realm。

如果這個訪問成功,則鑑權伺服器會返回 jwt 格式的 token 給 docker,然後 docker 會把賬戶密碼編碼並儲存在使用者目錄的 .docker/docker.json 檔案裡。

下圖是我登入倉庫之後的 docker.json 檔案。這個檔案作為 docker 登入倉庫的唯一證據,在後續映象倉庫操作中,會被不斷的讀取並使用。其中關鍵資訊 auth 就是賬戶密碼的 base64 編碼。

拉取映象是怎麼回事

映象一般會包括兩部分內容,乙個是 manifests 檔案,這個檔案定義了映象的元資料,另乙個是映象層,是實際的映象分層檔案。映象拉取基本上是圍繞這兩部分內容展開。因為我們這篇文章的重點是許可權問題,所以我們這裡只以 manifests 檔案拉取為例。

拉取 manifests 檔案,基本上也會做三件事情:

首先,docker 直接訪問映象manifests的位址,以便獲取 www-authenticate 頭欄位。這個字段包括鑑權伺服器的位址 bearer realm,映象服務位址 service,以及定義了映象和操作的 scope。

接著,docker 訪問上邊拿到的 bearer realm 位址來鑑權,以及在鑑權之後獲取乙個臨時的 token。這對應協議大圖使用賬戶密碼獲取臨時 token 這一步,使用的賬戶密碼直接讀取自 docker.json 檔案。

k8s 實現的私有映象自動拉取

基本功能

k8s 集群一般會管理多個節點,每個節點都有自己的 docker 環境。如果讓使用者分別到集群節點上登入映象倉庫,這顯然是很不方便的。為了解決這個問題,k8s 實現了自動拉取映象的功能。這個功能的核心,是把 docker.json 內容編碼,並以 secret 的方式作為 pod 定義的一部分傳給 kubelet。

具體來說,步驟如下:

建立 secret。這個 secret 的 .dockerconfigjson 資料項包括了乙份 base64 編碼的 docker.json 檔案;

建立 pod,且 pod 編排中 imagepullsecrets 指向第一步建立的 secret;

kubelet 作為集群控制器,監控著集群的變化。當它發現新的 pod 被建立,就會通過 api server 獲取 pod 的定義,這包括 imagepullsecrets 引用的 secret;

kubelet 呼叫 docker 建立容器且把 .dockerconfigjson 傳給 docker;

最後 docker 使用解碼出來的賬戶密碼拉取映象,這和上一節的方法一致。

高階方式

上邊的功能,一定程度上解決了集群節點登入映象倉庫不方便的問題。但是我們在建立 pod 的時候,仍然需要給 pod 指定 imagepullsecrets。k8s 通過變更准入控制(mutating admission control)進一步優化了上邊的基本功能。

進一步優化的內容如下:

在第一步建立 secret 之後,新增 default service account 對 imagepullsecrets 的引用;

pod 預設使用 default service account,而 service account 變更准入控制器會在 default service account 引用 imagepullsecrets 的情況下,新增 imagepullsecrets 配置到 pod 的編排裡。

阿里雲實現的 acr credential helper

阿里雲容器服務團隊,在 k8s 的基礎上實現了控制器 acr credential helper。這個控制器可以讓同時使用阿里雲 k8s 集群和容器映象服務產品的使用者,在不用配置自己賬戶密碼的情況下,自動使用私有倉庫中的容器映象。

具體來說,控制器會監聽 acr-configuration 這個 configmap 的變化,其主要關心 acr-registry 和 watch-namespace 這兩個配置。前乙個配置指定為臨時賬戶授權的映象倉庫位址,後乙個配置管理可以自動拉取映象的命名空間。當控制器發現有命名空間需要被配置卻沒有被配置的時候,它會通過阿里雲容器映象服務的 api,來獲取臨時賬戶和密碼。

有了臨時賬戶密碼,acr credential helper 為命名空間建立對應的 secret 以及更改 default sa 來引用這個 secret。這樣,控制器和 k8s 集群本身的功能,一起自動化了阿里雲 k8s 集群拉取阿里雲容器映象服務上的映象的全部流程。

總結理解私有映象自動拉取的實現,有乙個難點和乙個重點。

難點是 oauth 2.0 安全協議的原理,上文主要分析了為什麼 oauth 會這麼設計;

重點是集群控制器原理,因為整個自動化的過程,實際上是包括 admission control 和 acr credential helper 在內的多個控制器協作的結果。

K8s 從懵圈到熟練 集群網路詳解

作者 聲東 阿里雲售後技術專家 總體上來說,阿里雲 k8s 集群網路配置完成之後,如下圖所示 包括集群 cidr vpc 路由表 節點網路 節點的 podcidr 節點上的虛擬網橋 cni0 連線 pod 和網橋的 veth 等部分。基本上我們可以把這些配置分三種情況來理解 集群配置,節點配置以及 ...

K8s集群從私有映象倉庫中拉取映象

node節點已經配置了docker私有庫,docker pull映象可以正常拉取,但是在k8s master節點建立deployment時,pod一直處於imagepullbackoff,errimagepull狀態來回切換。kubectl describe pod 檢視pod錯誤提示,看到fail...

K8s 拉取私有倉庫映象方法

一般公司開發的image一般放在私有倉庫,不對外開放。在阿里雲建立乙個私有映象庫,並構建乙個image 建立阿里雲映象私有倉庫和構建image方法參考 docker 拉取私有映象的方法 a.登陸私有倉庫 login succeededb.拉取映象 c.儲存私有倉庫的登陸資訊檔案位置,如果不logou...