新聞中心
背景
云原生服務(wù)的開(kāi)發(fā)迭代,Docker 鏡像作為最終的交付產(chǎn)物,其生命周期中存在多個(gè)環(huán)節(jié)的流轉(zhuǎn):從鏡像構(gòu)建開(kāi)始,到開(kāi)發(fā)、測(cè)試環(huán)境的更新驗(yàn)證,再到交付制品生成,交付到生產(chǎn)環(huán)境。在這一整套的流轉(zhuǎn)過(guò)程中,鏡像作為流轉(zhuǎn)物,只要中間的一個(gè)流程出現(xiàn)失誤,很容易導(dǎo)致交付到生產(chǎn)環(huán)境的鏡像出現(xiàn)問(wèn)題。

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶(hù)真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶(hù)帶來(lái)驚喜。創(chuàng)新互聯(lián)推出樂(lè)亭免費(fèi)做網(wǎng)站回饋大家。
雖然 Tag 可以讓鏡像有一定的辨識(shí)度,但其可以修改的特性,并不能作為辨識(shí)身份的標(biāo)準(zhǔn)。 如果構(gòu)建流程中有需要人工干預(yù)修改 Tag 的操作,在交付過(guò)程中也會(huì)引入更多的風(fēng)險(xiǎn)。鏡像 ID 和 Digests 配合可以作為唯一身份標(biāo)識(shí)確保交付物的一致性,但可讀性比較差,出現(xiàn)交付物不一致的問(wèn)題,溯源的成本也比較高。
docker images --digests
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
koderover.tencentcloudcr.com/koderover-public/aslan 1.15.0-20220922-amd64 sha256:8af42b5dd2a8539c3a1ead4f7bcbcc0028f1ec84090ace6f853793151fc0a7d0 35331bf1ae55 22 hours ago 188MB
koderover.tencentcloudcr.com/koderover-public/zadig-portal 1.13.0-amd64 sha256:15d8207a3ab3573ea8e5a3e32be9fa9340dfb4a5fe0842d3ef848a92655c6f58 1cb89026c2c5 47 hours ago 133MB
koderover.tencentcloudcr.com/koderover-public/zadig-portal 1.14.0-amd64 sha256:1bdb47274a6cb6da12b5fb2d3a073e820a8d5a8be9dac48f8f624adb85ddcefd 63e46ebf3e11 3 weeks ago 133MB
tailscale/docker-extension 0.0.13 sha256:5f957b07602dd9b8923664f9b6acf86081c5bfd60b86bf46ab56e3f323ca4de9 1ae72d777218 2 months ago 129MB
algolia/docsearch-scraper latest sha256:7bc1cd5aa4783bf24be9ddd6ef22a629b6b43e217b3fa220b6a0acbdeb83b8f8 04e04eaa5c7d 15 months ago 1.74GB本文將舉例說(shuō)明使用 Tag 來(lái)辨識(shí)鏡像的一般痛點(diǎn),以及如何借助 Zadig 的能力來(lái)解決構(gòu)建產(chǎn)物溯源的問(wèn)題。
痛點(diǎn)
私有化交付過(guò)程中,某開(kāi)發(fā)人工誤操作,不慎導(dǎo)致線(xiàn)上鏡像倉(cāng)庫(kù)中某個(gè)服務(wù)的版本被本地推送的相同 Tag 的鏡像所覆蓋,其中包含未經(jīng)驗(yàn)收測(cè)試的功能,用戶(hù)端升級(jí)服務(wù)或者重新拉取該服務(wù)鏡像后, 導(dǎo)致服務(wù)出現(xiàn)故障,比如:功能不 work、服務(wù)無(wú)法啟動(dòng)...等,只通過(guò)鏡像無(wú)法追蹤具體是何種誤操作導(dǎo)致的,也不能定位到具體的代碼變更。
版本迭代過(guò)程中,難免會(huì)同時(shí)維護(hù)多個(gè)版本,用戶(hù)側(cè)使用的版本五花八門(mén),如何進(jìn)行版本和代碼信息的定位匹配,快速排查客戶(hù)端反饋的問(wèn)題也是一個(gè)頭疼的工程難題。
下面將從構(gòu)建產(chǎn)物為鏡像以及非鏡像兩種場(chǎng)景,介紹涵蓋前后端的實(shí)踐方案:可以從構(gòu)建產(chǎn)物中直接獲取詳細(xì)的構(gòu)建鏈路流程信息,提高后續(xù)問(wèn)題定位排查的效率。
場(chǎng)景一:鏡像構(gòu)建產(chǎn)物
核心原理:修改 Dockerfile 添加 LABEL,利用 Zadig 內(nèi)置構(gòu)建變量的能力,構(gòu)建鏡像時(shí)將其動(dòng)態(tài)注入。
背景知識(shí)
關(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]
第一步:編寫(xiě) Dockerfile
修改 Dockfile 動(dòng)態(tài)注入 Zadig 提供的構(gòu)建變量,這里以開(kāi)源的 zadig-portal[5] 為例,主要注入如下信息:
- 構(gòu)建時(shí)間
- 構(gòu)建任務(wù)的 URL
- 代碼信息(代碼庫(kù)/分支/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)建變量,透?jìng)鞯?docker build --build-arg,主要使用以下變量:
- $BUILD_URL 構(gòu)建任務(wù)的 URL
- $
_PR 構(gòu)建時(shí)使用的代碼 Pull Request 信息 - $
_BRANCH 構(gòu)建時(shí)使用的代碼分支信息 - $
_TAG 構(gòu)建時(shí)使用代碼 Tag 信息 - $
_COMMIT_ID 構(gòu)建時(shí)使用代碼 Commit 信息
由于 zadig-portal 使用的鏡像構(gòu)建,這里配置鏡像構(gòu)建的構(gòu)建參數(shù),將變量透?jìng)鞯?nbsp;Docker build ARG 。如果不使用鏡像構(gòu)建也可以根據(jù)實(shí)際構(gòu)建需求,在腳本中手動(dòng)拼接 docker build 參數(shù)。
構(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)證
至此,所有通過(guò) Zadig 運(yùn)行工作流產(chǎn)生的交付鏡像,都會(huì)被打上自定義的 Label。
可以通過(guò) docker pull 之后 docker inspect 查看注入的 Label。
嘗試進(jìn)行 docker tag 后,重新查看 Label,Label 并不會(huì)因?yàn)?Retag 而發(fā)生變化。
場(chǎng)景二:其他構(gòu)建產(chǎn)物
核心原理:利用 Zadig 的構(gòu)建參數(shù)能力,動(dòng)態(tài)傳入來(lái)源信息。
對(duì)于暫時(shí)不便于遷移容器部署的場(chǎng)景,比如基礎(chǔ)設(shè)施本身是可網(wǎng)絡(luò)互通的設(shè)備:IoT 物聯(lián)網(wǎng)場(chǎng)景下自動(dòng)駕駛車(chē)輛主機(jī)端、工廠可連接設(shè)備...等,交付物可能是二進(jìn)制或者是前端靜態(tài)文件。上述通過(guò)鏡像做追蹤溯源的實(shí)踐方法也就不再適用。下面分別介紹前端靜態(tài)文件以及后端二進(jìn)制程序的溯源方法。
前端靜態(tài)文件
現(xiàn)代化前端應(yīng)用離不開(kāi)模塊打包工具,這里以 Webpack 為例,介紹一種通過(guò)環(huán)境變量透?jìng)鞯乃菰捶椒?。其他的工?Vite、Parcel ...... 也可以參照該思路進(jìn)行實(shí)踐,具體配置可以參照相關(guān)打包工具的文檔。
背景知識(shí)
- Webpack Define Plugin[6]
- Webpack Environment Plugin[7]
- Process Env[8]
第一步:代碼實(shí)現(xiàn)
1. 構(gòu)建模板代碼實(shí)現(xiàn)
該步驟主要依賴(lài) Webpack Define Plugin ,創(chuàng)建一個(gè)需要的構(gòu)建環(huán)境變量模板,方便后續(xù)構(gòu)建時(shí)動(dòng)態(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)行自定義。
- VERSION
- BUILD_TIME
- TAG
- COMMIT_ID
- BRANCH
- PR
2.在業(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)建變量,通過(guò)腳本實(shí)現(xiàn)動(dòng)態(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)成功的透?jìng)?,并且替換了預(yù)設(shè)的變量模板。
部署后查看控制臺(tái),可以看到 Zadig 的構(gòu)建信息已經(jīng)可以在 console 中顯示。
后端二進(jìn)制產(chǎn)物
由于后端二進(jìn)制交付物背后的項(xiàng)目類(lèi)型比較多,這里主要介紹 Golang 項(xiàng)目一種實(shí)現(xiàn)思路,該部分涉及到的源碼可以點(diǎn)擊 鏈接[9] 查看,其他項(xiàng)目類(lèi)型可以根據(jù)實(shí)際情況進(jìn)行參考和配置。
背景知識(shí)
- 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 utils
import (
"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 main
import (
"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)建工程文件編寫(xiě)
這里新建一個(gè) Makefile 進(jìn)行構(gòu)建,使用 ldflags -X 透?jìng)?Zadig 構(gòu)建內(nèi)置變量,核心邏輯如下:
# build with verison infos
versinotallow="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ì)信息如下:
- 依賴(lài)的軟件包 go 1.16.13
- 自定義構(gòu)建變量 配置 VERSION 變量
- 構(gòu)建腳本 內(nèi)容如下:
set -e
cd $WORKSPACE/zadig/examples/version-demo
env
make default
cd build
./version.linux version第三步:效果驗(yàn)證
運(yùn)行工作流,可以看到構(gòu)建變量已經(jīng)成功的透?jìng)?,并且該二進(jìn)制程序通過(guò) version 參數(shù)可以打印詳細(xì)的構(gòu)建來(lái)源信息。
結(jié)語(yǔ)
以上,就是一些常見(jiàn)交付物類(lèi)型在 Zadig 上的溯源思路總結(jié),相比于通過(guò)原始的 Image ID 、Digest ....來(lái)反推進(jìn)行追蹤,該流程可以讓用戶(hù)以及開(kāi)發(fā)人員通過(guò)更簡(jiǎn)單便捷的方式上報(bào)或者追蹤交付物問(wèn)題,提高問(wèn)題排查定位的效率。
參考鏈接
[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
網(wǎng)站標(biāo)題:如何優(yōu)雅的在Zadig上實(shí)踐交付物溯源流程
URL鏈接:http://m.fisionsoft.com.cn/article/dppeeoo.html


咨詢(xún)
建站咨詢(xún)
