源地址:harbor鏡像倉庫原理和安裝
目錄
------------------------------------------------------------------------
一:Harbor簡介
Harbor是一個用於存儲和分發Docker鏡像的企業級Registry服務器。
Harbor和Registry都是Docker的鏡像倉庫,但是Harbor作為更多企業的選擇,是因為相比較於Regisrty來說,它具有很多的優勢。
1. docker registry的缺點:
- 缺少認證機制,任何人都可以隨意拉取及上傳鏡像,安全性缺失
- 缺乏鏡像清理機制,鏡像可以push卻不能刪除,日積月累,占用空間會越來越大
- 缺乏相應的擴展機制
2. Harbor優點
a.提供分層傳輸機制,優化網絡傳輸
Docker鏡像是是分層的,而如果每次傳輸都使用全量文件(所以用FTP的方式並不適合),顯然不經濟。必須提供識別分層傳輸的機制,以層的UUID為標識,確定傳輸的對象。
b.提供WEB界面,優化用戶體驗
只用鏡像的名字來進行上傳下載顯然很不方便,需要有一個用戶界面可以支持登陸、搜索功能,包括區分公有、私有鏡像。
c.支持水平擴展集群
當有用戶對鏡像的上傳下載操作集中在某服務器,需要對相應的訪問壓力作分解。
d.良好的安全機制
企業中的開發團隊有很多不同的職位,對於不同的職位人員,分配不同的權限,具有更好的安全性。
e.Harbor提供了基於角色的訪問控制機制,並通過項目來對鏡像進行組織和訪問權限的控制。
kubernetes中通過namespace來對資源進行隔離,在企業級應用場景中,通過將兩者進行結合可以有效將kubernetes使用的鏡像資源進行管理和訪問控制,增強鏡像使用的安全性。尤其是在多租戶場景下,可以通過租戶、namespace和項目相結合的方式來實現對多租戶鏡像資源的管理和訪問控制。
3. Harbor介紹
鏡像的存儲harbor使用的是官方的docker registry(v2命名是distribution)服務去完成。harbor在docker distribution的基礎上增加了一些安全、訪問控制、管理的功能以滿足企業對於鏡像倉庫的需求。harbor以docker-compose的規范形式組織各個組件,並通過docker-compose工具進行啟停。
docker的registry是用本地存儲或者s3都是可以的,harbor的功能是在此之上提供用戶權限管理、鏡像復制等功能,提高使用的registry的效率。Harbor的鏡像拷貝功能是通過docker registry的API去拷貝,這種做法屏蔽了繁瑣的底層文件操作、不僅可以利用現有docker registry功能不必重復造輪子,而且可以解決沖突和一致性的問題。
Harbor官方網站:http://vmware.github.io/harbor/
Harbor源碼地址:https://github.com/vmware/harbor/
二:Harbor主要組件
Proxy:對應啟動組件nginx。它是一個nginx反向代理,代理Notary client(鏡像認證)、Docker client(鏡像上傳下載等)和瀏覽器的訪問請求(CoreService)給后端的各服務;
UI(Core Service):對應啟動組件harbor-ui。底層數據存儲使用mysql數據庫,主要提供了四個子功能:
- UI:一個web管理頁面ui;
- API:Harbor暴露的API服務;
- Auth:用戶認證服務,decode后的token中的用戶信息在這里進行認證;auth后端可以接db、ldap、uaa三種認證實現;
- Token服務(上圖中未體現):負責根據用戶在每個project中的role來為每一個docker push/pull命令issuing一個token,如果從docker client發送給 registry的請求沒有帶token,registry會重定向請求到token服務創建token。
Registry:對應啟動組件registry。負責存儲鏡像文件,和處理鏡像的pull/push命令。Harbor對鏡像進行強制的訪問控制,Registry會將客戶端的每個pull、push請求轉發到token服務來獲取有效的token。
Admin Service:對應啟動組件harbor-adminserver。是系統的配置管理中心附帶檢查存儲用量,ui和jobserver啟動時候需要加載adminserver的配置;
Job Sevice:對應啟動組件harbor-jobservice。負責鏡像復制工作的,他和registry通信,從一個registry pull鏡像然后push到另一個registry,並記錄job_log;
Log Collector:對應啟動組件harbor-log。日志匯總組件,通過docker的log-driver把日志匯總到一起;
Volnerability Scanning:對應啟動組件clair。負責鏡像掃描
Notary:對應啟動組件notary。負責鏡像認證
DB:對應啟動組件harbor-db,負責存儲project、 user、 role、replication、image_scan、access等的metadata數據。
需要說明的是,harbor的每個組件都是以Docker容器的形式構建的,可以使用Docker Compose來進行部署,當然,如果你的環境中使用了kubernetes,harbor也提供了kubernetes的配置文件。
docker鏡像:harbor-jobservice, nginx, harbor-core, redis, harbor-portal, harbor-db, registry, registryctl, harbor-log
harbor共有8個容器組成:
- ui:harbor的核心服務。
- log:運行着rsyslog的容器,進行日志收集。
- mysql:由官方mysql鏡像構成的數據庫容器
- nginx:使用Nginx做反向代理
- registry:官方的Docker registry
- adminserver:harbor的配置數據管理器
- jobservice:Harbor的任務管理服務。
- redis:用於存儲session
-------------------
三:Harbor架構

1. Harbor登錄過程
假設Harbor部署在IP為192.168.1.10的主機上。用戶運行docker命令將登錄請求發送到Harbor:
$ docker login 192.168.1.10
用戶輸入所需憑證后,Docker客戶端向地址“192.168.1.10/v2/”發送HTTP GET請求。Harbor的不同容器將按照以下步驟進行處理:
(a)首先,該請求由監聽端口80的代理容器接收。容器中的Nginx將請求轉發到后端的registry容器。
(b)Registry容器已配置為基於令牌的身份驗證,因此它返回錯誤代碼401,通知Docker客戶端從指定的URL獲取有效的令牌。在Harbor,這個URL指向核心服務的令牌服務;
(c)Docker客戶端收到此錯誤代碼后,會根據HTTP規范的基本認證向令牌服務URL發送請求,將請求頭部嵌入用戶名和密碼;
(d)通過端口80將該請求發送到代理容器后,Nginx會根據預先配置的規則再次將該請求轉發給UI容器。UI容器內的令牌服務接收請求,解碼請求並獲取用戶名和密碼;
(e)獲取用戶名和密碼后,令牌服務將檢查數據庫,並通過MySql數據庫中的數據驗證用戶。當令牌服務配置為LDAP / AD身份驗證時,它將對外部LDAP / AD服務器進行身份驗證。認證成功后,令牌服務返回一個表示成功的HTTP代碼。HTTP響應體包含由私鑰生成的令牌。
2. Docker push 的過程
(我們省略了代理轉發步驟,上圖顯示了Docker推送過程中不同組件之間的通信)
用戶成功登錄后,Docker Image將通過Docker Push命令發送到Harbor:
# docker push 192.168.1.10/library/hello-world
(a)首先,碼頭客戶端通過向注冊表發送請求重復類似登錄的過程,然后取回令牌服務的URL;
(b)隨后,當接觸令牌服務時,Docker客戶端提供附加信息以在image(library/ hello-world)上應用推送操作的令牌;
(c)收到Nginx轉發的請求后,令牌服務查詢數據庫查詢用戶的角色和權限,以推送image。如果用戶具有適當的權限,則對Push操作的信息進行編碼,並用私鑰對其進行簽名,並向Docker客戶端生成一個令牌;
(d)在Docker客戶端獲取令牌之后,它向包含令牌的頭部向Registry發送推送請求。一旦Registry接收到請求,它將使用公鑰解碼令牌並驗證其內容。公鑰對應於令牌服務的私鑰。如果Registry找到令牌有效推送Image,則Image傳輸過程開始。
四:harbor鏡像倉庫部署
1. 安裝harbor環境
系統版本: centos7.6
確認docker 和 docker-compose版本號(
docker和docker-compose安裝)
[root@harbor harbor]# docker version
Client: Docker Engine - Community
Version: 18.09.7
Server: Docker Engine - Community
Version: 18.09.7
[root@harbor harbor]# docker-compose --version
docker-compose version 1.24.1, build 4667896
2. 安裝harobr鏡像倉庫
github官網地址 https://github.com/goharbor/harbor/releases
[root@harbor ~]# wget https://github.com/goharbor/harbor/releases/download/v1.9.3/harbor-offline-installer-v1.9.3.tgz
[root@harbor ~]# tar -zxvf harbor-offline-installer-v1.9.1.tgz
[root@harbor ~]# cd harbor/
[root@harbor harbor]# ls
harbor.v1.9.1.tar.gz harbor.yml install.sh LICENSE prepare
[root@harbor harbor]# ls keys/ #自己制作證書的位置
ikan.key ikan.pem
3.修改主機名,開啟https認證並安裝
不需要添加域名,到時候nginx直接轉發過來即可,和主機名同時支持
數據默認放置在data_volume: /data下,日志在/var/lib/harbor下
[root@harbor harbor]# vim harbor.yml #修改以下這些地方
hostname: harbor1.ikan.com
https:
port: 443
certificate: /root/harbor/keys/ikan.pem
private_key: /root/harbor/keys/ikan.key
[root@harbor harbor]# ./prepare
prepare base dir is set to /root/harbor
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
loaded secret from file: /secret/keys/secretkey
Generated certificate, key file: /secret/core/private_key.pem, cert file: /secret/registry/root.crt
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir
[root@harbor harbor]# ./install.sh
[Step 0]: checking installation environment ...
Note: docker version: 19.03.2
Note: docker-compose version: 1.24.1
[Step 1]: loading Harbor images ...
cad87ea2da29: Loading layer [==================================================>] 77.02MB/77.02MB
安裝完成后,它會提示你訪問harbor的地址是多少,你就可以直接在瀏覽器中訪問這個地址了。
- 停止服務: docker-compose stop
- 開始服務: docker-compose start
五:Harbor使用
1. 通過界面登陸harbor
https://harbor1.ikan.com ,開啟https后默認只走這個

默認用戶名和密碼 admin Harbor12345

2. 創建鏡像項目kubernetes
路徑:項目 -> 新建項目 -> 項目名稱 kubernetes -> 確認

3. 測試harbor倉庫可用性
[root@harbor2 ~]# docker login harbor1.ikan.com
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
[root@harbor2 ~]# # 登陸成功后,token會存放在 ~/.docker/config.json.文件里
[root@harbor2 ~]# docker tag busybox harbor.ikan.com/kubernetes/busybox:v0.3
[root@harbor2 ~]# docker push harbor.ikan.com/kubernetes/busybox:v0.3
The push refers to repository [harbor.ikan.com/kubernetes/busybox]
eac247cb7af5: Layer already exists
v0.3: digest: sha256:24fd20af232ca4ab5efbf1aeae7510252e2b60b15e9a78947467340607cd2ea2 size: 527
報錯1:鏡像直接上傳到harbor正常,但是通過nginx一直顯示超時:
[root@harbor2 ~]# docker push harbor.ikan.com/kubernetes/busybox:v0.3
The push refers to repository [harbor.ikan.com/kubernetes/busybox]
eac247cb7af5: Retrying in 10 seconds
解決:需要修改安裝包里面Nginx配置文件,刪掉scheme的那幾行,在反向代理的配置上如果有寫的話
報錯2: 在拉取鏡像的時候,會拋出倉庫不受信任的異常。
解決:需要在所有的docker客戶端的docker配置文件/etc/docker/daemon.json中添加如下配置:
{ "insecure-registries": ["https://harbor1.ikan.com"], }
六:harbor鏡像倉庫高可用
高可用方案有兩種:
1. 雙主復制
所謂的雙主復制其實就是復用主從同步實現兩個harbor節點之間的雙向同步,來保證數據的一致性,然后在兩台harbor前端頂一個負載均衡器將進來的請求分流到不同的實例中去,只要有一個實例中有了新的鏡像,就是自動的同步復制到另外的的實例中去,這樣實現了負載均衡,也避免了單點故障,在一定程度上實現了Harbor的高可用性:

這個方案有一個問題就是有可能兩個Harbor實例中的數據不一致。假設如果一個實例A掛掉了,這個時候有新的鏡像進來,那么新的鏡像就會在另外一個實例B中,后面即使恢復了掛掉的A實例,Harbor實例B也不會自動去同步鏡像,這樣只能手動的先關掉Harbor實例B的復制策略,然后再開啟復制策略,才能讓實例B數據同步,讓兩個實例的數據一致。
在實際生產使用中,主從復制有時候會出現報錯。
2. 多harbor實例共享后端存儲,
共享后端存儲算是一種比較標准的方案,就是多個Harbor實例共享同一個后端存儲,包括數據庫,redis和本地存儲數據;任何一個實例持久化到存儲的鏡像,都可被其他實例中讀取。通過前置LB進來的請求,可以分流到不同的實例中去處理,這樣就實現了負載均衡,也避免了單點故障:

這個方案在實際生產環境中部署需要考慮三個問題:
- 共享存儲的選取,Harbor的后端存儲目前支持AWS S3、Openstack Swift, Ceph等,在我們的實驗環境里,就直接使用nfs
- Session在不同的實例上共享,這個現在其實已經不是問題了,在最新的harbor中,默認session會存放在redis中,我們只需要將redis獨立出來即可。可以通過redis sentinel或者redis cluster等方式來保證redis的可用性。在我們的實驗環境里,仍然使用單台redis
- Harbor多實例數據庫問題,這個也只需要將harbor中的數據庫拆出來獨立部署即可。讓多實例共用一個外部數據庫,數據庫的高可用也可以通過數據庫的高可用方案保證。
目前,Harbor官方並未給出具體的高可用部署方案,用戶需要根據自己的情況來設計合適的高可用方案並完成部署。主從同步高可用方案,只是一種簡單的實現。
0.1 已經有了另一台鏡像倉庫harbor2
1. 創建用戶

2. 項目中添加用戶

3. 倉庫管理中添加目標
- 選擇系統管理中的倉庫管理,點擊“新建目標”,如下圖
- 輸入對應信息。
- 目標名和描述隨意,
- 目錄URL為另一台地址,如果為https協議,則證書需要安全。(制作免費的https證書.note)
- Access ID和Access Secret為有同步權限的賬號即可
- 點擊“測試鏈接”,顯示“測試鏈接成功”,則表示權限通過,點解“確認”添加即可

4. 添加復制規則
- 在系統管理的復制管理里,點擊“新建規則”,如下圖
- 添加規則信息
- 名稱和描述隨意
- 選擇復制模式:Push-based 從本地倉庫推送到遠程倉庫,Pull-based 拉去鏡像到本地倉庫
- 鏡像過濾規則,包括包含名稱,標簽等
- 選擇遠程鏡像倉庫和命名空間
- 選擇觸發模式,分為手動/定時/事件,鏡像是否強制覆蓋,是否啟動規則等

5. 測試harbor倉庫可用性
這時你推送鏡像到鏡像倉庫harbor1,則在鏡像倉庫harbor2上也能看到
[root@harbor2 ~]# docker tag busybox harbor.ikan.com/kubernetes/busybox:v0.4
[root@harbor2 ~]# docker push harbor.ikan.com/kubernetes/busybox:v0.4
The push refers to repository [harbor.ikan.com/kubernetes/busybox]
eac247cb7af5: Layer already exists
v0.3: digest: sha256:24fd20af232ca4ab5efbf1aeae7510252e2b60b15e9a78947467340607cd2ea2 size: 527
鏡像自動化刪除
默認情況下,Harbor將鏡像存儲在本地磁盤,隨着鏡像越來越多,可能會導致磁盤空間不夠。為了提供磁盤的利用率,需要把不用或者多余的鏡像刪除。 Harbor提供了刪除鏡像的功能,但需要手動去處理。
可以采用cron job定期去運行鏡像刪除腳本來實現鏡像自動化刪除。腳本通過調用Harbor的RESTful API,來獲取要刪除鏡像的名稱和tag。刪除鏡像的過程如下:
1) 獲取所有project並解析project_id字段,得到project的個數;
2) 獲取每個project的repo名稱;
3) 根據repo名稱獲取每個repo下的tag並統計個數;
4) 若tag數大於規定的個數,進行排序,刪除最早的tag(並不會刪除鏡像);
5) 刪除鏡像,命令如下:
docker-compose stop;
docker run -it --name gc --rm --volumes-from registry vmware/registry:2.6.1-photon garbage-collect /etc/registry/config.yml;
docker-compose start;
問題:registry https://192.168.70.120 is unhealthy: unhealthy

解決:證書自簽名,不被信任。