一、Harbor簡介
Harbor是一個用于存儲和分發(fā)Docker鏡像的企業(yè)級Registry服務器,可以用來構(gòu)建企業(yè)內(nèi)部的Docker鏡像倉庫。它在Docker的開源項目 Distribution的基礎上,添加了一些企業(yè)需要的功能特性,如鏡像同步復制、漏洞掃描和權(quán)限管理等。Harbor是由VMware公司開源的企業(yè)級的Docker Registry管理項目,它包括權(quán)限管理(RBAC)、LDAP、日志審核、管理界面、自我注冊、鏡像復制和中文支持等功能。
二、Harbor組件
Harbor在架構(gòu)上主要由以下組件構(gòu)成:
Proxy:Harbor的registry, UI, token等服務,通過一個前置的反向代理統(tǒng)一接收瀏覽器、Docker客戶端的請求,并將請求轉(zhuǎn)發(fā)給后端不同的服務。
Registry: 負責儲存Docker鏡像,并處理dockerpush/pull 命令。由于我們要對用戶進行訪問控制,即不同用戶對Docker image有不同的讀寫權(quán)限,Registry會指向一個token服務,強制用戶的每次docker pull/push請求都要攜帶一個合法的token,Registry會通過公鑰對token 進行解密驗證。
Core services: 這是Harbor的核心功能,主要提供以下服務:
UI:提供圖形化界面,幫助用戶管理registry上的鏡像(image), 并對用戶進行授權(quán)
webhook:為了及時獲取registry 上image狀態(tài)變化的情況, 在Registry上配置webhook,把狀態(tài)變化傳遞給UI模塊。
token服務:負責根據(jù)用戶權(quán)限給每個docker push/pull命令簽發(fā)token.Docker 客戶端向Regi?stry服務發(fā)起的請求,如果不包含token,會被重定向到這里,獲得token后再重新向Registry進行請求。
Database:為coreservices提供數(shù)據(jù)庫服務,負責儲存用戶權(quán)限、審計日志、Docker image分組信息等數(shù)據(jù)。
Job Services:提供鏡像遠程復制功能,可以把本地鏡像同步到其他Harbor實例中。
Log collector:為了幫助監(jiān)控Harbor運行,負責收集其他組件的log,供日后進行分析。
這幾個容器通過 Docker link 的形式連接在一起,這樣,在容器之間可以通過容器名字互相訪問。對終端用戶而言,只需要暴露 proxy (即 Nginx)的服務端口。
三、工作原理
用戶通過 docker login 命令向這Harbor 服務kube.com發(fā)起登錄請求:docker login kube.com當用戶輸入所需信息并點擊回車后,Docker 客戶端會向地址“kube.com/v2/” 發(fā)出 HTTP GET 請求。Harbor 的各個容器會通過以下步驟處理:
3.1 Docker login
首先,這個請求會由監(jiān)聽 80 端口的 proxy 容器接收到。根據(jù)預先設置的匹配規(guī)則,容器中的 Nginx會將請求轉(zhuǎn)發(fā)給后端的 registry 容器;
在 registry 容器一方,由于配置了基于 token 的認證,registry 會返回錯誤代碼 401,提示 Docker客戶端訪問 token 服務綁定的 URL。在 Harbor 中,這個 URL 指向 Core Services;
Docker 客戶端在接到這個錯誤代碼后,會向token服務的URL發(fā)出請求,并根據(jù)HTTP協(xié)議的BasicAuthentication 規(guī)范,將用戶名密碼組合并編碼,放在請求頭部(header);
類似地,這個請求通過 80 端口發(fā)到 proxy 容器后,Nginx 會根據(jù)規(guī)則把請求轉(zhuǎn)發(fā)給 ui 容器,ui 容器監(jiān)聽 token 服務網(wǎng)址的處理程序接收到請求后,會將請求頭解碼,得到用戶名、密碼;
在得到用戶名、密碼后,ui 容器中的代碼會查詢數(shù)據(jù)庫,將用戶名、密碼與 mysql 容器中的數(shù)據(jù)進行比對(注:ui 容器還支持 LDAP 的認證方式,在那種情況下 ui 會試圖和外部 LDAP 服務進行通信并校驗用戶名/密碼)。比對成功,ui 容器會返回表示成功的狀態(tài)碼, 并用密鑰生成 token,放在響應體中返回給 Docker 客戶端。
這個過程中組件間的交互過程如下圖所示:
至此,一次 docker login 成功地完成了,Docker 客戶端會把步驟(3)中編碼后的用戶名密碼保存在本地的隱藏文件中~/.docker/config.json。
3.2 Docker Push
用戶登錄成功后用 docker push 命令向 Harbor 推送一個 Docker 鏡像:docker push kube.com/library/hello-world
首先,docker 客戶端會重復 login 的過程,首先發(fā)送請求到 registry,之后得到 token 服務的地址;
之后,Docker 客戶端在訪問ui容器上的token服務時會提供額外信息,指明它要申請一個對library/hello-world 進行 push 操作的 token;
token 服務在經(jīng)過 Nginx 轉(zhuǎn)發(fā)得到這個請求后,會訪問數(shù)據(jù)庫核實當前用戶是否有權(quán)限對該 image進行 push。如果有權(quán)限,它會把 image 的信息以及 push 動作進行編碼,并用私鑰簽名,生成 token返回給 Docker 客戶端;
得到 token 之后 Docker 客戶端會把 token 放在請求頭部,向 registry 發(fā)出請求,試圖開始推送image。 Registry 收到請求后會用公鑰解碼 token 并進行核對,一切成功后,image 的傳輸就開始了。
下圖描述了這個過程中各組件的通信:
四、安裝部署
4.1、harbor-ui管理后臺
1、進入到GitHub下載官方harbor文件,下載鏈接地址為:https://github.com/vmware/harbor/releases,harbor分為在線和離線版本,我下載了1.10離線版本使用。
2、下載harbor-v1.10.1.tar.gz,解壓縮后進入到harbor目錄,根據(jù)實際情況修改配置文件harbor.yaml
hostname: kube.com
http:
? port: 80
https:
? port: 443
? certificate: /etc/harbor/ssl/kube.com.cert#這里后面生成
? private_key: /etc/harbor/ssl/kube.com.key
harbor_admin_password: password
database:
? password: password
? max_idle_conns: 50
? max_open_conns: 100
data_volume: /data
clair:
? updaters_interval: 12
jobservice:
? max_job_workers: 10
notification:
? webhook_job_max_retry: 10
chart:
? absolute_url: disabled
log:
? level: info
? local:
?? rotate_count: 50
?? rotate_size: 200M
?? location: /var/log/harbor
_version: 1.10.0
proxy:
? http_proxy:
? https_proxy:
? no_proxy:
? components:
?? - core
?? - jobservice
?? - clair
修改完成之后,使用官方自帶腳本更新參數(shù),在harbor目錄中執(zhí)行./prepare,這時候你會發(fā)現(xiàn)harbor是需要安裝docker和docker-compose才能使用的。3、docker安裝步驟略,docker-dompose安裝步驟如下:yum install python-pippip install docker-compose
4、接著在harbor目錄下執(zhí)行./install.sh命令即可,會自動導入鏡像并啟動對應的容器,待腳本跑完之后使用docke-compose ps即可查看,常用命令包含以下幾個:
docker-compose up-d###后臺啟動,如果容器不存在根據(jù)鏡像自動創(chuàng)建
docker-compose down-v ###停止容器并刪除容器
docker-composestart###啟動容器,不存在就無法啟動,不會自動創(chuàng)建
docker-composestop###停止容器
注:其實上面是停止docker-compose.yml中定義的所有容器,默認情況下docker-compose就是操作同目錄下的docker-compose.yml文件,如果使用其他yml文件,可以使用-f自己指定。最后使用鏈接https://domain.com(這是我自己的地址,你需要換成你自己的),輸入用戶名密碼即可登錄系統(tǒng)了。
4.2、push和pull鏡像
1、docker默認是從官方拉取鏡像的,并且從1.12版本之后,默認私有倉庫是使用https來進行連接,所以我們這里需要進行一些相應的修改:編輯docker啟動文件,在啟動命令后加入?yún)?shù):--insecure-registry kube.com,然后使用systemctl daemon-reload一下,重啟docker
2、使用docker命令對鏡像打標簽并且上傳至私有倉庫,docker打標簽命令:docker tag centos:latest kube/devil/centos:latest 上面的命令的意思是將centos這個鏡像的最新版latest打上標簽,其中kube.com是倉庫的地址,devil是倉庫里創(chuàng)建的項目(可以網(wǎng)上看登錄的界面截圖,我創(chuàng)建了一個devil項目,項目分為公開和私有,公開項目不需要登錄就可以進行拉取,私有的是需要登錄以后才能拉取的,上傳鏡像都需要登錄并且要有上傳的權(quán)限才行),centos:latest是我自己取的名字和版本,可以跟原來的保持一致,也可以自己另外取名,比如centos:mytest,打完標簽之后登錄倉庫并上傳鏡像:docker push kube/devil/centos:latest然后進入web管理界面即可查看到我們最新上傳的鏡像了
3、拉取鏡像很簡單,因為我設置的是公開項目,直接docker pull kube/devil/centos:latest即可
4.3、鏡像倉庫復制
一個倉庫的情況下如果鏡像倉庫掛了,那么所有的鏡像也就沒有了,所以最好是創(chuàng)建一個備份倉庫,harbor提供了鏡像倉庫復制功能,可以很好的自動實現(xiàn);創(chuàng)建2個harbor倉庫,其中一個為主,另外一個為輔,登陸主倉庫http://kube.com,點擊任意想要復制的倉庫項目,然后復制,點擊新建規(guī)則,名稱、描述根據(jù)自己的實際隨便填寫,勾選啟用,目標名為復制到輔倉庫的目標名,需要存在,如果不存在可以勾選創(chuàng)建目標,url為輔倉庫的harbor-ui的url,賬戶密碼也是輔倉庫賬戶密碼,點擊測試,測試成功代表沒有問題了,然后就會自動復制了,從日志處可以看到復制的過程。
4.4、https的啟用
要啟用https,那么ca證書必不可少,一般內(nèi)網(wǎng)環(huán)境都是直接使用自建ca,這里使用openssl自建ca,openssl的配置文件默認為/etc/pki/tls/openssl.cnf
進入到CA目錄下執(zhí)行
(umask077;opensslgenrsa-outprivate/cakey.pem2048)
# 括號中執(zhí)行,代表使用子shell執(zhí)行,不影響本機的umask值。
?
# 作為根 CA,可以生成一個自簽名的證書,來標明自己的身份,簽名方法如下
opensslreq-new-x509-keyprivate/cakey.pem-days3655-outcacert.pem
?
# 會提示輸入相關(guān)信息,不要隨便亂寫,其中Common Name一般填寫為域名或者ip地址,最好是域名。
?
# 開始生成服務證書
opensslgenrsa-outkube.com.key2048
?
# 生成簽名請求
opensslreq-new-keykube.com.key-outkube.com.csr
?
# 使用ca證書簽署請求
opensslca-inkube.com.csr-outkube.com.crt-days3650
?
# 提示信息選擇yes就可以了
?
# 最后cp證書到harbor.yml配置設置好的路徑下
cp-akube.com.* /etc/harbor/ssl
?
# 同時docker登錄、推送鏡像都需要使用證書,其中需要將ca證書放置到docker目錄中,docker默認從/etc/docker/certs.d/kube.com/ 目錄下讀取證書
cp-aca.crt /etc/docker/certs.d/kube.com/
?
# 然后重啟docker和harbor
systemctl daemon-reload && systemctlrestartdocker
docker-compose down-v&& docker-compose up-d
?
#? 注意執(zhí)行時的目錄下有docker-compose.yml文件
五、Kubelet使用私有倉庫項目
5.1 身份驗證
要想拉取私有鏡像必須在鏡像倉庫上進行身份驗證。
$ dockerlogin
當出現(xiàn)提示時,輸入 Docker 用戶名和密碼。
登錄過程會創(chuàng)建或更新保存有授權(quán)令牌的 config.json 文件。
查看 config.json 文件:
cat~/.docker/config.json
輸出結(jié)果包含類似于以下內(nèi)容的部分:
{
? "auths": {
? ? "harbor.vmic.xyz": {
? ? ? "auth":"YWRtaW46ZGV2aWwyMDIx"
? ? }
? },
? "HttpHeaders": {
? ? "User-Agent":"Docker-Client/19.03.14 (linux)"
? }
}
說明: 如果使用 Docker 憑證倉庫,則不會看到 auth 條目,看到的將是以倉庫名稱作為值的 credsStore 條目。
5.2 在集群中創(chuàng)建保存授權(quán)令牌的 Secret
Kubernetes 集群使用 docker-registry 類型的 Secret 來通過容器倉庫的身份驗證,進而提取私有映像。
創(chuàng)建 Secret,命名為 harborsecret:
$ kubectlcreate secret docker-registry harborsecret \
--docker-server=<你的鏡像倉庫服務器> \
--docker-username=<你的用戶名> \
--docker-password=<你的密碼> \
--docker-email=<你的郵箱地址>
在這里:
<your-registry-server> 是你的私有 Docker 倉庫全限定域名(FQDN)。 (參考 https://index.docker.io/v1/ 中關(guān)于 DockerHub 的部分)
<your-name> 是你的 Docker 用戶名。
<your-pword> 是你的 Docker 密碼。
<your-email> 是你的 Docker 郵箱。
這樣你就成功地將集群中的 Docker 憑據(jù)設置為名為 harborsecret 的 Secret。
5.3 檢查 Secret harborsecret
了解創(chuàng)建的 regcred Secret 的內(nèi)容,可以用 YAML 格式進行查看:
kubectlgetsecret harborsecret--output=yaml
輸出和下面類似:
apiVersion: v1
data:
? .dockerconfigjson: eyJodHRwczovL2luZGV4L ... J0QUl6RTIifX0=
kind: Secret
metadata:
? ...
? name: harborsecret
? ...
type: kubernetes.io/dockerconfigjson
.dockerconfigjson 字段的值是 Docker 憑據(jù)的 base64 表示。
要了解 dockerconfigjson 字段中的內(nèi)容,請將 Secret 數(shù)據(jù)轉(zhuǎn)換為可讀格式:
kubectlgetsecret harborsecret--output="jsonpath={.data.\.dockerconfigjson}"| base64--decode
輸出和下面類似:
{"auths":{"yourprivateregistry.com":{"username":"admin","password":"xxxxxxxxxxx","email":"weiping.tao@xxx.com","auth":"c3R...zE2"}}}
要了解 auth 字段中的內(nèi)容,請將 base64 編碼過的數(shù)據(jù)轉(zhuǎn)換為可讀格式:
echo"c3R...zE2"| base64--decode
輸出結(jié)果中,用戶名和密碼用 : 鏈接,類似下面這樣:
admin:xxxxxxxxxxx
注意,Secret 數(shù)據(jù)包含與本地 ~/.docker/config.json 文件類似的授權(quán)令牌。
這樣你就已經(jīng)成功地將 Docker 憑據(jù)設置為集群中的名為 harborsecret 的 Secret。
5.4 創(chuàng)建一個使用你的 Secret 的 Pod
下面是一個 Pod 配置文件,它需要訪問 harborsecret 中的 Docker 憑據(jù):
? - name: private-reg-container
$ wget-Omy-private-reg-pod.yaml https://k8s.io/examples/pods/private-reg-pod.yaml
在my-private-reg-pod.yaml 文件中,使用私有倉庫的鏡像路徑替換 <your-private-image>,例如:
創(chuàng)建使用了你的 Secret 的 Pod,并檢查它是否正常運行: