云原生服務(wù)的開發(fā)迭代,Docker 鏡像作為最終的交付產(chǎn)物
,其生命周期中存在多個(gè)環(huán)節(jié)的流轉(zhuǎn):從鏡像構(gòu)建開始,到開發(fā)、測試環(huán)境的更新驗(yàn)證,再到交付制品生成,交付到生產(chǎn)環(huán)境。在這一整套的流轉(zhuǎn)過程中,鏡像作為流轉(zhuǎn)物,只要中間的一個(gè)流程出現(xiàn)失誤,很容易導(dǎo)致交付到生產(chǎn)環(huán)境的鏡像出現(xiàn)問題。雖然 Tag 可以讓鏡像有一定的辨識度
(資料圖片)
docker images --digestsREPOSITORY TAG DIGEST IMAGE ID CREATED SIZEkoderover.tencentcloudcr.com/koderover-public/aslan 1.15.0-20220922-amd64 sha256:8af42b5dd2a8539c3a1ead4f7bcbcc0028f1ec84090ace6f853793151fc0a7d0 35331bf1ae55 22 hours ago 188MBkoderover.tencentcloudcr.com/koderover-public/zadig-portal 1.13.0-amd64 sha256:15d8207a3ab3573ea8e5a3e32be9fa9340dfb4a5fe0842d3ef848a92655c6f58 1cb89026c2c5 47 hours ago 133MBkoderover.tencentcloudcr.com/koderover-public/zadig-portal 1.14.0-amd64 sha256:1bdb47274a6cb6da12b5fb2d3a073e820a8d5a8be9dac48f8f624adb85ddcefd 63e46ebf3e11 3 weeks ago 133MBtailscale/docker-extension 0.0.13 sha256:5f957b07602dd9b8923664f9b6acf86081c5bfd60b86bf46ab56e3f323ca4de9 1ae72d777218 2 months ago 129MBalgolia/docsearch-scraper latest sha256:7bc1cd5aa4783bf24be9ddd6ef22a629b6b43e217b3fa220b6a0acbdeb83b8f8 04e04eaa5c7d 15 months ago 1.74GB
本文將舉例說明使用 Tag 來辨識鏡像的一般痛點(diǎn),以及如何借助 Zadig 的能力來解決構(gòu)建產(chǎn)物溯源的問題
。痛點(diǎn)私有化交付過程中
,某開發(fā)人工誤操作,不慎導(dǎo)致線上鏡像倉庫中某個(gè)服務(wù)的版本被本地推送的相同 Tag 的鏡像所覆蓋,其中包含未經(jīng)驗(yàn)收測試的功能,用戶端升級服務(wù)或者重新拉取該服務(wù)鏡像后, 導(dǎo)致服務(wù)出現(xiàn)故障,比如:功能不 work、服務(wù)無法啟動...等,只通過鏡像無法追蹤具體是何種誤操作導(dǎo)致的,也不能定位到具體的代碼變更。版本迭代過程中,難免會同時(shí)維護(hù)多個(gè)版本
,用戶側(cè)使用的版本五花八門,如何進(jìn)行版本和代碼信息的定位匹配,快速排查客戶端反饋的問題也是一個(gè)頭疼的工程難題。下面將從構(gòu)建產(chǎn)物為鏡像以及非鏡像兩種場景
,介紹涵蓋前后端的實(shí)踐方案:可以從構(gòu)建產(chǎn)物中直接獲取詳細(xì)的構(gòu)建鏈路流程信息,提高后續(xù)問題定位排查的效率。場景一:鏡像構(gòu)建產(chǎn)物核心原理:修改 Dockerfile 添加 LABEL
,利用 Zadig 內(nèi)置構(gòu)建變量的能力,構(gòu)建鏡像時(shí)將其動態(tài)注入。背景知識關(guān)于 Docker 鏡像構(gòu)建
、LABEL 能力以及構(gòu)建參數(shù)相關(guān)可閱讀以下資料:Docker object labels[1]
Docker label / OCI image annotation metadata types[2]
Dockerfile LABEL[3]
Docker build ARG[4]
第一步:編寫 Dockerfile修改 Dockfile 動態(tài)注入 Zadig 提供的構(gòu)建變量
,這里以開源的zadig-portal[5]為例,主要注入如下信息:構(gòu)建時(shí)間構(gòu)建任務(wù)的 URL代碼信息(代碼庫/分支/PR/Tag/Commit ID)如果需要注入其他參數(shù)
,可以根據(jù)實(shí)際的項(xiàng)目需求進(jìn)行自定義ARG repoName="zadig-portal"ARG branch=""ARG pr=""ARG tag=""ARG commit=""ARG buildTime=""ARG buildURL=""LABEL maintainer="Zadig Maintainers" \ description="Zadig is a cloud native, distributed, developer-oriented continuous delivery product." \ repoName=${repoName} \ branch=${branch} \ pr=${pr} \ tag=${tag} \ commit=${commit} \ buildTime=${buildTime} \ buildURL=${buildURL}
第二步:完成構(gòu)建配置將 Zadig 提供的內(nèi)置構(gòu)建變量,透傳到 docker build --build-arg
由于 zadig-portal 使用的鏡像構(gòu)建
構(gòu)建參數(shù)中內(nèi)容如下:
--build-arg branch=$zadig_portal_BRANCH --build-arg pr=$zadig_portal_PR --build-arg tag=$zadig_portal_TAG --build-arg commit=$zadig_portal_COMMIT_ID --build-arg buildTime=$(date +%s) --build-arg buildURL=$BUILD_URL
第三步:效果驗(yàn)證至此
可以通過 docker pull 之后 docker inspect 查看注入的 Label
嘗試進(jìn)行 docker tag 后
核心原理:利用 Zadig 的構(gòu)建參數(shù)能力
對于暫時(shí)不便于遷移容器部署的場景
現(xiàn)代化前端應(yīng)用離不開模塊打包工具
背景知識
Webpack Define Plugin[6]Webpack Environment Plugin[7]Process Env[8]第一步:代碼實(shí)現(xiàn)1. 構(gòu)建模板代碼實(shí)現(xiàn)
該步驟主要依賴 Webpack Define Plugin
,創(chuàng)建一個(gè)需要的構(gòu)建環(huán)境變量模板,方便后續(xù)構(gòu)建時(shí)動態(tài)替換參數(shù)。const env = require("./config/prod.env");.......//其他配置 plugins: [ new webpack.DefinePlugin({ "BUILDINFO": env }), ]
prod.env 文件內(nèi)容如下:
"use strict"module.exports = { VERSION: ""${VERSION}"", BUILD_TIME: ""${BUILD_TIME}"", TAG: ""${TAG}"", COMMIT_ID: ""${COMMIT_ID}"", BRANCH: ""${BRANCH}"", PR: ""${PR}"",}
這里主要暴露以下參數(shù),可以根據(jù)實(shí)際需求進(jìn)行自定義
。VERSIONBUILD_TIMETAGCOMMIT_IDBRANCHPR2.在業(yè)務(wù)代碼中讀取并展示構(gòu)建變量
這里以 Vue 項(xiàng)目為例
,實(shí)現(xiàn)在終端中打印構(gòu)建信息,其他項(xiàng)目可自行調(diào)整computed: { processEnv () { return process.env }, }, mounted () { if (this.processEnv && this.processEnv.NODE_ENV === "production" && BUILDINFO) { console.log("%cHello ZADIG!", "color: #e20382;font-size: 13px;") const buildInfo = [] if (BUILDINFO.VERSION) { buildInfo.push(`${BUILDINFO.VERSION}`) } if (BUILDINFO.TAG) { buildInfo.push(`Tag-${BUILDINFO.TAG}`) } if (BUILDINFO.BRANCH) { buildInfo.push(`Branch-${BUILDINFO.BRANCH}`) } if (BUILDINFO.PR) { buildInfo.push(`PR-${BUILDINFO.PR}`) } if (BUILDINFO.COMMIT_ID) { buildInfo.push(`${BUILDINFO.COMMIT_ID.substring(0, 7)}`) } console.log( `%cBuild:${buildInfo.join(" ")}`, "color: #e20382;font-size: 13px;" ) if (BUILDINFO.BUILD_TIME) { console.log( `%cTime:${moment .unix(BUILDINFO.BUILD_TIME) .format("YYYYMMDDHHmm")}`, "color: #e20382;font-size: 13px;" ) } } }第二步:完成構(gòu)建配置將 Zadig 提供的內(nèi)置構(gòu)建變量,通過腳本實(shí)現(xiàn)動態(tài)替換 prod.env 的內(nèi)容
,主要使用以下變量:$_PR構(gòu)建時(shí)使用的代碼 Pull Request 信息$_BRANCH構(gòu)建時(shí)使用的代碼分支信息$_TAG構(gòu)建時(shí)使用代碼 Tag 信息$_COMMIT_ID構(gòu)建時(shí)使用代碼 Commit 信息第三步:效果驗(yàn)證運(yùn)行工作流
,可以看到構(gòu)建變量已經(jīng)成功的透傳,并且替換了預(yù)設(shè)的變量模板。部署后查看控制臺
,可以看到 Zadig 的構(gòu)建信息已經(jīng)可以在 console 中顯示。后端二進(jìn)制產(chǎn)物由于后端二進(jìn)制交付物背后的項(xiàng)目類型比較多
,這里主要介紹 Golang 項(xiàng)目一種實(shí)現(xiàn)思路,該部分涉及到的源碼可以點(diǎn)擊鏈接[9]查看,其他項(xiàng)目類型可以根據(jù)實(shí)際情況進(jìn)行參考和配置。背景知識go build -ldflags -X[10]Kubectl version[11]K8s version[12]Golang 中管理程序的版本信息[13]第一步:代碼實(shí)現(xiàn)1. 定義版本信息
這里在項(xiàng)目中維護(hù)一份 version.go 文件
,根據(jù)實(shí)際需求,定義需要暴露的參數(shù)。package utilsimport ( "fmt" "runtime")var ( version string gitBranch string gitTag string gitCommit string gitPR string gitTreeState string buildDate string buildURL string)// Info contains versioning information.type Info struct { Version string `json:"version"` GitBranch string `json:"gitBranch"` GitTag string `json:"gitTag"` GitCommit string `json:"gitCommit"` GitPR string `json:"gitPR"` GitTreeState string `json:"gitTreeState"` BuildDate string `json:"buildDate"` BuildURL string `json:"buildURL"` GoVersion string `json:"goVersion"` Compiler string `json:"compiler"` Platform string `json:"platform"`}// String returns info as a human-friendly version string.func (info Info) String() string { return info.Platform}func GetVersion() Info { return Info{ Version: version, GitBranch: gitBranch, GitTag: gitTag, GitCommit: gitCommit, GitPR: gitPR, GitTreeState: gitTreeState, BuildDate: buildDate, BuildURL: buildURL, GoVersion: runtime.Version(), Compiler: runtime.Compiler, Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), }}
2. main 函數(shù)調(diào)用
在入口處設(shè)置傳入version參數(shù)調(diào)用GetVersion函數(shù):
package mainimport ( "fmt" "os" "version/utils")func main() { args := os.Args if len(args) >= 2 && args[1] == "version" { v := utils.GetVersion() fmt.Printf("Version: %s\nBranch: %s\nCommit: %s\nPR: %s\nBuild Time: %s\nGo Version: %s\nOS/Arch: %s\nBuild URL: %s\n", v.Version, v.GitBranch, v.GitCommit,v.GitPR, v.BuildDate, v.GoVersion, v.Platform,v.BuildURL) } else { fmt.Printf("Version(hard code): %s\n", "0.1") }}
3. 構(gòu)建工程文件編寫
這里新建一個(gè) Makefile 進(jìn)行構(gòu)建
,使用ldflags -X透傳 Zadig 構(gòu)建內(nèi)置變量,核心邏輯如下:# build with verison infosversinotallow="version/utils"gitTag=$(version_TAG)gitBranch=$(version_BRANCH)gitPR=$(version_PR)buildDate=$(shell TZ=Asia/Shanghai date +%FT%T%z)gitCommit=$(version_COMMIT_ID)gitTreeState=$(shell if git status|grep -q "clean";then echo clean; else echo dirty; fi)buildURL=$(BUILD_URL)ldflags="-s -w -X ${versionDir}.gitTag=${gitTag} -X ${versionDir}.buildDate=${buildDate} -X ${versionDir}.gitCommit=${gitCommit} -X ${versionDir}.gitPR=${gitPR} -X ${versionDir}.gitTreeState=${gitTreeState} -X ${versionDir}.versinotallow=${VERSION} -X ${versionDir}.gitBranch=${gitBranch} -X ${versionDir}.buildURL=${buildURL}"PACKAGES=`go list ./... | grep -v /vendor/`VETPACKAGES=`go list ./... | grep -v /vendor/ | grep -v /examples/`GOFILES=`find . -name "*.go" -type f -not -path "./vendor/*"`default: @echo "build the ${BINARY}" @GOOS=linux GOARCH=amd64 go build -ldflags ${ldflags} -o build/${BINARY}.linux -tags=jsoniter @go build -ldflags ${ldflags} -o build/${BINARY}.mac -tags=jsoniter @echo "build done."
第二步:完成構(gòu)建配置在 Zadig 中配置構(gòu)建
,在構(gòu)建腳本中構(gòu)建并打印輸出,詳細(xì)信息如下:依賴的軟件包go 1.16.13自定義構(gòu)建變量配置 VERSION 變量構(gòu)建腳本內(nèi)容如下:set -ecd $WORKSPACE/zadig/examples/version-demoenvmake defaultcd build./version.linux version
第三步:效果驗(yàn)證運(yùn)行工作流,可以看到構(gòu)建變量已經(jīng)成功的透傳
,并且該二進(jìn)制程序通過version參數(shù)可以打印詳細(xì)的構(gòu)建來源信息。結(jié)語以上
,就是一些常見交付物類型在 Zadig 上的溯源思路總結(jié),相比于通過原始的 Image ID 、Digest ....來反推進(jìn)行追蹤,該流程可以讓用戶以及開發(fā)人員通過更簡單便捷的方式上報(bào)或者追蹤交付物問題,提高問題排查定位的效率。參考鏈接[1]https://docs.docker.com/config/labels-custom-metadata/
[2]https://github.com/opencontainers/image-spec/blob/main/annotations.md
[3]https://docs.docker.com/engine/reference/builder/#label
[4]https://docs.docker.com/engine/reference/builder/#arg
[5] https://github.com/koderover/zadig-portal/blob/main/Dockerfile
[6] https://webpack.js.org/plugins/define-plugin/
[7] https://webpack.js.org/plugins/environment-plugin/#root
[8]https://nodejs.org/api/process.html#process_process_env
[9]https://github.com/koderover/zadig/tree/main/examples/version-demo
[10] https://pkg.go.dev/cmd/link
[11]https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/version/version.go
[12] https://github.com/kubernetes/component-base/blob/master/version/version.go
[13] https://zhuanlan.zhihu.com/p/150991555
關(guān)鍵詞:
最近更新
- 如何優(yōu)雅的在 Zadig 上實(shí)踐交付物溯源流程|全球快資訊2023-04-25
- “星艦”下次發(fā)射遙不可及?發(fā)射臺已嚴(yán)重?fù)p壞!2023-04-25
- 食品加工板塊表現(xiàn)活躍,安井食品快速漲停-全球頭條2023-04-25
- 鋰電板塊開盤下挫!一季度鋰價(jià)下跌,帶崩多家公司業(yè)績|世界播報(bào)2023-04-25
- 報(bào)告:商務(wù)旅行再也回不到疫情前水平了2023-04-25
- 五一勞動模范|彭紅:社區(qū)“當(dāng)家人” 居民“知心人”2023-04-25
- 太龍股份(300650):續(xù)聘2023年審計(jì)機(jī)構(gòu) 觀天下2023-04-25
- 《復(fù)興文庫》閱讀推廣第三期:高俊平|全球觀察2023-04-25
- 鋰電板塊開盤下挫!一季度鋰價(jià)下跌,帶崩多家公司業(yè)績 環(huán)球觀天下2023-04-25
- 賀勝橋鎮(zhèn):多措并舉推進(jìn)平安建設(shè)2023-04-25
- 烏無人機(jī)在莫斯科郊外墜毀