咱们的项目之前都是由各开发人员本身写一个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
来记录时间,保证部署成功