您好,登錄后才能下訂單哦!
作者 | 聲東 阿里云售后技術專家
導讀:相比 K8s 集群的其他功能,私有鏡像的自動拉取,看起來可能是比較簡單的。而鏡像拉取失敗,大多數情況下都和權限有關。所以,在處理相關問題的時候,我們往往會輕松的說:這問題很簡單,肯定是權限問題。但實際的情況是,我們經常為一個問題,花了多個人的時間卻找不到原因。這主要還是我們對鏡像拉取,特別是私有鏡像自動拉取的原理理解不深。這篇文章,作者將帶領大家討論下相關原理。
順序上來說,私有鏡像自動拉取會首先通過阿里云 Acr credential helper 組件,再經過 K8s 集群的 API Server 和 kubelet 組件,最后到 docker 容器運行時。但是我的敘述,會從后往前,從最基本的 docker 鏡像拉取說起。
為了討論方便,我們來設想一個場景。很多人會使用網盤來存放一些文件,像照片,文檔之類。當我們存取文件的時候,我們需要給網盤提供賬戶密碼,這樣網盤服務就能驗證我們的身份。這時,我們是文件資源的所有者,而網盤則扮演著資源服務器的角色。賬戶密碼作為認證方式,保證只有我們自己可以存取自己的文件。
cdn.com/6b9d7ab4225d4d10ec91b23f609d34f92f6df4fd.png">
這個場景足夠簡單,但很快我們就遇到新需求:我們需要使用一個在線制作相冊的應用。按正常的使用流程,我們需要把網盤的照片下載到本地,然后再把照片上傳到電子相冊。這個過程是比較很繁瑣的。我們能想到的優化方法是,讓相冊應用,直接訪問網盤來獲取我們的照片,而這需要我們把用戶名和密碼授權給相冊應用使用。
這樣的授權方式,優點顯而易見,但缺點也是很明顯的:我們把網盤的用戶名密碼給了相冊服務,相冊服務就擁有了讀寫網盤的能力,從數據安全角度,這個是很可怕的。其實這是很多應用都會遇到的一個一般性場景。私有鏡像拉取其實也是這個場景。這里的鏡像倉庫,就跟網盤一樣,是資源服務器,而容器集群則是三方服務,它需要訪問鏡像倉庫獲取鏡像。
OAuth 協議是為了解決上述問題而設計的一種標準方案,我們的討論針對 2.0 版本。相比把賬戶密碼直接給三方應用,此協議采用了一種間接的方式來達到同樣的目的。如下圖,這個協議包括六個步驟,分別是三方應用獲取用戶授權,三方應用獲取臨時 Token 以及三方應用存取資源。
這六步理解起來不容易,主要是因為安全協議的設計,需要考慮協議的易證明性,所以我們換一種方式來解釋這個協議。簡單來說,這個協議其實就做了兩件事情:
如果用網盤的例子來說明的話,那就是用戶授權網盤服務給相冊應用創建臨時 token,然后相冊應用使用這個 token 去網盤服務獲取用戶的照片。實際上 OAuth 2.0 各個變種的核心差別,在于第一件事情,就是用戶授權資源服務器的方式。
從上面的描述我們可以看到,資源服務器實際上扮演了鑒權和資源管理兩種角色,這兩者分開實現的話,協議流程會變成下圖這樣。
鏡像倉庫 Registry 的實現,目前使用“把賬戶密碼給三方應用”的方式。即假設用戶對 Docker 足夠信任,用戶直接將賬戶密碼交給 Docker,然后 Docker 使用賬戶密碼跟鑒權服務器申請臨時 token。
首先,我們在拉取私有鏡像之前,要使用 docker login 命令來登錄鏡像倉庫。這里的登錄其實并沒有和鏡像倉庫建立什么會話之類的關系。登錄主要就做了三件事情:
如下圖,當執行登錄命令,這個命會提示輸入賬戶密碼,這件事情對應的是大圖的第一步。
這件事情在協議圖中沒有對應的步驟。它的作用跟 ping 差不多,只是確認下 v2 鏡像倉庫是否在線,以及版本是否匹配。
如果這個訪問成功,則鑒權服務器會返回 jwt 格式的 token 給 docker,然后 docker 會把賬戶密碼編碼并保存在用戶目錄的 .docker/docker.json 文件里。
下圖是我登錄倉庫之后的 docker.json 文件。這個文件作為 docker 登錄倉庫的唯一證據,在后續鏡像倉庫操作中,會被不斷的讀取并使用。其中關鍵信息 auth 就是賬戶密碼的 base64 編碼。
鏡像一般會包括兩部分內容,一個是 manifests 文件,這個文件定義了鏡像的元數據,另一個是鏡像層,是實際的鏡像分層文件。鏡像拉取基本上是圍繞這兩部分內容展開。因為我們這篇文章的重點是權限問題,所以我們這里只以 manifests 文件拉取為例。
拉取 manifests 文件,基本上也會做三件事情:
K8s 集群一般會管理多個節點,每個節點都有自己的 docker 環境。如果讓用戶分別到集群節點上登錄鏡像倉庫,這顯然是很不方便的。為了解決這個問題,K8s 實現了自動拉取鏡像的功能。這個功能的核心,是把 docker.json 內容編碼,并以 Secret 的方式作為 Pod 定義的一部分傳給 Kubelet。
具體來說,步驟如下:
上邊的功能,一定程度上解決了集群節點登錄鏡像倉庫不方便的問題。但是我們在創建 Pod 的時候,仍然需要給 Pod 指定 imagePullSecrets。K8s 通過變更準入控制(Mutating Admission Control)進一步優化了上邊的基本功能。
進一步優化的內容如下:
阿里云容器服務團隊,在 K8s 的基礎上實現了控制器 Acr credential helper。這個控制器可以讓同時使用阿里云 K8s 集群和容器鏡像服務產品的用戶,在不用配置自己賬戶密碼的情況下,自動使用私有倉庫中的容器鏡像。
具體來說,控制器會監聽 acr-configuration 這個 configmap 的變化,其主要關心 acr-registry 和 watch-namespace 這兩個配置。前一個配置指定為臨時賬戶授權的鏡像倉庫地址,后一個配置管理可以自動拉取鏡像的命名空間。當控制器發現有命名空間需要被配置卻沒有被配置的時候,它會通過阿里云容器鏡像服務的 API,來獲取臨時賬戶和密碼。
有了臨時賬戶密碼,Acr credential helper 為命名空間創建對應的 Secret 以及更改 default SA 來引用這個 Secret。這樣,控制器和 K8s 集群本身的功能,一起自動化了阿里云 K8s 集群拉取阿里云容器鏡像服務上的鏡像的全部流程。
理解私有鏡像自動拉取的實現,有一個難點和一個重點。
**“ 阿里巴巴云×××icloudnative×××erverless、容器、Service Mesh等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發×××
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。