Habor是由VMWare公司開源的容器鏡像倉庫。事實上,Habor是在Docker Registry上進行了相應的企業級擴充,進而獲得了更加廣泛的應用,這些新的企業級特性包括:管理使用者界面,基于角色的通路控制 ,AD/LDAP內建以及審計日志等。
容器的核心在于鏡象的概念,由于可以将應用打包成鏡像,并快速的啟動和停止,是以容器成為新的炙手可熱的基礎設施CAAS,并為靈活和持續傳遞包括DevOps提供底層的支援。
而Habor和Docker Registry所提供的容器鏡像倉庫,就是容器鏡像的存儲和分發服務。之是以會有這樣的服務存在,是由于以下三個原因:
-
提供分層傳輸機制,優化網絡傳輸
Docker鏡像是是分層的,而如果每次傳輸都使用全量檔案(是以用FTP的方式并不适合),顯然不經濟。必須提供識别分層傳輸的機制,以層的UUID為辨別,确定傳輸的對象。
-
提供WEB界面,優化使用者體驗
隻用鏡像的名字來進行上傳下載下傳顯然很不友善,需要有一個使用者界面可以支援登陸、搜尋功能,包括區分公有、私有鏡像。
-
支援水準擴充叢集
當有使用者對鏡像的上傳下載下傳操作集中在某伺服器,需要對相應的通路壓力作分解。
上面這些就是Docker Registry所完成的主要工作,而Habor在此之上,又提供了使用者、同步等諸多特性,這篇文章中我們就這幾個方面作一些闡述,同時執行個體代碼介紹Harbor與K8s的內建。
一、Harbor的安全機制
企業中的軟體研發團隊往往劃分為諸多角色,如項目經理、産品經理、測試、運維等。在實際的軟體開發和運維過程中,這些角色對于鏡像的使用需求是不一樣的。從安全的角度,也是需要通過某種機制來進行權限控制的。
舉例來說,開發人員顯然需要擁有對鏡像的讀寫(PULL/PUSH)權限以更新和改正代碼;測試人員中需要讀取(PULL)權限;而項目經理需要對上述的角色進行管理。
Harbor為這種需求提供了使用者和成員兩種管理概念。
在Harbor中,使用者主要分為兩類。一類為管理者,另一類為普通使用者。兩類使用者都可以成為項目的成員。而管理者可以對使用者進行管理。
成員是對應于項目的概念,分為三類:管理者、開發者、訪客。管理者可以對開發者和訪客作權限的配置和管理。測試和運維人員可以訪客身份讀取項目鏡像,或者公共鏡像庫中的檔案。
從項目的角度出發,顯然項目管理者擁有最大的項目權限,如果要對使用者進行禁用或限權等,可以通過修改使用者在項目中的成員角色來實作,甚至将使用者移除出這個項目。

二、Harbor的鏡像同步
為什麼需要鏡像同步
由于對鏡像的通路是一個核心的容器概念,在實際使用過程中,一個鏡像庫可能是不夠用的,下例情況下,我們可能會需要部署多個鏡像倉庫:
- 國外的公有鏡像下載下傳過慢,需要一個中轉倉庫進行加速
- 容器規模較大,一個鏡像倉庫不堪重負
- 對系統穩定性要求高,需要多個倉庫保證高可用性
- 鏡像倉庫有多級規劃,下級倉庫依賴上級倉庫
更常用的場景是,在企業級軟體環境中,會在軟體開發的不同階段存在不同的鏡像倉庫,
- 在開發環境庫,開發人員頻繁修改鏡像,一旦代碼完成,生成穩定的鏡像即需要同步到測試環境。
- 在測試環境庫,測試人員對鏡像是隻讀操作,測試完成後,将鏡像同步到預上線環境庫。
- 在預上線環境庫,運維人員對鏡像也是隻讀操作,一旦運作正常,即将鏡像同步到生産環境庫。
- 在這個流程中,各環境的鏡像庫之間都需要鏡像的同步和複制。
Harbor的鏡像同步機制
有了多個鏡像倉庫,在多個倉庫之間進行鏡像同步馬上就成為了一個普遍的需求。比較傳統的鏡像同步方式,有兩種:
- 第一種方案,使用Linux提供的RSYNC服務來定義兩個倉庫之間的鏡像資料同步。
- 第二種方案,對于使用IaaS服務進行鏡像存儲的場景,利用IaaS的配置工具來對鏡像的同步進行配置。
這兩種方案都依賴于倉庫所在的存儲環境,而需要采用不同的工具政策。Harbor則提供了更加靈活的方案來處理鏡像的同步,其核心是三個概念:
- 用Harbor自己的API來進行鏡像下載下傳和傳輸,作到與底層存儲環境解耦。
- 利用任務排程和監控機制進行複制任務的管理,保障複制任務的健壯性。在同步過程中,如果源鏡像已删除,Harbor會自動同步删除遠端的鏡像。在鏡像同步複制的過程中,Harbor會監控整個複制過程,遇到網絡等錯誤,會自動重試。
-
提供複制政策機制保證項目級的複制需求。在Harbor中,可以在項目中建立複制政策,來實作對鏡像的同步。與Docker
Registry的不同之處在于,Harbor的複制是推(PUSH)的政策,由源端發起,而Docker
Registry的複制是拉(PULL)的政策,由目标端發起。
Harbor的多級部署
在實際的企業級生産運維場景,往往需要跨地域,跨層級進行鏡像的同步複制,比如集團企業從總部到省公司,由省公司再市公司的場景。
這一部署場景可簡化如下圖:
更複雜的部署場景如下圖:
三、Harbor與K8s的內建實踐
Harbor提供了基于角色的通路控制機制,并通過項目來對鏡像進行組織和通路權限的控制。kubernetes中通過namespace來對資源進行隔離,在企業級應用場景中,通過将兩者進行結合可以有效将kubernetes使用的鏡像資源進行管理和通路控制,增強鏡像使用的安全性。尤其是在多租戶場景下,可以通過租戶、namespace和項目相結合的方式來實作對多租戶鏡像資源的管理和通路控制。
內建的核心概念和關鍵步驟
兩者的內建,一個核心概念是k8s的secret。作為kubernetes中一個重要的資源secret,它的設計初衷是為了解決容器在通路外部網絡或外部資源時驗證的問題,例如通路一個Git倉庫,連接配接一個資料庫,設定一些密碼配置等,需要額外驗證的場景Secret存儲了敏感資料,例如能允許容器接受請求的權限令牌。通過将Harbor的使用者資訊與K8s的Secret相關聯,即達成了兩者的內建。步驟如下:
- 在Harbor中建立建立使用者,項目,将項目設定為私有。
- 将建立的使用者加入到項目中,設定使用者的角色為開發者或者為項目管理者。確定該賬戶具有拉取該倉庫鏡像的權限。
- 建立K8s下的Secret,其中secret中的使用者名、密碼和郵箱位址資訊為在Harbor中建立的使用者的資訊。
在此過程中需要注意的是,第三步中建立的secret,對應的使用者必須在Harbor的對應私庫中有下載下傳鏡像的權限,否則應用部署時會報無法下載下傳鏡像。
舉例來說
- 在Harbor中建立了使用者,如userD
- 在Harbor中建立一個私有項目,如projectA
- 在Harbor中使用Docker指令行登陸并上傳鏡像至步驟2中的私有庫
- 在K8s中建立Namespace
- 在K8s的Namespace中建立SecretC,該Secret對應Harbor中的使用者賬号userD
使用Harbor私庫中的鏡像在K8s的Namespace中部署應用,指定鏡像下載下傳時使用上面建立的SecretC
如果隻需要能夠拉取Harbor的鏡像在K8s中部署應用,Harbor中的userD需要在projectA中有最低權限的訪客成員角色。
Harbor與K8s內建的代碼實踐
p_w_picpathPullSecret在K8s中用來儲存鏡像倉庫的認證資訊,以友善Kubelet在啟動Pod時,能夠獲得鏡像倉庫的認證資訊,確定能Kubelet夠有權限從鏡像倉庫中下載下傳Pod所需的鏡像。
首先我們來看一下k8s中的ImagePull類型的Secret如何來建立。官方文檔為:https://kubernetes.io/docs/user-guide/p_w_picpaths/#specifying-p_w_picpathpullsecrets-on-a-pod
以下代碼實踐Harbor版本是0.3.5。
首先,我們需要在harbor中選擇一個使用者,使用它的使用者名與密碼生成一個字元串,使用者名與密碼中間用冒号相連,然後使用base64對它進行加密,如下所示:[root@k8s-01
~]# echo “test:tT001″|base64dGVzdDp0VDAwMQo=
然後,我們需要生成一個dockerconfig.json,需要使用上面生成的加密字元串,内容大緻如下,假如對應的harbor庫的位址為:hub.testharbor.com:
{
"auths":{
"hub.testharbor.com": {
"auth": "dGVzdDp0VDAwMQo=",
"email": ""
}
}
}
我們需要把這整個json使用base64進行加密。生成的字元串可能比較長,需要加上 -w 0 參數,不讓它換行。将上面的json儲存成dockerconfig.json檔案,然後執行指令:
[root@k8s-01 secret]# cat dockerconfig.json |base64 -w 0
ewogICJhdXRocyI6IHsKICAgICJodWIudGVzdGhhcmJvci5jb20iOiB7CiAgICAgICJhdXRoIjogImRHVnpkRHAwVkRBd01Rbz0iLAogICAgICAiZW1haWwiOiAiIgogICAgfQogIH0KfQo=
現在,我們可以來建立secret所需的yaml了。secret建立的時候,必須指定namespace。多個namespace中的secret可以同名。假如我們需要在名為hub中的namespace中建立名為testsecret的secret,對應的secret.yaml内容如下。需要使用上面生成的加密字元串。
此時在k8s中使用kubectl create 指令即可建立對應的secret:
kubectl create -f secret.yaml
最後,在部署應用的時候,我們需要為Pod指定下載下傳鏡像所需的secret名字,如下所示:
apiVersion: v1
kind: Pod
metadata:
name: httpdpod namespace: hub
spec:
containers:
- name: httpdpod
p_w_picpath:hub.testharbor.com/project1/httpd:2.2
p_w_picpathPullSecrets:
- name:testsecret
注意,要想部署成功,test使用者必須為harbor中的project1項目中的成員,它才能有下載下傳這個httpd:2.2的權限。
容器雲的使用者與內建
作為容器雲運作時,Harbor的使用者與K8s的Secret可以有更集約的整合方式。在我們的項目實踐中,一個容器雲的使用者與一個Harbor中同名Project一一對應,但此使用者可以在k8s中可以建立多個namespace。為了簡化管理過程,目前我們的做法是:
- 在容器雲啟動過程中,自動在Harbor中建立一個專用使用者,專門用來在各私庫中下載下傳鏡像
- 每個在Harbor中建立的私庫,都會将這個專用使用者添加為它的訪客成員角色 ,使這個專用使用者擁有下載下傳此庫中鏡像的權限
- 在K8s中,每建立一個新的namespace的同時,在此namespace下,使用上面的專用使用者的資訊建立固定名稱的secret(多namespace中可存在同名secret)
- 部署應用時,指定p_w_picpathPullSecrets下面的名稱為上面固定的secret名稱。
四、兩個小貼士
使用線上工具讓Harbor的接口文檔更易讀
Harbor對外提了restful形式的接口供其它系統內建,它的接口描述以swagger格式的文檔包含在源碼中,文檔位址為:https://github.com/vmware/harbor/blob/master/docs/swagger.yaml。
目前,越來越多的系統使用restful的接口對外暴露服務,而swagger已經成了事實上的restful接口的描述标準。直接使用文本編輯器去檢視這種swagger文檔,會有點暈,沒法友善清晰地檢視接口的整體結構。我們可以借助一些工具來看這些文檔。線上的,比如官方提供的swagger線上編輯器,把文檔内容複制至左邊,右邊即可顯示html格式的文檔,可以折疊等,讓人對所有接口一目了然。離線的,則可以在一些編輯器安裝插件,将它同樣轉化成html進行檢視,比如vscode,安裝
Swagger
Viewer插件即可。關于Swagger的使用,也可以閱讀我的同僚李小飛的文章《微服務架構實戰:Swagger規範RESTful API》。
兩種格式的文檔展示如下:
小貼士:Harbor的Java Client開源實作
對于熟悉Java程式設計的使用者來說,Harbor官方沒有提供java client,但是在github上也有人寫了相關的項目,項目位址:https://github.com/grissomsh/harbor-java-client
五、總結
本文主要介紹了Harbor的使用者機制、鏡像同步和與K8s的內建實踐。
Harbor的使用者機制分為系統使用者和項目成員兩類。使用者可以成為項目成員,而不同成員有不同的鏡像讀寫權限。
Harbor的同步政策和任務排程機制,為鏡像庫間的鏡像同步提供了靈活的機制。
利用K8s的Secret與Harbor使用者的關聯,可以在K8s中拉取Harbor私有庫中的鏡像來部署應用。我們也用代碼進行了舉例。
最後,再分享幾個在Harbor(0.3.5)的使用過程中碰到的小坑:
- 在Harbor中建立使用者時,密碼必須為複雜密碼。但是修改時,沒有了此限制