一個(gè)簡(jiǎn)單的基于gitlab的配置服務(wù)

要什么樣的配置服務(wù)

我們的項(xiàng)目以前都是由各開發(fā)人員自己寫一個(gè)config.js或者app.conf來(lái)管理項(xiàng)目的配置信息某饰,經(jīng)常出現(xiàn)下面的問(wèn)題,我需要一個(gè)配置服務(wù)來(lái)解決它

1. 杜絕犯低級(jí)錯(cuò)誤

如果沒(méi)犯低級(jí)錯(cuò)誤的話渴逻,一般也不會(huì)出現(xiàn)什么問(wèn)題猿妈,什么是低級(jí)錯(cuò)誤呢精钮,就拿前端來(lái)說(shuō)袍啡,以前引入配置一般這樣

if( env === 'dev' ){
    configs = import('./dev.config')
}else if( env === 'test' ){
    configs = import('./test.config')
}else{
    configs = import('./prod.config')
}

本地為了解決測(cè)試環(huán)境的一個(gè)bug,本來(lái)env應(yīng)該為dev的珠增,結(jié)果為了用測(cè)試環(huán)境的配置超歌,強(qiáng)制把env設(shè)置為test了,然后問(wèn)題解決了蒂教,測(cè)試環(huán)境測(cè)試也沒(méi)問(wèn)題了巍举,發(fā)布的時(shí)候就直接更新到正式環(huán)境了,結(jié)果就gg了凝垛,一查原來(lái)是env忘記改了懊悯。

2. 不希望當(dāng)前環(huán)境看到其它環(huán)境的配置值

接著杜絕犯低級(jí)錯(cuò)誤,上面那樣寫前端配置還會(huì)有個(gè)問(wèn)題梦皮,就是前端按F12可以看到我們測(cè)試服務(wù)器的一些信息炭分,比如某個(gè)網(wǎng)頁(yè)的測(cè)試前端域名,這些信息我其時(shí)是不想外面看到的

3. 配置冗余問(wèn)題

假如我有一個(gè)基礎(chǔ)服務(wù)A剑肯,BC模塊依賴服務(wù)A的域名捧毛,那么就要在這兩個(gè)模塊下各寫一個(gè)域名配置

export default {
    A_Domain:"https://xxx.readboy.com"
}

看起來(lái)是沒(méi)問(wèn)題,其實(shí)這里我覺得問(wèn)題很多让网,假如我的A模塊域名更新了呀忧,我只知道B模塊依賴這個(gè)域名,通知了B模塊開發(fā)人員修改溃睹,然后更新了而账,舊域名移除了,那么C模塊肯定會(huì)有問(wèn)題因篇,如果能由各開發(fā)人員維護(hù)自己的配置泞辐,依賴項(xiàng)目不需要設(shè)置,直接配置依賴竞滓,直接引用就好了

4. 建立配置和項(xiàng)目依賴

這個(gè)問(wèn)題是基于配置冗余問(wèn)題的咐吼,我希望我可以知道這個(gè)配置(A模塊域名)有哪些項(xiàng)目依賴了,如果這個(gè)配置更新了商佑,我希望依賴的項(xiàng)目能自動(dòng)拉取最新的配置并部署

總結(jié)

基于上面的問(wèn)題锯茄,網(wǎng)上大概找了下相關(guān)的解決方案都不太滿意(自己能力太水-),

  1. 我不想要運(yùn)行時(shí)動(dòng)態(tài)拉取配置莉御,總感覺這個(gè)可靠性不強(qiáng)(小廠撇吞,資源有限)
  2. 獲取配置要足夠簡(jiǎn)單,不要再配環(huán)境礁叔,還要裝什么客戶端牍颈,我希望一個(gè)http就能解決,來(lái)吧琅关,搞起來(lái)

配置服務(wù)實(shí)現(xiàn)的基本功能

項(xiàng)目管理

新建一個(gè)項(xiàng)目煮岁,指定這個(gè)項(xiàng)目有哪些環(huán)境,一般固定prod,env,dev

項(xiàng)目管理

配置管理

項(xiàng)目指定幾個(gè)環(huán)境涣易,相應(yīng)項(xiàng)目下的配置就有相應(yīng)的環(huán)境画机,開發(fā)人員填入相應(yīng)的值就行


配置管理

這基本就完成了項(xiàng)目的配置存儲(chǔ)功能,怎么用呢新症?這個(gè)時(shí)候就需要定義一個(gè)配置描述文件(.config.yml)了步氏,基本內(nèi)容就是你要哪些項(xiàng)目的哪個(gè)配置,由配置服務(wù)接口根據(jù)描述文件自動(dòng)返回配置值

運(yùn)行效果(gif圖徒爹,有點(diǎn)大)

配置更新自動(dòng)部署所有依賴的項(xiàng)目


自動(dòng)部署

format: json
itemFormat: 配置key處理規(guī)則荚醒,看下面
envBranch: 
  test: test
  prod: master
project:
  name: readboyconfig
  description: 項(xiàng)目描述
  id: gitlab項(xiàng)目ID
configs:
  projecta:
    - configa
    - configb
    - configc
  projectb:
    - configb
    - configc
    - configd
env: test(環(huán)境在部署的時(shí)候動(dòng)態(tài)寫入)
    

format

表示輸出文件格式,值如下:

js(es6)

json

ini

yml


project

表示工程信息隆嗅,主要是相關(guān)配置更新后用于重啟服務(wù)用的

id 項(xiàng)目在gitlab中的ID

name 項(xiàng)目名稱

description 項(xiàng)目描述信息


envBranch

環(huán)境和分支的對(duì)應(yīng)關(guān)系界阁,主要是相關(guān)配置更新后用于重啟服務(wù)用的

格式:
env: branch name


env

表示要輸出的環(huán)境配置,值對(duì)應(yīng)后臺(tái)錄入的env


itemFormat

表示生成配置項(xiàng)的方式胖喳,取值如下

ignore 忽略項(xiàng)目名

prefix 項(xiàng)目名+配置名

dot 項(xiàng)目名+ . +連接配置

tree 保持層級(jí)結(jié)構(gòu)

project_without_prefix 當(dāng)前項(xiàng)目不加前綴泡躯,其它項(xiàng)目同 prefix

project_without_dot 當(dāng)前項(xiàng)目不用.連接,其它項(xiàng)目同 dot

project_without_tree 當(dāng)前項(xiàng)目不保持層級(jí)結(jié)構(gòu)丽焊,其它項(xiàng)目同 tree

configs

項(xiàng)目配置信息较剃,具體參考后臺(tái)數(shù)據(jù)

CI配置

所有配置信息更新后,會(huì)觸發(fā)依賴項(xiàng)目的CI并攜帶參數(shù) readboy_trigger=config粹懒,如果某些階段在自動(dòng)觸發(fā)的CI中不要執(zhí)行重付,可以在CI文件中加上條件

only:
  variables
    - $readboy_trigger == 'config'

except:
  variables
    - $readboy_trigger == 'config'

yml格式說(shuō)明結(jié)束


獲取配置

curl "${CONFIG_SERVER}" -fd "`cat .config.yml`" > src/config/index.js

CONFIG_SERVER這個(gè)接口要實(shí)現(xiàn)功能主要有:

  1. 根據(jù)環(huán)境來(lái)獲取描述文件的值
  2. 建立相關(guān)配置和gitlab項(xiàng)目的依賴關(guān)系,當(dāng)相關(guān)配置更新的時(shí)候凫乖,自己觸發(fā)相關(guān)項(xiàng)目的gitlab CI确垫,實(shí)現(xiàn)自動(dòng)拉取最新配置,自動(dòng)部署
獲取配置
自動(dòng)部署

配置管理后臺(tái)的配置值更新的時(shí)候帽芽,程序會(huì)檢測(cè)哪個(gè)環(huán)境的值變了删掀,并獲取依賴該屬性的gitlab項(xiàng)目信息,利用gitlabAPI导街,API鏈接披泪,自動(dòng)創(chuàng)建一個(gè)pipeline來(lái)拉取配置,部署程序搬瑰。至此款票,一個(gè)簡(jiǎn)單的基于gitlab的配置服務(wù)就完成了控硼。

當(dāng)然要完全把這個(gè)配置服務(wù)利用起來(lái),還需要跟開發(fā)人員做要求艾少,配置使用卡乾,依賴項(xiàng)目的配置絕對(duì)不要再寫一遍,不然配置變了缚够,更新就會(huì)出問(wèn)題幔妨。


一些CI配置

前端CI文件

image: node:8.9.3
stages:
  - build
  - buildImage  
  - deploy

variables:
  ALI_REGISTRY_HOST: ""
  ALI_REGISTRY_IMAGE: ""
  ALI_SERVICE_NAME: ""
  PROD_NAMESPACE: ebag-prod
  BETA_IMAGE: beta-$CI_COMMIT_SHA
  BETA_LATEST: beta-latest

masterbuild:
  stage: build
  script:
    - printf "\nenv:" >> .config.yml
    - printf " prod" >> .config.yml
    - curl "${CONFIG_SERVER}" -fd "`cat .config.yml`" > src/config/index.js
    - npm install --no-optional
    - npm run build
    - node ./tools/generate.config.js
    - qshell='./tools/qshell-linux-x64'
    - chmod a+x "${qshell}"
    - ${qshell} account "${QINIU_AK}" "${QINIU_SK}"
    - ${qshell} qupload 8 ./qiniuconfig
  only:
    - master
  artifacts:
    expire_in: 1 week
    paths:
      - dist
      
imagebuild:
  stage: buildImage
  image: docker:latest
  script:
    - docker login -u $ALI_REGISTRY_USER -p $ALI_REGISTRY_PASSWORD $ALI_REGISTRY_HOST
    - docker build -t $ALI_REGISTRY_IMAGE:$BETA_IMAGE -t $ALI_REGISTRY_IMAGE:$BETA_LATEST -f docker/Dockerfile .
    - docker push $ALI_REGISTRY_IMAGE:$BETA_IMAGE
    - docker push $ALI_REGISTRY_IMAGE:$BETA_LATEST
  only:
    - master

前端Dockerfile

FROM nginx:latest
COPY dist /usr/share/nginx/html
COPY docker/default.conf /etc/nginx/conf.d

服務(wù)端CI文件

image: docker:git
stages:
  - build
  - deploy

variables:
  ALI_REGISTRY_IMAGE: "..."
  ALI_SERVICE_NAME: "readboyconfig"

build_test:
  stage: build
  script:
    - echo `date "+%Y%m%d%H%M%S"` > ./datetime
    - docker build --build-arg APP_ROOT=/go/src/$CI_PROJECT_NAME --build-arg EXPOSE_PORT=6381 --build-arg DREAM_ENV=test --build-arg TAG_NAME=${CI_COMMIT_SHA} --build-arg CONFIG_SERVER=${CONFIG_SERVER}  -t ${ALI_REGISTRY_IMAGE}:latest -t ${ALI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}_`cat ./datetime` -f docker/Dockerfile .
    - docker login -u $ALI_REGISTRY_USER -p $ALI_REGISTRY_PASSWORD $ALI_REGISTRY_HOST
    - docker push ${ALI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}_`cat ./datetime`
    - docker push ${ALI_REGISTRY_IMAGE}:latest
  artifacts:
    expire_in: 2 days
    paths:
      - datetime
  only:
    - test

deploy_test:
  stage: deploy
  variables:
    IMAGE_NAME: ${ALI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
  image: ...
  before_script:
    - mkdir -p ~/.kube
    - echo "$TEST_KUBERNETES_CONFIG" > ~/.kube/config
    - echo "$TEST_KUBERNETES_CA" > ~/.kube/ca.crt
  script:
    - kubectl -n ebag-test set image deployment/${ALI_SERVICE_NAME} ${ALI_SERVICE_NAME}=${IMAGE_NAME}_`cat ./datetime`
  only:
    - test

服務(wù)端Dockerfile文件(去掉一些非必要信息)

FROM golang:1.9.2 AS gobuild
WORKDIR ${APP_ROOT}
RUN curl "${CONFIG_SERVER}" -fd "`cat .comfig.yml`" > ./conf/dev/app.conf
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./main.go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o migrate ./migrate.go

FROM alpine:latest
ARG APP_ROOT
ARG DREAM_ENV
ARG EXPOSE_PORT
WORKDIR /app
EXPOSE ${EXPOSE_PORT}
USER root
RUN mkdir -p ./conf/dev && touch ./conf/dev/app.conf
RUN mkdir -p ./log
VOLUME ["/app/log"]
COPY --from=gobuild ${APP_ROOT}/migrate ./migrate
COPY --from=gobuild ${APP_ROOT}/main ./main
COPY --from=gobuild ${APP_ROOT}/conf/ ./conf/
COPY --from=gobuild ${APP_ROOT}/migration/ ./migration/
COPY --from=gobuild ${APP_ROOT}/docker/start.sh ./start.sh
COPY --from=gobuild ${APP_ROOT}/bin ./bin
ENTRYPOINT ["/app/start.sh"]

注意

curl一定要把-f加上,不然你的CONFIG_SERVER有bug的話谍椅,會(huì)部署一個(gè)空的配置文件到服務(wù)器上误堡,出現(xiàn)服務(wù)不可用的問(wèn)題,加上-f雏吭,如果你的CONFIG_SERVER有bug锁施,返回500了,CI會(huì)中斷執(zhí)行思恐,不會(huì)把有問(wèn)題的程序部署到服務(wù)器

為什么有要datetime

如果內(nèi)容沒(méi)變沾谜,編譯出來(lái)的鏡像名稱是一樣的,重新部署pod會(huì)失敗胀莹,所以為了保證每次編譯出來(lái)的鏡像名稱不一樣基跑,用datetime來(lái)記錄時(shí)間,保證部署成功

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末描焰,一起剝皮案震驚了整個(gè)濱河市媳否,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荆秦,老刑警劉巖篱竭,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異步绸,居然都是意外死亡掺逼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門瓤介,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吕喘,“玉大人,你說(shuō)我怎么就攤上這事刑桑÷戎剩” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵祠斧,是天一觀的道長(zhǎng)闻察。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么辕漂? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任呢灶,我火速辦了婚禮,結(jié)果婚禮上钉嘹,老公的妹妹穿的比我還像新娘填抬。我一直安慰自己,他們只是感情好隧期,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赘娄,像睡著了一般仆潮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遣臼,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天性置,我揣著相機(jī)與錄音,去河邊找鬼揍堰。 笑死鹏浅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屏歹。 我是一名探鬼主播隐砸,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蝙眶!你這毒婦竟也來(lái)了季希?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤幽纷,失蹤者是張志新(化名)和其女友劉穎式塌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體友浸,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡峰尝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了收恢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片武学。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖派诬,靈堂內(nèi)的尸體忽然破棺而出劳淆,到底是詐尸還是另有隱情,我是刑警寧澤默赂,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布沛鸵,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏曲掰。R本人自食惡果不足惜疾捍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望栏妖。 院中可真熱鬧乱豆,春花似錦、人聲如沸吊趾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)论泛。三九已至揩尸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間屁奏,已是汗流浹背岩榆。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坟瓢,地道東北人勇边。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像折联,于是被迫代替她去往敵國(guó)和親粒褒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353