360私有云容器鏡像倉庫簡介
鏡像倉庫,顧名思義就是存儲鏡像的。Docker 倉庫的概念跟Git 類似,注冊服務(wù)器可以理解為 GitHub 這樣的托管服務(wù)。用戶制作好鏡像push到倉庫,這樣下次在另外一臺機器上使用這個鏡像時候,只需要從倉庫上 pull 下來就可以了。本文主要介紹360私有云HULK使用的鏡像倉庫Harbor。
一、什么是Harbor
Habor是由VMWare公司開源的容器鏡像倉庫,是一個用于存儲和分發(fā)Docker鏡像的企業(yè)級Registry服務(wù)器。
Harbor主要是提供了一些企業(yè)級的管理功能,而鏡像存儲用的還是docker registry,相當于docker registry的反向代理。
1. Harbor架構(gòu)
如上圖所示,Harbor由6個組件組成:
Proxy:nginx反向代理。上圖來自官網(wǎng),已經(jīng)滯后了。目前到harbor的所有請求都必須走nginx,包括上圖中Proxy–> Registory這條。
Registry:負責(zé)存儲Docker圖像和處理Docker push/pull命令。由于Harbor需要加強對映像的訪問控制,因此注冊中心將引導(dǎo)客戶端到令牌服務(wù),以便為每個pull或push請求獲得一個有效的令牌。
Core services:港口的核心功能,主要提供以下服務(wù):
- UI:提供了一個web管理頁面,當然還包括了一個前端頁面和后端API。
- Webhook:在Registory中配置,鏡像復(fù)制,日志更新都是同伙該功能實現(xiàn)。
- Token service:令牌服務(wù),如果從Docker客戶機發(fā)送的請求中沒有令牌,注冊中心將把請求重定向到令牌服務(wù)。
- Job services:鏡像復(fù)制。
- Log collector:日是收集。
2. HULK使用的Harbor功能
(1) 用戶管理
基于角色的訪問控制:用戶分為三種角色:項目管理員(MDRWS)、開發(fā)人員(RWS)和訪客(RS),當然還有一個造物主admin系統(tǒng)管理員。
注:M:管理、D:刪除、R:讀取、W:寫入、S:查詢。
(2) 項目管理
項目管理是系統(tǒng)最主要的一個功能模塊,項目是一組鏡像倉庫的邏輯集合,是權(quán)限管理和資源管理的單元劃分。一個項目下面有多個鏡像倉庫,并且關(guān)聯(lián)多個不同角色的成員,鏡像復(fù)制也是基于項目的,通過添加復(fù)制規(guī)則,
可以將項目下面的鏡像從一個harbor遷移到另一個harbor,并且可以通過日志查看復(fù)制過程,并有retry機制。
(3) 權(quán)限管理
配置管理主要是配置harbor的認證模式,企業(yè)內(nèi)部使用,通常都是對接到公司LDAP上面,我們目前用的數(shù)據(jù)庫認證;還可以設(shè)置token的有效時間。
(4) 鏡像復(fù)制
HULK多機房就是通過鏡像復(fù)制功能實現(xiàn)的,可在不同的數(shù)據(jù)中心、不同的運行環(huán)境之間同步鏡像。
目前HULK上,用戶申請容器服務(wù)后,我們會為其創(chuàng)建個Harbor的project(下圖中的xxl-api即為Harbor中的項目名),
并為其分配兩個用戶名,一個RWS、一個RS,xxl-api是只讀用戶,還有一個對用戶隱藏的xxl-api-p開發(fā)人員用戶。以達到用戶只能操作自己私有倉庫的目的。
3. Harbor的高可用負載均衡
通過三個harbor完成高可用部署,前面通過負載均衡器(HULK上的LVS)對外提供服務(wù)。共享數(shù)據(jù)庫與緩存。
多機房
多機房可以應(yīng)對單機房s3異常,機房孤島等及特殊情況,同時可以減輕主機房負擔。
目前我們有bjyt(主)和shyc2(從)兩套harbor,push都到主,k8s拉鏡像可以選擇拉主或者從。
每個機房的harbor組件完全獨立,包括s3和數(shù)據(jù)庫。目的就是為了即使出現(xiàn)孤島也不會影響服務(wù)。
二、什么是鏡像
鏡像就是,聯(lián)合文件系統(tǒng)(UnionFS),目前用的驅(qū)動是overlay2。
鏡像的基礎(chǔ)層是rootfs:任何程序運行時都會有依賴,無論是開發(fā)語言層的依賴庫,還是各種系統(tǒng)lib、操作系統(tǒng)等,不同的系統(tǒng)上這些庫可能是不一樣的,或者有缺失的。為了讓容器運行時一致,docker將依賴的操作系統(tǒng)、各種lib依賴整合打包在一起(即鏡像),然后容器啟動時,作為它的根目錄(根文件系統(tǒng)rootfs),使得容器進程的各種依賴調(diào)用都在這個根目錄里,這樣就做到了環(huán)境的一致性。
Layer:Dockerfile中的基礎(chǔ)是rootfs,而之后的每一個操作都是一層,如:RUN、ADD等命令。所有為了鏡像體積小寫,可以把多個RUN命令整合成一行,這樣多層就變成一層了。
鏡像只有最上一層是讀寫的,其余都是只讀的(目錄的without屬性)。所謂without屬性union文件系統(tǒng)中,如果刪除的文件在只讀層,最上層看到文件已經(jīng)刪除,但是只讀層文件依然存在,在最上層做改文件without隱藏文件實現(xiàn)。rm mnt/haha.log操作和touch a/.wh.haha.log效果相同。
1. 容器的鏡像掛載
docker支持多種graphDriver,包括vfs、devicemapper、overlay、overlay2、aufs,docker鏡像存儲驅(qū)動目前用的是overlay2。
docker默認的存儲目錄是/var/lib/docker
- [root@p22295v zhangzhifei]# ls -lrt /var/lib/docker/
- total 156
- drwx--x--x 3 root root 4096 Dec 6 2018 containerd
- drwx------ 4 root root 4096 Dec 6 2018 plugins
- drwx------ 3 root root 4096 Dec 6 2018 image
- drwx------ 2 root root 4096 Dec 6 2018 trust
- drwxr-x--- 3 root root 4096 Dec 6 2018 network
- drwx------ 2 root root 4096 Dec 6 2018 swarm
- drwx------ 2 root root 4096 Dec 6 2018 builder
- drwx------ 89 root root 12288 Jul 17 11:07 volumes
- drwx------ 2 root root 4096 Jul 17 14:30 runtimes
- drwx------ 2 root root 4096 Jul 23 12:51 tmp
- drwx------ 758 root root 94208 Jul 29 19:12 overlay2
- drwx------ 80 root root 12288 Jul 29 19:12 containers
我們運行個容器演示下:
- [root@p22295v zhangzhifei]# docker run -it -d kraken-agent:dev
- 83555ad8c034682ad885fc9e320bfb1f8b75498b61a1a8684d738c411caa930b
啟動一個容器,在/var/lib/docker/overlay2目錄下生成一個容器視圖層,目錄包括diff,link,lower,merged,work。
diff記錄每一層自己內(nèi)容的數(shù)據(jù),link記錄該層鏈接目錄(實際是l目錄下到層的鏈接),比如在容器中創(chuàng)建目錄或在diff新增該目錄。
根據(jù)存儲數(shù)據(jù)及功能可以把這些層分為3部分:
- 只讀層
- init層(夾在只讀層和讀寫層之間,專門用來存放/etc/hosts、/etc/resolv.conf等信息。需要這樣一層的原因是,這些文件本來屬于只讀的系統(tǒng)鏡像層的一部分,但是用戶往往需要在啟動容器時寫入一些指定的值比如hostname,所以就需要在可讀寫層對它們進行修改。可是,這些修改往往只對當前的容器有效,我們并不希望執(zhí)行docker commit時,把這些信息連同可讀寫層一起提交掉。所以,Docker做法是,在修改了這些文件之后,以一個單獨的層掛載了出來。而用戶執(zhí)行docker commit只會提交可讀寫層,所以是不包含這些內(nèi)容的。)
- 讀寫層(在沒有寫入文件之前,這個目錄是空的。而一旦在容器里做了寫操作,你修改產(chǎn)生的內(nèi)容就會以增量的方式出現(xiàn)在這個層中)
查看容器掛載目錄
- [root@p22295v zhangzhifei]# cat /var/lib/docker/image/overlay2/layerdb/mounts/83555ad8c034682ad885fc9e320bfb1f8b75498b61a1a8684d738c411caa930b/mount-id
- 3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40[root@p22295v zhangzhifei]#
- #讀寫層
- [root@p22295v zhangzhifei]# ls /var/lib/docker/overlay2/3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40/diff/
- [root@p22295v zhangzhifei]#
- #只讀層
- [root@p22295v zhangzhifei]# ls /var/lib/docker/overlay2/65e5cdd72f2995da4c73f2d9b90e8d974b9d2f18829a2479296aaec24e67d185/diff/
- bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
- #只讀層(Dockerfile時ADD的二進制程序)
- [root@p22295v zhangzhifei]# ls -lrt /var/lib/docker/overlay2/852fa5138c3da5070b59e6402348a5a281378b28ee08fede9c635e4101f91092/diff/usr/bin/
- total 28836
- -rwxr-xr-x 1 root root 29526888 Jul 10 16:23 kraken-origin
最終,這寫層都被聯(lián)合掛載到/var/lib/docker/overlay2/3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40/merged目錄下,表現(xiàn)為一個完整的操作系統(tǒng)和運行時環(huán)境供容器使用。
- [root@p22295v zhangzhifei]# mount | grep 3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40
- overlay on /var/lib/docker/overlay2/3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/Z7QMVXSKSNAKCUEJ6ZMU5YTFWG:/var/lib/docker/overlay2/l/2OYCXTK7M4QN3DT7IYJK6J7VYT:/var/lib/docker/overlay2/l/UZTDJDVUOBHU2VERRLXF5KMIQO:/var/lib/docker/overlay2/l/NAXXPRFMO4ATUIG6SFPU4LBUUV:/var/lib/docker/overlay2/l/AM4PHUFWOD4UHYIVO5Q6GVZ5L7:/var/lib/docker/overlay2/l/7XLJNT7Q3UQIKHDNV4QG4EX2C3:/var/lib/docker/overlay2/l/3RAVSDXXRS3BASAKZFPT2ESY2K:/var/lib/docker/overlay2/l/FFNAQF5ADFSTEBNZZ4O2R3CP4N:/var/lib/docker/overlay2/l/X6BOWOZKYRN3DZFY6QLLP7OFDP:/var/lib/docker/overlay2/l/P3EO3WHIM2XPDNPIFUP42EGMQI:/var/lib/docker/overlay2/l/EOSBLWDBASO7GKSDILC4XVGO45:/var/lib/docker/overlay2/l/7K7266OIDWAVXLAN6AA3SZXZQZ,upperdir=/var/lib/docker/overlay2/3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40/diff,workdir=/var/lib/docker/overlay2/3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40/work)
- [root@p22295v zhangzhifei]# ls /var/lib/docker/overlay2/3695f349587aaa2cdc82fcde1a380c7b567ef870a47e4c28b8b279e4edc9eb40/merged
- bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
三、鏡像在鏡像倉庫中的存儲
1. 鏡像存儲的目錄結(jié)構(gòu)
以本地存儲為例,默認在/data/registry/docker/registry/v2,鏡像存儲的任何一層都不會重復(fù)。
- ├── blobs
- │ └── sha256
- │ │ └── dfa94d685d1c2179324f02bf2a119f6d8ee0d380cef5506566012f7c4936a04a
- │ │ └── data
- │ ├── e6
- │ │ └── e6ae4ac760c8457aca9be07de8ca66b3a358a19b950389a0d158ae885178f6cf
- │ │ └── data
- │ ├── e7
- │ │ └── e71de1ca8f2b18993c258e2bf50edea8c23ea4a78a821bcfef181de50b3c32f4
- │ │ └── data
- └── repositories
- ├── registry-share-private
- │ ├── push-mount
- │ │ ├── _layers
- │ │ │ └── sha256
- │ │ │ ├── 1b1ad4542c99b8881265610cf5dc09e37d38445529a7584edb2a607fd783216f
- │ │ │ │ └── link
- │ │ ├── _manifests
- │ │ │ ├── revisions
- │ │ │ │ └── sha256
- │ │ │ │ └── 9e4cf4691735c02e59dd49ee561a3f5e56bccf78d57eaa94581e29f69a5162bd
- │ │ │ │ └── link
- │ │ │ └── tags
- │ │ │ └── v1
- │ │ │ ├── current
- │ │ │ │ └── link
- │ │ │ └── index
- │ │ │ └── sha256
- │ │ │ └── 9e4cf4691735c02e59dd49ee561a3f5e56bccf78d57eaa94581e29f69a5162bd
- │ │ │ └── link
- │ │ └── _uploads
- │ ├── push-new
- │ │ ├── _layers
- │ │ │ └── sha256
- │ │ │ ├── 1b1ad4542c99b8881265610cf5dc09e37d38445529a7584edb2a607fd783216f
- │ │ │ │ └── link
- │ │ ├── _manifests
- │ │ │ ├── revisions
- │ │ │ │ └── sha256
- │ │ │ │ └── 9e4cf4691735c02e59dd49ee561a3f5e56bccf78d57eaa94581e29f69a5162bd
- │ │ │ │ └── link
- │ │ │ └── tags
- │ │ │ └── v1
- │ │ │ ├── current
- │ │ │ │ └── link
- │ │ │ └── index
- │ │ │ └── sha256
- │ │ │ └── 9e4cf4691735c02e59dd49ee561a3f5e56bccf78d57eaa94581e29f69a5162bd
- │ │ │ └── link
(1) blobs
目錄是存放每層數(shù)據(jù)(gzip)以及一個鏡像的manifests信息(json)的具體文件
(2) repositories
存儲鏡像的組織信息,類似于元數(shù)據(jù)
- 倉庫名:registry-share-private/push-mount就是一個倉庫名,registry-share-private相當于project的概念,push-mount容器名
- _layers:目錄類似于blobs目錄,但是它不存儲真是數(shù)據(jù)僅僅以link文件保存每個layer的sha256編碼。保存該repository長傳過得所有l(wèi)ayer的sha256編碼信息
- _manifests:該repository的上傳的所有版本(tag)的manifest信息。其目錄下有revisions目錄和tags目錄
- tags:每個tag一組記錄(v1), 每個tag下面有current目錄和index目錄, current目錄下的link文件保存了該tag目前的manifest文件的sha256編碼,而index目錄則列出了該tag歷史上傳的所有版本的sha256編碼信息
- _revisions:目錄里存放了該repository歷史上上傳版本的所有sha256編碼信息
- _uploads:是一個臨時目錄,一旦鏡像上傳完成,該目錄下的文件就被刪除
2. 上傳鏡像流程認證
- 到認證服務(wù)獲取token
- 查詢倉庫中是否有欲上傳的層
- 開始上傳blob
- 大塊用則分塊傳,小塊用put。分塊上傳后也要以一個put請求表示完成上傳。
- 上傳mainfest
當所有的blob上傳完成后需上傳文件清單。
注意:
- 如果上傳鏡像的某一層在倉庫中已經(jīng)存在,并且有讀的權(quán)限。docker 會先獲取token,之后攜帶這個toke進行mount,減少重復(fù)層的上傳,加快push速度
- mount信息處理其實就是在生產(chǎn)對應(yīng)layer的信息放在_layers目錄下。
- 對于已經(jīng)存在的層,但是沒有權(quán)限的,客戶端需要重新上傳,但是最終存儲還是一份。但是文件系統(tǒng)做move時,先判斷目的路徑是否存在,存在則不進行覆蓋。
- 對于已經(jīng)存在的鏡像HEAD請求時世界返回200,表示不需要上傳。
【本文是51CTO專欄機構(gòu)360技術(shù)的原創(chuàng)文章,微信公眾號“360技術(shù)( id: qihoo_tech)”】