做者 | 聲東 阿里雲售後技術專家docker
導讀:相比 K8s 集羣的其餘功能,私有鏡像的自動拉取,看起來多是比較簡單的。而鏡像拉取失敗,大多數狀況下都和權限有關。因此,在處理相關問題的時候,咱們每每會輕鬆的說:這問題很簡單,確定是權限問題。但實際的狀況是,咱們常常爲一個問題,花了多我的的時間卻找不到緣由。這主要仍是咱們對鏡像拉取,特別是私有鏡像自動拉取的原理理解不深。這篇文章,做者將帶領你們討論下相關原理。json
順序上來講,私有鏡像自動拉取會首先經過阿里雲 Acr credential helper 組件,再通過 K8s 集羣的 API Server 和 kubelet 組件,最後到 docker 容器運行時。可是個人敘述,會從後往前,從最基本的 docker 鏡像拉取提及。安全
爲了討論方便,咱們來設想一個場景。不少人會使用網盤來存放一些文件,像照片,文檔之類。當咱們存取文件的時候,咱們須要給網盤提供帳戶密碼,這樣網盤服務就能驗證咱們的身份。這時,咱們是文件資源的全部者,而網盤則扮演着資源服務器的角色。帳戶密碼做爲認證方式,保證只有咱們本身能夠存取本身的文件。服務器
這個場景足夠簡單,但很快咱們就遇到新需求:咱們須要使用一個在線製做相冊的應用。按正常的使用流程,咱們須要把網盤的照片下載到本地,而後再把照片上傳到電子相冊。這個過程是比較很繁瑣的。咱們能想到的優化方法是,讓相冊應用,直接訪問網盤來獲取咱們的照片,而這須要咱們把用戶名和密碼受權給相冊應用使用。微信
這樣的受權方式,優勢顯而易見,但缺點也是很明顯的:咱們把網盤的用戶名密碼給了相冊服務,相冊服務就擁有了讀寫網盤的能力,從數據安全角度,這個是很可怕的。其實這是不少應用都會遇到的一個通常性場景。私有鏡像拉取其實也是這個場景。這裏的鏡像倉庫,就跟網盤同樣,是資源服務器,而容器集羣則是三方服務,它須要訪問鏡像倉庫獲取鏡像。less
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 集羣拉取阿里雲容器鏡像服務上的鏡像的所有流程。
理解私有鏡像自動拉取的實現,有一個難點和一個重點。
「 阿里巴巴雲原生微信公衆號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的技術公衆號。」