開源Registry項目Harbor源代碼結構解析

上週咱們介紹了Harbor開源企業級容器Registry的架構,得到了社區不少朋友的反饋和建議,再次一併感謝,但願和你們一塊兒,共同建設一個優秀的開源項目。本文請Harbor項目工程師尹文開介紹源碼結構,幫助開發和運維人員理解代碼的工做原理。

css

Harbor項目概覽

容器應用的開發和運行離不開可靠的鏡像管理。從安全和效率等方面考慮,在企業私有環境內部署的Registry服務是很是必要的。Harbor(https://github.com/vmware/harbor)是由VMware中國研發團隊爲企業用戶設計的Registry Server開源項目,包括了權限管理(RBAC)、圖形管理界面、LDAP/AD集成、審計、自我註冊、HA等企業必需的功能,同時針對中國用戶的特色,原生支持中文,並計劃實現鏡像複製(roadmap)等功能。

本文主要介紹Harbor項目的源碼結構,幫助開發和運維人員理解其工做原理。
html

主要組件

Harbor系統由五個容器組成:Proxy、Core Services(包含UI, tokenservice和webhook)、Database、Registry和Log Collector。

Proxy提供反向代理服務,用戶的不一樣請求由Proxy分發到後端的UI或者Registry。Harbor中使用的是官方的nginx鏡像。
Core Services是Harbor項目的核心組件,主要提供權限管理、審計、管理界面UI、token service以及可供其餘系統調用的API等功能。
Database提供數據持久化服務,採用了官方的mysql鏡像。
Registry是Docker官方的開源的Registry鏡像,主要提供鏡像的存儲和分發功能。
Log Collector負責收集其餘容器的日誌並進行日誌輪轉。

各個容器之間的關係以下圖所示:
mysql

源碼結構

如下所述主要爲Core Services組件的源碼結構,經過根目錄下的Dockerfile能夠構建出Core Services的鏡像。另外Deploy目錄下的db和log分別對應Database和Log Collector的Dockerfile鏡像構建文件,而Nginx和Registry則都是採用的官方鏡像。

| -- api (Harbor提供的外部調用的API)
| -- auth (認證模塊,目前提供兩種方式:數據庫和LDAP)
| -- db (數據庫認證)
| -- ldap (LDAP認證)
| -- controllers (控制器相關代碼)
| -- dao (數據持久層)
| -- Deploy (部署相關代碼)
| -- db (構建Database鏡像的源碼)
| -- log (構建Log Collector鏡像的源碼)
| -- docker-compose.yml (運行Harbor的docker compose文件)
| -- docs (文檔)
| -- log (log工具)
| -- models (數據庫映射的模型代碼)
| -- routers (路由相關代碼)
| -- service (服務)
| -- notification.go (處理Registry發來的鏡像上傳或下載等事件)
| -- token.go (爲Registry提供鑑權服務)
| -- static (js、css等文件)
| -- utils (工具類)
| -- vendor (依賴的第三方源碼)
| -- views (html模版文件)
| -- Dockerfile (構建Core Services鏡像的Dockerfile)
| -- main.go (入口函數)
nginx

源碼分析

下面以獲取項目列表和獲取某個項目的詳細信息爲例來分析Harbor源碼。

Harbor項目使用了go語言開發,WEB框架採用beego。main.go、routers目錄和controllers目錄分別對應了入口函數、路由函數目錄和控制器函數目錄。當Core Services啓動時,routers目錄下的相應函數會將各個控制器與其所對應的用戶請求URL進行註冊,這樣當不一樣的用戶請求到達的時候,不一樣的控制器邏輯就會被觸發。主要處理流程以下圖所示:
當獲取項目列表時會發送請求http://hostname/api/projects/,該請求首先到達Nginx。Nginx的配置文件以下:

server {
listen 80;

location / {
proxy_passhttp://ui/;

}

location /v1/ {
return 404;
}

location /v2/ {
proxy_passhttp://registry/v2/;

}

location/service/ {
proxy_passhttp://ui/service/;

}
}

根據配置文件該請求會被轉發到http://ui/,也即Core Services中的UI。根據UI中routers/router.go中定義的規則:

beego.Router( "/api/projects/?:id",&api.ProjectAPI{} )

可知該請求最終是由api包中的ProjectAPI的Get方法來處理的。ProjectAPI結構體的定義以下:

typeProjectAPI struct {
BaseAPI
userID int
projectID int64
}

在beego中,控制器處理用戶請求的方法執行以前首先會執行Prepare()方法來進行一些準備或者校驗操做,ProjectAPI定義的Prepare()方法以下:

func(p *ProjectAPI) Prepare() {
p.userID = p.ValidateUser()

}

Prepare()中調用BaseAPI中的ValidateUser方法檢查用戶的合法性,並將用戶ID賦值給ProjectAPI的userID屬性。以後執行Get方法來處理用戶的請求:

func(p *ProjectAPI) Get() {
queryProject :=models.Project{UserID: p.userID}

projectList, err :=dao.QueryProject(queryProject)

for i := 0; i < len(projectList); i++{
if isProjectAdmin(p.userID,projectList[i].ProjectID) {
projectList[i].Togglable= true
}
}
p.Data["json"] = projectList
p.ServeJSON()
}

Get方法中調用dao包中的QueryProject()方法來獲取項目列表,以後遍歷列表判斷該用戶是否對此項目具備administrator的權限,最終返回項目列表的JSON數據,這次用戶請求處理完畢。

當獲取某個項目的詳細信息時會發送請求http://hostname/registry/detail,該請求一樣會通過Nginx和Router並最終到達其對應的Controller的處理方法以下:

func (idc *ItemDetailController) Get() {
//具體處理邏輯

idc.ForwardTo("page_title_item_details","item-detail")
}

具體的處理邏輯此處忽略。該方法的最後一步調用idc.ForwardTo(「page_title_item_details」,」item-detail」)定位對應的HTML模版文件。模版文件默認的存放目錄爲views,「item-detail」爲模板文件名,所以該語句最終定位到views/item-detail.tpl的文件。通過數據填充最終生成對應的HTML文件並返回。

歡迎廣大用戶使用Harbor項目並反饋意見和建議,也歡迎加入咱們貢獻代碼。若是您是Harbor的用戶或開發者,請長按下面二維碼加入Harbor開源項目羣,以方便溝通。Github網址:
https://github.com/vmware/harbor
git

相關文章
相關標籤/搜索