Harbor是一個用於存儲和分發Docker鏡像的企業級Registry服務器,能夠用來構建企業內部的Docker鏡像倉庫。html
harbor是基於docker registry進行了相應的企業級擴展,從而得到了更加普遍的應用,新特性包括:管理用戶界面,基於角色的訪問控制 ,AD/LDAP集成以及審計日誌等。mysql
以Docker爲表明的容器技術的出現,改變了傳統的交付方式。經過把業務及其依賴的環境打包進Docker鏡像,解決了開發環境和生產環境的差別問題,提高了業務交付的效率。如何高效地管理和分發Docker鏡像?是衆多企業須要考慮的問題。linux
能夠根據角色靈活的進行權限控制,如訪客只需給pull權限便可nginx
爲何須要鏡像同步git
1. 對系統穩定性要求高,須要多個倉庫保證高可用性 2. 更經常使用的場景是,在企業級軟件環境中,會在軟件開發的不一樣階段存在不一樣的鏡像倉庫
傳統鏡像同步方式是採用RSYNC服務來定義兩個倉庫之間的鏡像數據同步!!github
harbor同步機制web
1. 採用用Harbor本身的API來進行鏡像下載和傳輸,做到與底層存儲環境解耦。 2. 利用任務調度和監控機制進行復制任務的管理,保障複製任務的健壯性。在同步過程當中,若是源鏡像已刪除,Harbor會自動同步刪除遠端的鏡像。在鏡像同步複製的過程當中,Harbor會監控整個複製過程,遇到網絡等錯誤,會自動重試。 3. 提供複製策略機制保證項目級的複製需求。在Harbor中,能夠在項目中建立複製策略,來實現對鏡像的同步。與Docker Registry的不一樣之處在於,Harbor的複製是推(PUSH)的策略,由源端發起,而Docker Registry的複製是拉(PULL)的策略,由目標端發起。
參考文章redis
Docker鏡像是是分層的,而若是每次傳輸都使用全量文件(因此用FTP的方式並不適合),顯然不經濟。必須提供識別分層傳輸的機制,以層的UUID爲標識,肯定傳輸的對象。sql
1. Proxy:Harbor的registry,UI, token等服務,經過一個前置的反向代理統一接收瀏覽器、Docker客戶端的請求,並將請求轉發給後端不一樣的服務。 2. Registry: 負責儲存Docker鏡像,並處理docker push/pull 命令。因爲咱們要對用戶進行訪問控制,即不一樣用戶對Dockerimage有不一樣的讀寫權限,Registry會指向一個token服務,強制用戶的每次docker pull/push請求都要攜帶一個合法的token,Registry會經過公鑰對token 進行解密驗證。 3. Core services: 這是Harbor的核心功能,主要提供如下服務: UI:提供圖形化界面,幫助用戶管理registry上的鏡像(image), 並對用戶進行受權。 webhook:爲了及時獲取registry 上image狀態變化的狀況, 在Registry上配置webhook,把狀態變化傳遞給UI模塊。 token 服務:負責根據用戶權限給每一個docker push/pull命令簽發token. Docker 客戶端向Regiøstry服務發起的請求,若是不包含token,會被重定向到這裏,得到token後再從新向Registry進行請求。 4. Database:爲core services提供數據庫服務,負責儲存用戶權限、審計日誌、Dockerimage分組信息等數據。 5. Log collector:爲了幫助監控Harbor運行,負責收集其餘組件的log,供往後進行分析。
Harbor的每一個組件都是以Docker容器的形式構建的,所以很天然地,咱們使用Docker Compose來對它進行部署。docker
在源代碼中(https://github.com/vmware/harbor), 用於部署Harbor的Docker Compose 模板位於/Deployer/docker-compose.yml. 打開這個模板文件,會發現Harbor由5個容器組成: 1. proxy:由Nginx 服務器構成的反向代理。 2. registry:由Docker官方的開源registry 鏡像構成的容器實例。 3. ui: 即架構中的coreservices, 構成此容器的代碼是Harbor項目的主體。 4. mysql: 由官方MySql鏡像構成的數據庫容器。 5. log: 運行着rsyslogd的容器,經過log-driver的形式收集其餘容器的日誌。
這幾個容器經過Docker link的形式鏈接在一塊兒,這樣,在容器之間能夠經過容器名字互相訪問。對終端用戶而言,只須要暴露proxy (即Nginx)的服務端口。
因爲只說乾貨比較抽象,咱們用具體的命令做爲表現形式研究工做流程
假設咱們將Harbor部署在IP 爲192.168.1.10的機器上。用戶經過docker login命令向這個Harbor服務發起登陸請求:
docker login 192.168.1.10
當用戶輸入所需信息並點擊回車後,Docker 客戶端會向地址 「192.168.1.10/v2/」 發出HTTP GET請求。 Harbor的各個容器會經過如下步驟處理: 1.. 1.10機器上收到該請求,會有映射到宿主機80端口的容器接收到。根據匹配規則,容器中Nginx將請求轉發給registry容器; 2.. registry容器,因爲基於token認證,registry返回錯誤代碼401,提示docker客戶端訪問token去訪問token服務綁定的URL。在harbor中,這個URL指向的是CoreServices(核心服務組件); 3.. Docker 客戶端在接到這個錯誤代碼後,會向token服務的URL發出請求,並根據HTTP協議的BasicAuthentication規範,將用戶名密碼組合並編碼,放在請求頭部(header); 4.. 這個請求經過1.10:80發送到proxy容器後,Nginx根據規則吧請求轉發給UI容器,UI容器監聽token服務網址的處理程序,接收到請求後,將請求頭解碼,獲得了用戶名和密碼; 5.. 獲得用戶名、密碼後,UI容器中的代碼會查詢數據庫,將用戶名、密碼與mysql容器中的數據進行比對。比對成功的話,UI容器返回表示成功狀態嗎,用祕鑰生成token,放在響應體中返回給docker客戶端
docker push 192.168.1.10/library/hello-word
1.. docker客戶端重複login的過程,首先發送請求到registry,以後獲得token服務的地址; 2.. 以後,docker客戶端在訪問UI容器的token服務時會提供額外的信息,指明它要申請一個對library/hello-word進行push操做的token; 3.. token服務在通過Nginx轉發獲得了這個請求後,訪問數據庫合適當前用戶是否有權限對該image進行push操做。若是有權限,會把image信息以及push動做進行編碼,而且用私鑰簽名,生成token返回給docker客戶端 4.. 獲得token以後docker客戶端將token放在請求頭部,向registry發出請求,師徒開始推送image。registry收到請求後會用公鑰解碼token而且進行覈對,一切成功後,image傳輸就開始了
主機名 | IP地址 | 角色 |
---|---|---|
harbor1 | 192.168.111.3 | harbor倉庫 |
harbor2 | 192.168.111.4 | harbor備份倉庫 |
client | 192.168.111.5 | docker客戶端 |
本案例搭建harbor鏡像倉庫的高可用,可是因爲harbor並無相應官方方案推薦,本案例只是簡單採用主主高可用,而且基於keepalived的VIP實現
[root@localhost ~]# yum -y install yum-utils device-mapper-persistent-data lvm2 #安裝依賴 [root@localhost ~]# wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo #下載docker的repo [root@localhost ~]# yum -y install docker-ce [root@localhost ~]# mkdir /etc/docker [root@localhost ~]# vim /etc/docker/daemon.json { "registry-mirrors":["https://*******.mirror.aliyuncs.com"] } #阿里雲鏡像加速 #systemctl start docker
地址須要我的前往阿里雲得到,參考這篇文檔
在本案例中,一開始我初心是想要部署一個基於https的高可用harbor鏡像倉庫,可是後來生成證書時發現應該是必需要用域名才能夠,可是若是用域名的話,個人高可用VIP如何實現,故去除https的配置,用普通鏈接
從 github harbor 官網 release 頁面下載指定版本的安裝包。
一、在線安裝包 $ wget https://github.com/vmware/harbor/releases/download/v1.1.2/harbor-online-installer-v1.1.2.tgz $ tar xvf harbor-online-installer-v1.1.2.tgz 二、離線安裝包 $ wget https://github.com/vmware/harbor/releases/download/v1.1.2/harbor-offline-installer-v1.1.2.tgz $ tar xvf harbor-offline-installer-v1.1.2.tgz [root@harbor1 ~]# mv harbor /usr/local/ [root@harbor1 ~]# vim /usr/local/harbor/harbor.cfg hostname = 192.168.111.3 ui_url_protocol = http [root@harbor2 cert]# vim /usr/local/harbor/harbor.cfg hostname = 192.168.111.4 ui_url_protocol = http
curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` [root@harbor2 ~]# mv docker-compose /usr/local/bin/docker-compose [root@harbor2 ~]# chmod +x !$ chmod +x /usr/local/bin/docker-compose
[root@harbor2 ~]# sh /usr/local/harbor/install.sh [root@harbor1 ~]# sh /usr/local/harbor/install.sh #此過程比較慢
瀏覽器訪問測試http://192.168.111.3/
和http://192.168.111.4/
[root@localhost anchors]# docker pull cirros [root@localhost anchors]# docker login 192.168.111.3 Username: admin Password: [root@localhost anchors]# docker tag cirros:latest 192.168.111.3/joinbest1/cirros:test1 [root@localhost anchors]# docker push 192.168.111.3/joinbest1/cirros:test1 The push refers to repository [192.168.111.3/joinbest1/cirros] abbd6d6ac643: Pushed 75b99987219d: Pushed 0cc237193a30: Pushed test1: digest: sha256:96137d51e0e46006243fa2403723eb47f67818802d1175b5cde7eaa7f19446bd size: 943
兩端都是如此
這時,在對端harbor已經能夠看到剛纔建立的測試鏡像了。
因爲部署是主主,對端harbor倉庫也要進行以上操做
[root@localhost anchors]# docker tag cirros:latest 192.168.111.4/joinbest1/cirros:test2 [root@localhost anchors]# docker push 192.168.111.4/joinbest1/cirros:test2 The push refers to repository [192.168.111.4/joinbest1/cirros] abbd6d6ac643: Layer already exists 75b99987219d: Layer already exists 0cc237193a30: Layer already exists test2: digest: sha256:96137d51e0e46006243fa2403723eb47f67818802d1175b5cde7eaa7f19446bd size: 943 #上面的部分輸出含義是該層數據已經存在,可是不影響,由於在harbor中並非每一個鏡像都要全量上傳,而是分層存儲,更利於節省空間,以層的UUID爲標識
這時兩個倉庫上都有了該鏡像
也就是說,不管我再任何一個倉庫操做,都會同步給其它的任何倉庫
本案例太多因素出自筆者主觀,也許可靠,也許不可靠
兩臺harbor安裝keepalived #yum -y install keepalived [root@harbor1 harbor]# cat /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } script_user root #須要制定腳本運行用戶 notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL vrrp_skip_check_adv_addr vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_script check_harbor { script "/opt/harbor.sh" interval 2 weight 20 } #使用監控腳原本監控自身80端口,由於他是整個harbor的訪問入口 vrrp_instance VI_1 { state MASTER interface ens32 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.111.100/32 dev ens32 label ens32:2 } track_script { check_harbor } } --------------注意修改關鍵配置項------------ [root@harbor2 harbor]# cat /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } script_user root #須要制定腳本運行用戶 notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL1 vrrp_skip_check_adv_addr vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_script check_harbor { script "/opt/harbor.sh" interval 2 weight 20 } vrrp_instance VI_1 { state BACKUP interface ens32 virtual_router_id 51 priority 90 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.111.100/32 dev ens32 label ens32:2 } track_script { check_harbor } } ----------故障切換腳本----------- [root@harbor1 harbor]# vim /opt/harbor.sh #!/bin/bash sum=`netstat -lnpt | grep -wo 80 | wc -l` if [ $sum -eq 0 ]; then pkill -9 keepalived fi [root@harbor1 harbor]# chmod +x /opt/harbor.sh [root@localhost anchors]# vim /usr/lib/systemd/system/docker.service #主機3 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.111.3 --insecure-registry 192.168.111.4 --insecure-registry 192.168.111.100 #將VIP添加入可不安全訪問 [root@localhost anchors]# docker login 192.168.111.100 Authenticating with existing credentials... 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@localhost anchors]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE 192.168.111.4/joinbest1/cirros test2 bc94bceaae77 5 months ago 10.3MB cirros latest bc94bceaae77 5 months ago 10.3MB 192.168.111.3/joinbest1/cirros test1 bc94bceaae77 5 months ago 10.3MB #鏡像也正常 [root@harbor1 harbor]# docker-compose stop Stopping harbor-jobservice ... done Stopping nginx ... done Stopping harbor-ui ... done Stopping harbor-adminserver ... done Stopping redis ... done Stopping registry ... done Stopping harbor-db ... done Stopping harbor-log ... done #測試故障切換 [root@harbor2 harbor]# ip a | grep ens32 2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 192.168.111.4/24 brd 192.168.111.255 scope global noprefixroute ens32 inet 192.168.111.100/32 scope global ens32:2 #ip切過來了
[root@localhost anchors]# docker tag cirros:latest 192.168.111.100/joinbest1/cirros:test3 [root@localhost anchors]# docker push 192.168.111.100/joinbest1/cirros:test3 The push refers to repository [192.168.111.100/joinbest1/cirros] abbd6d6ac643: Layer already exists 75b99987219d: Layer already exists 0cc237193a30: Layer already exists test3: digest: sha256:96137d51e0e46006243fa2403723eb47f67818802d1175b5cde7eaa7f19446bd size: 943 #目前正常寫入 #經過web界面對111.3和111.4的joinbest1倉庫看看鏡像是否同步 #這裏先把剛纔測試關閉的harbor1倉庫給啓動 Starting log ... done Starting registry ... done Starting mysql ... done Starting adminserver ... done Starting ui ... done Starting redis ... done Starting jobservice ... done Starting proxy ... done #好,我這裏是所有能夠正常同步,就算是剛纔客戶端上傳時,harbor1是宕機的,可是從新啓動後,仍是會進行同步,不過應該是有觸發機制,我後來又建立了一個test4,剛開始harbor1是沒有test3的,我上傳test4以後出發了同步機制,這時harbor1的鏡像倉庫也是正常工做了,便將3.4一塊兒同步過去了
raise Exception("Error: the protocol must be https when Harbor is deployed with Notary") Exception: Error: the protocol must be https when Harbor is deployed with Notary #我輸入得命令是sh install.sh --with-notary --with-clair #其中使用--with-notary含義是啓用鏡像簽名;必須是https才能夠,把該選項去掉便可· [root@localhost anchors]# docker login 192.168.111.3 Username: admin Password: Error response from daemon: Get https://192.168.111.3/v2/: dial tcp 192.168.111.3:443: connect: connection refused #客戶端鏈接報錯,默認使用的是https我須要修改成可使用http來進行鏈接 [root@localhost anchors]# vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.111.3 --insecure-registry 192.168.111.4