咱們的項目之前都是由各開發人員本身寫一個config.js
或者app.conf
來管理項目的配置信息,常常出現下面的問題,我須要一個配置服務來解決它html
若是沒犯低級錯誤的話,通常也不會出現什麼問題,什麼是低級錯誤呢,就拿前端來講,之前引入配置通常這樣前端
if( env === 'dev' ){
configs = import('./dev.config')
}else if( env === 'test' ){
configs = import('./test.config')
}else{
configs = import('./prod.config')
}
複製代碼
本地爲了解決測試環境的一個bug,原本env
應該爲dev
的,結果爲了用測試環境的配置,強制把env
設置爲test
了,而後問題解決了,測試環境測試也沒問題了,發佈的時候就直接更新到正式環境了,結果就gg了,一查原來是env
忘記改了。node
接着杜絕犯低級錯誤
,上面那樣寫前端配置還會有個問題,就是前端按F12
能夠看到咱們測試服務器的一些信息,好比某個網頁的測試前端域名,這些信息我其時是不想外面看到的linux
假如我有一個基礎服務A
,B
和C
模塊依賴服務A
的域名,那麼就要在這兩個模塊下各寫一個域名配置nginx
export default {
A_Domain:"https://xxx.readboy.com"
}
複製代碼
看起來是沒問題,其實這裏我以爲問題不少,假如個人A
模塊域名更新了,我只知道B
模塊依賴這個域名,通知了B
模塊開發人員修改,而後更新了,舊域名移除了,那麼C
模塊確定會有問題,若是能由各開發人員維護本身的配置,依賴項目不須要設置,直接配置依賴,直接引用就行了git
這個問題是基於配置冗餘問題
的,我但願我能夠知道這個配置(A
模塊域名)有哪些項目依賴了,若是這個配置更新了,我但願依賴的項目能自動拉取最新的配置並部署es6
基於上面的問題,網上大概找了下相關的解決方案都不太滿意(本身能力太水^-^),golang
http
就能解決,來吧,搞起來新建一個項目,指定這個項目有哪些環境,通常固定prod
,env
,dev
docker
項目指定幾個環境,相應項目下的配置就有相應的環境,開發人員填入相應的值就行 shell
這基本就完成了項目的配置存儲功能,怎麼用呢?這個時候就須要定義一個配置描述文件(.config.yml
)了,基本內容就是你要哪些項目的哪一個配置,由配置服務接口根據描述文件自動返回配置值
配置更新自動部署全部依賴的項目
format: json
itemFormat: 配置key處理規則,看下面
envBranch:
test: test
prod: master
project:
name: readboyconfig
description: 項目描述
id: gitlab項目ID
configs:
projecta:
- configa
- configb
- configc
projectb:
- configb
- configc
- configd
env: test(環境在部署的時候動態寫入)
複製代碼
format
表示輸出文件格式,值以下:
js
(es6)
json
ini
yml
project
表示工程信息,主要是相關配置更新後用於重啓服務用的
id
項目在gitlab中的ID
name
項目名稱
description
項目描述信息
envBranch
環境和分支的對應關係,主要是相關配置更新後用於重啓服務用的
格式: env
: branch name
env
表示要輸出的環境配置,值對應後臺錄入的env
itemFormat
表示生成配置項的方式,取值以下
ignore
忽略項目名
prefix
項目名+配置名
dot
項目名+ .
+鏈接配置
tree
保持層級結構
project_without_prefix
當前項目不加前綴,其它項目同 prefix
project_without_dot
當前項目不用.
鏈接,其它項目同 dot
project_without_tree
當前項目不保持層級結構,其它項目同 tree
configs
項目配置信息,具體參考後臺數據
CI配置
全部配置信息更新後,會觸發依賴項目的CI
並攜帶參數 readboy_trigger=config
,若是某些階段在自動觸發的CI中不要執行,能夠在CI
文件中加上條件
only:
variables
- $readboy_trigger == 'config'
複製代碼
或
except:
variables
- $readboy_trigger == 'config'
複製代碼
curl "${CONFIG_SERVER}" -fd "`cat .config.yml`" > src/config/index.js
複製代碼
CONFIG_SERVER
這個接口要實現功能主要有:
gitlab
項目的依賴關係,當相關配置更新的時候,本身觸發相關項目的gitlab CI
,實現自動拉取最新配置,自動部署配置管理後臺的配置值更新的時候,程序會檢測哪一個環境的值變了,並獲取依賴該屬性的gitlab
項目信息,利用gitlab
的API
,API連接,自動建立一個pipeline
來拉取配置,部署程序。至此,一個簡單的基於gitlab
的配置服務就完成了。
固然要徹底把這個配置服務利用起來,還須要跟開發人員作要求,配置使用,依賴項目的配置絕對不要再寫一遍,否則配置變了,更新就會出問題。
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
複製代碼
FROM nginx:latest
COPY dist /usr/share/nginx/html
COPY docker/default.conf /etc/nginx/conf.d
複製代碼
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
複製代碼
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的話,會部署一個空的配置文件到服務器上,出現服務不可用的問題,加上-f
,若是你的CONFIG_SERVER
有bug,返回500
了,CI
會中斷執行,不會把有問題的程序部署到服務器
若是內容沒變,編譯出來的鏡像名稱是同樣的,從新部署pod
會失敗,因此爲了保證每次編譯出來的鏡像名稱不同,用datetime
來記錄時間,保證部署成功