容器學(xué)習(xí):容器鏡像命名規(guī)范及版本管理規(guī)范
?在我們使用容器云平臺的過程中,公司業(yè)務(wù)的規(guī)模會不斷發(fā)展、各類軟件的鏡像版本會不停迭代更新,各種版本的鏡像變得越來越多,在管理這些鏡像的過程中,由于容器云平臺的不同開發(fā)和運(yùn)維人員的能力、工作習(xí)慣存在較大的差異,出現(xiàn)各類奇葩的鏡像命名,造成問題追溯時(shí)需要花費(fèi)大量的時(shí)間在問題的定位和溝通層面,降低了運(yùn)維的效率。
如何統(tǒng)一規(guī)范管理容器鏡像的命名和版本成為了我們?nèi)粘9ぷ髦斜仨氁鉀Q的一個(gè)問題。規(guī)范和標(biāo)準(zhǔn)是工作中重要的指引文件,通過規(guī)范標(biāo)準(zhǔn)能統(tǒng)一線上容器鏡像的名字,防止出現(xiàn)隨心所欲的命名,加快容器鏡像的定位。本文旨在于介紹容器鏡像的命名規(guī)范和版本管理,實(shí)現(xiàn)“三個(gè)方便”原則。方便使用:統(tǒng)一規(guī)范的命名規(guī)則,使鏡像名稱能夠清晰的描述該鏡像的環(huán)境信息和用途,方便維護(hù):能夠有效地對所有鏡像進(jìn)行展示和查詢,定期對無用鏡像進(jìn)行清理,釋放存儲空間;方便管理:只有鏡像名稱滿足一定規(guī)范,才能精確地對所有鏡像進(jìn)行配額管理和權(quán)限控制,最終達(dá)到為企業(yè)降本增效的目的。
1.鏡像倉庫介紹
鏡像倉庫(Repository)是集中存儲容器鏡像(符合OCI規(guī)范)的地方,這里有個(gè)概念要稍微做一下區(qū)分那就是鏡像倉庫與鏡像倉庫服務(wù)器(Registry)是兩回事,一個(gè)鏡像倉庫服務(wù)器可以創(chuàng)建多個(gè)鏡像倉庫的空間,例如,quay.io就是一個(gè)開源的公共鏡像倉庫,而Quay企業(yè)版則是一個(gè)開源的企業(yè)級的鏡像倉庫服務(wù)器,不過其實(shí)有時(shí)候我們不太需要太過區(qū)分這兩個(gè)概念。
1.1 公共鏡像倉庫
公共鏡像倉庫主要有quay.io和Docker Hub,使用過docker或podman的我們已經(jīng)明白了如何從公共鏡像倉庫獲取鏡像,除了獲取鏡像外,我們也可以將自己構(gòu)建的鏡像存放到公共鏡像倉庫,這樣別人也可以使用我們構(gòu)建的鏡像了。不過要將鏡像上傳到公共鏡像倉庫,必須先在公共鏡像倉庫的網(wǎng)站上注冊一個(gè)賬號,注冊好了之后,可以在本地使用login命令登錄到公共鏡像倉庫,在輸入賬號密碼登錄到公共鏡像倉庫之后,便可以使用push命令把鏡像推送到公共鏡像倉庫了。
1.2 私有鏡像倉庫
在企業(yè)級應(yīng)用環(huán)境中,我們不可能將企業(yè)的內(nèi)部容器推送到公共鏡像倉庫中,如果直接使用導(dǎo)出鏡像的方式進(jìn)行共享又比較麻煩,這時(shí)候我們可以自己搭建屬于自己的私有鏡像倉庫服務(wù),用于存儲和發(fā)布企業(yè)使用的鏡像。
Docker官方提供了registry這個(gè)鏡像,可以用于搭建私有鏡像倉庫服務(wù),我們把鏡像拉到本地之后,用該鏡像的容器便可以搭建一個(gè)簡易的鏡像倉庫服務(wù)。
Quay企業(yè)版是一個(gè)用于存儲和分發(fā)Docker鏡像的企業(yè)級Registry服務(wù)器,通過添加一些企業(yè)必需的功能特性,例如安全、標(biāo)識和管理等,擴(kuò)展了簡易的Docker Distribution。作為一個(gè)企業(yè)級私有Registry服務(wù)器,Quay企業(yè)版提供了更好的性能和安全。提升用戶使用Registry構(gòu)建和運(yùn)行環(huán)境傳輸鏡像的效率。Quay企業(yè)版支持安裝在多個(gè)Registry節(jié)點(diǎn)的鏡像資源復(fù)制,鏡像全部保存在私有Registry中,確保數(shù)據(jù)和知識產(chǎn)權(quán)在公司內(nèi)部網(wǎng)絡(luò)中管控。另外,Quay企業(yè)版也提供了高級的安全特性,諸如用戶管理,訪問控制和活動審計(jì)等。
1.3 云鏡像倉庫
目前主要的云廠商都提供了租戶的鏡像倉庫的服務(wù),如阿里云、百度云、騰訊云等,在這些云平臺上,我們可以創(chuàng)建自己租戶的鏡像倉庫,而且還可以使用到這些鏡像倉庫的加速服務(wù)用于加快我們Pull鏡像的速度,如果企業(yè)的應(yīng)用本身就在云上,那么使用云鏡像倉庫服務(wù)是一個(gè)很好的選擇。
2.鏡像倉庫的命名規(guī)范
2.1 基礎(chǔ)鏡像倉庫和業(yè)務(wù)鏡像倉庫的分離
首先我們?yōu)榛A(chǔ)鏡像和業(yè)務(wù)鏡像做一個(gè)定義?;A(chǔ)鏡像:不包含具體業(yè)務(wù)的鏡像。主要是為業(yè)務(wù)提供運(yùn)行環(huán)境的,或者是一些開源項(xiàng)目的官方鏡像。業(yè)務(wù)鏡像:基于基礎(chǔ)鏡像構(gòu)建出來的包含具體業(yè)務(wù)的鏡像,能夠在測試或生產(chǎn)環(huán)境中部署和運(yùn)行。
我們在進(jìn)行容器化部署實(shí)踐過程中,有些通用軟件的鏡像是會被多個(gè)項(xiàng)目的應(yīng)用經(jīng)常作為基礎(chǔ)鏡像使用,這些基礎(chǔ)軟件不需要我們進(jìn)行二次開發(fā),在生產(chǎn)環(huán)境、測試環(huán)境、試運(yùn)行環(huán)境等使用的均為同一鏡像,直接使用穩(wěn)定版本的鏡像跑起來更改配置就可以提供對外服務(wù)了,例如常見的RHEL、OpenJDK、Nginx、Redis、MySQL等,這些常用軟件我們可以放在基礎(chǔ)軟件鏡像庫中。
針對我們自身開發(fā)或者合作開發(fā)的軟件,一般以項(xiàng)目為單位建立倉庫,一個(gè)項(xiàng)目存在一到N個(gè)不同的模塊的鏡像,為了方便我們查找和核實(shí)鏡像的情況,針對每個(gè)項(xiàng)目我們構(gòu)建相對獨(dú)立的鏡像倉庫空間。
2.2 規(guī)范鏡像源管理
對于不同倉庫的鏡像文件,不能由開發(fā)或者測試員隨意進(jìn)行上傳,針對不同倉庫的鏡像維護(hù)需要明確責(zé)任方,例如:由配置管理員負(fù)責(zé)提供和維護(hù)基礎(chǔ)鏡像,需要確?;A(chǔ)鏡像的版本的安全性、可靠性和穩(wěn)定性,一般開發(fā)和運(yùn)維人員不能隨意上傳鏡像到此倉庫中;CI流水線:項(xiàng)目持續(xù)集成生成的鏡像,自動上傳到我們的項(xiàng)目倉庫中;個(gè)人用戶:非配置管理員手動用push命令上傳的測試鏡像到項(xiàng)目倉庫中。
3.鏡像命名規(guī)則及其格式
3.1 鏡像名稱格式
我們?nèi)粘J褂玫溺R像名稱的通用格式為:DOCKER_REGISTRY/repo/name:tag,各個(gè)字段具體含義如下:
DOCKER_REGISTRY:企業(yè)統(tǒng)一的Docker Registry地址;
repo:鏡像倉庫,用來管理某一類鏡像;
name:某個(gè)鏡像的具體名稱,一般的命名規(guī)則為:系統(tǒng)名稱+系統(tǒng)版本+服務(wù)名+服務(wù)版本(如果公司約定了主要使用的系統(tǒng)名稱和版本,則可以省略系統(tǒng)名稱+系統(tǒng)版本部分,直接使用服務(wù)名作為鏡像的名稱)。例如:centos7.6-nginx-1.47。
tag:某個(gè)鏡像具體的標(biāo)簽。例如:2.0。
需要注意的是:鏡像的名稱需要限制為[a-z0-9],其中可以出現(xiàn)的符號為[-._],不能出現(xiàn)中文以及中文符號,包括鏡像名稱中的: 也必須是英文的冒號,不然創(chuàng)建容器的時(shí)候會失敗。
3.2 基礎(chǔ)鏡像命名規(guī)則
上文我們說到,我們采用一個(gè)獨(dú)立的倉庫來管理企業(yè)的基礎(chǔ)鏡像,例如使用public倉庫來管理所有的基礎(chǔ)鏡像,下面我們來約定基礎(chǔ)鏡像的命名規(guī)則:DOCKER_REGISTRY/repo/name:tag;
repo:統(tǒng)一用public倉庫來進(jìn)行管理;
name:描述該image中所提供的軟件,各軟件間通過“-”連接;
tag:依次順序描述該image中所提供的軟件的版本,各版本間通過“-”連接。
注意點(diǎn):
所有Base image除了盡量通過name和tag描述該image中所有的軟件及其版本信息,還需要通過添加description的label,更加詳細(xì)地描述image內(nèi)容。對于非軟件版本的更新(例如:更新安全漏洞),Base image的tag不會更新。為了追蹤Base image的版本信息,需要在image中加入構(gòu)建該image的Dockerfile的commit id。
例如:
3.3 業(yè)務(wù)鏡像命名規(guī)則
業(yè)務(wù)鏡像的命名規(guī)則以項(xiàng)目為倉庫進(jìn)行隔離,例如在一個(gè)支付項(xiàng)目中,我們使用payment鏡像倉庫,另一個(gè)風(fēng)控項(xiàng)目使用risk-control鏡像倉庫,下面是我們約定的鏡像命名規(guī)范:
repo:用項(xiàng)目名作為倉庫,來管理該項(xiàng)目下的所有鏡像。
name:描述該image中所包含的業(yè)務(wù)。
tag:commit id(前7位)和timestamp(12位,yymmddHHMMSS)組合成唯一標(biāo)識,中間通過“-”連接。
例如:
4.鏡像的版本管理
版本控制規(guī)范用于確定軟件配置項(xiàng)的命名與版本號管理的規(guī)則,以確保清楚地、唯一地標(biāo)識軟件的各個(gè)組成部分及其狀態(tài),并建立這些部分之間的一致性關(guān)系。
鏡像的版本號我們可以通過直接平移項(xiàng)目的版本號到在鏡像上。用來標(biāo)識開發(fā)、測試、交付階段的不同狀態(tài)的產(chǎn)品,版本號格式一般為:
<主版本號>.<次版本號>.<小版本號>-[Build號]
主版本號:立項(xiàng)時(shí)設(shè)置,在整個(gè)項(xiàng)目開發(fā)過程中不改變
次版本號:立項(xiàng)時(shí)設(shè)置,在整個(gè)項(xiàng)目開發(fā)過程中不改變
小版本號:立項(xiàng)時(shí)設(shè)置,在整個(gè)項(xiàng)目開發(fā)過程中不改變
Release號:又叫Build號,內(nèi)部測試開始之前設(shè)置,初始值為0,此后每產(chǎn)生一次小的修改,Release號+1。版本號的一般形式如:1.0.7-101,2.0.0-900
4.1 主版本號設(shè)置規(guī)則
設(shè)置時(shí)間:產(chǎn)品立項(xiàng)時(shí)設(shè)置
設(shè)置規(guī)則:
新產(chǎn)品立項(xiàng),主版本號為1
產(chǎn)品構(gòu)架發(fā)生改變,主版本號+1
產(chǎn)品主要組件(比如訂單處理框架)進(jìn)行重大修改,主版本號+1
產(chǎn)品對外接口協(xié)議發(fā)生更改,主版本號+1
4.2 次版本號設(shè)置規(guī)則
設(shè)置時(shí)間:產(chǎn)品立項(xiàng)時(shí)設(shè)置
設(shè)置規(guī)則:
新產(chǎn)品立項(xiàng),次版本號為0
為處理產(chǎn)品Bug或改進(jìn)現(xiàn)有功能/性能,對現(xiàn)有功能模塊做大的修改,但不增加新的功能模塊,副版本號+1
為增加產(chǎn)品功能,在原版本產(chǎn)品上增加新的功能模塊,而產(chǎn)品的主體構(gòu)件未做重大修改,并且產(chǎn)品的主體構(gòu)件之間的接口協(xié)議也未做修改,副版本號+1
為適應(yīng)不同用戶需求,對產(chǎn)品進(jìn)行更改,而產(chǎn)品的主體構(gòu)件未做重大修改,并且產(chǎn)品的主體構(gòu)件之間的接口協(xié)議也未做修改,副版本號+1
當(dāng)主版本號變更時(shí),副版本號同時(shí)置0
4.3 小版本號設(shè)置規(guī)則
新產(chǎn)品立項(xiàng),小版本號為0
修復(fù)Bug或改進(jìn)現(xiàn)有功能,但不對現(xiàn)有功能模塊做大的修改,不增加新的功能模塊,小版本號+1
當(dāng)次版本號變更時(shí),小版本號同時(shí)置0
4.4 Build號設(shè)置規(guī)則
設(shè)置時(shí)間:產(chǎn)品開發(fā)結(jié)束,內(nèi)部測試開始之前
設(shè)置規(guī)則:
Release號初始值為0
測試過程中,每進(jìn)行一次修改,Release號+1
5.鏡像倉庫的權(quán)限管理
5.1 基礎(chǔ)鏡像倉庫
鏡像倉庫劃分基礎(chǔ)鏡像和項(xiàng)目鏡像倉庫以后,我們下一步需要做的是規(guī)范鏡像倉庫的權(quán)限管理,對于基礎(chǔ)鏡像倉庫而言,應(yīng)該要對所有人可見,而且他們都能pull,但是只有配置管理員才有push和delete的權(quán)限。
下表中做了基礎(chǔ)的權(quán)限角色分配:
5.2 業(yè)務(wù)鏡像倉庫
項(xiàng)目鏡像倉庫中的內(nèi)容應(yīng)該與項(xiàng)目相關(guān)的人員才可以看見和pull該項(xiàng)目的所有鏡像,與項(xiàng)目無關(guān)人員無權(quán)限看見和pull,達(dá)到保護(hù)項(xiàng)目的私密性的目的。
下表中做了基礎(chǔ)的權(quán)限角色分配:
6.鏡像倉庫的容量管理
Docker Registry中沒有提供命令來完成刪除鏡像的功能,日積月累,將會產(chǎn)生許多無用的鏡像,占用大量存儲空間。若要?jiǎng)h除鏡像并回收空間,需要調(diào)用 Restful API來完成。我們在管理自己的鏡像倉庫時(shí),必須要明確約定每個(gè)image最多保留可配置的tag數(shù)量。對于N個(gè)的話,按時(shí)間排序,優(yōu)先將老的tag刪除,達(dá)到將倉庫容量維持在一個(gè)相對穩(wěn)定的狀態(tài)。?