持续集成CI/CD之配置管理最佳实践

网友投稿 328 2022-09-10

持续集成CI/CD之配置管理最佳实践

上一章:​​持续集成CI&CD之工具快速搭建​​

下一章:​​持续集成CI&CD之CI的完整版最佳实践​​

选用阿里的nacos配置管理进行最佳实践

Nacos Config 配置方案设计

业务配置的一些场景

在实际的业务场景中应用和共享配置间的关系可能如下图所示:

从单个应用的角度来看: 应用可能会有多套(develop/beta/product)发布环境,多套发布环境之间有不同的基础配置,例如数据库。从多个应用的角度来看:多个应用间可能会有一些共享通用的配置,比如多个应用之间共用一套zookeeper集群。

极简配置方案设计

在实际开发、运维过程中,如果一个或多个应用使用了多个配置文件,特别是共享的配置文件,很容易出现误解,搞混配置【需要区别多个配置文件的优先级】;建议设计2层配置文件即可,手动配置的全局共享配置只能有一个,并且不支持动态刷新;每一个应用除了有一个全局配置文件后,还应该默认有一个专属的配置(默认可以不存在),支持动态刷新;如下图

配置的优化级别应该是:本地配置 < 全局共享配置 < 专属配置 不同的环境配置,应该使用空间进行隔离

实现案例

nacos配置的优先级

Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置。

A: 通过​​spring.cloud.nacos.config.shared-configs[n].data-id​​ 支持多个共享 Data Id 的配置B: 通过​​spring.cloud.nacos.config.extension-configs[n].data-id​​ 的方式支持多个扩展 Data Id 的配置C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置

当三种方式共同使用时,他们的一个优先级关系是:A < B < C

nacos配置的使用

以spring-cloud为例

基于nacos配置优先级,以及设计方案的最简原则,建议spring-cloud项目使用以下bootstrap.yml文件配置

server:  port: ${CONTAINER_PORT:8080} #所有类似${CONTAINER_PORT:8080}写法的 CONTAINER_PORT不能改动,默认值根据业务修改  servlet:    context-path: /   #工程访问路径业务自己定义# 的形式的属性文件存在,用于覆盖本地的默认值。

扩展

有些管理系统的配置的一些开关,可以结合nacos的配置实现,如下增加​​系统全局配置​​

spring:  application:    name: ${APP_NAME:talkweb-demo} #默认值一般修改为与工程名或子模块名相同  cloud:    ###nacos配置###    nacos:      server-addr: ${NACOS_URL:192.168.141.203:8848}      username: ${NACOS_USR:nacos-usr}      password: ${NACOS_PWD:nacos-pwd}      discovery:        namespace: ${NACOS_NAMESPACE:namespace-dev}        group: ${NACOS_GROUP:DEFAULT_GROUP}      config:        namespace: ${NACOS_NAMESPACE:namespace-dev}        file-extension: properties        extension-configs:          # 全局配置不支持动态刷新          - data-id: ${GLOBAL_COMM:global-comm.properties}            group: ${NACOS_GROUP:DEFAULT_GROUP}          # 系统全局配置支持动态刷新[该配置由系统默认创建,不能人为操作]          - data-id: ${SYS_GLOBAL_CONFIG:sys-global-config.properties}            group: ${NACOS_GROUP:DEFAULT_GROUP}            refresh: true

系统默认全局配置:sys-global-config.properties (手动设置data-id,支持动态刷新,业务系统自动生成,不能人为操作,主要用于管理后台配置的参数,eg:邮箱配置、短信配置、系统开关等等)

前端使用nacos配置

为了使一套代码能再不同的环境中,前端也需要使用配置中心,最好能与后端使用一套配置。 设计方案:前端工程(vue)在项目中使用公共的一个配置文件;部署时利用shell脚本,从nacos中获取配置后, 自动替换前端配置文件中的配置项。

以k8s部署为例

1.在docker编译时,将​​默认的配置文件​​​替换为​​带有占位符配置文件​​。(占位符,只是将具体值由nacos中key取代,eg: ${key})

FROM nginx:stableMAINTAINER Qiming Mei COPY dist/ /usr/share/nginx/html/COPY init.js /usr/share/nginx/html/static/js/config.jsCOPY entrypoint.sh /RUN chmod +x /entrypoint.sh#CMD ["/bin/bash","-c", "/entrypoint.sh" ]ENTRYPOINT ["/entrypoint.sh"]

2.利用启动entrypoint.sh配置文件中​​替换占位符​​

#!/bin/bash#配置文件路径,默认是static/js/config.js__config_file="/usr/share/nginx/html/static/js/config.js"if [ -n "$VUE_CONFIG_FILE_PATH" ]; then  __config_file="/usr/share/nginx/html/${VUE_CONFIG_FILE_PATH}"fi;# if [  -f "/init-env/env.conf" ]; thengrep -v "^#" /init-env/env.conf |grep -v ^$  |while read LINEdo  A=`echo $LINE |awk -F "=" '{print $1}'`  B=`echo $LINE |awk -F "$A=" '{print $2}'`  result=$(echo $A | grep "\.")  if [[ "$result" != "" ]]; then    echo "#$A=\"$B\"" >>  /init-env/env1.conf  elif [[ -z "$B" ]]; then    echo "空行,不需转换舍弃";  else    B=${B//\"/\\\"}; #处理特殊字符    echo "$A=\"${B/\`/\\\`}\"" >>  /init-env/env1.conf  fidonesed -i 's/\r//' /init-env/env1.conf#sed -e 's#\&#\\&#g' env.conf > env1.confeval "$(cat /init-env/env1.conf)"rm -f /init-env/env1.confelse    echo "/init-env/env.conf文件不存在,注意需要引入外部环境变量哦!";fi;#备份配置文件,存在就不备份,不存在就备份if [ ! -f  "${__config_file}.env" ]; then  cp ${__config_file} ${__config_file}.envfi# 变量替换方式直接会将${}的变量替换掉if [ -f "/init-env/env.conf" -o "$IS_ENV_REPLACE" = "true" ]; then  #替换${}中的环境变量eval "cat < ${__config_file}  #删除环境变量文件  rm -rf /init-env/env.conf  #赋予可读权限  chmod -R +r /usr/share/nginx/htmlfinginx -g 'daemon off;'

3.利用k8s的初始化容器下载nacos配置文件 ​​__XXX__​​为占位符,部署时会替换为具体的值

---apiVersion: apps/v1  kind: Deploymentmetadata:  name: __DOMAIN_NAME__  namespace: __NAME_SPACE__spec:  selector:    matchLabels:      app: __DOMAIN_NAME__  replicas: __REPLICAS_NUM__   template:     metadata:      labels:        app: __DOMAIN_NAME__    spec:      initContainers:      - name: init-env-sidecar        image: busybox:latest        command: [ "sh", "-c"]        args:        - set -ex;          CONFIG_FILE=${CONFIG_FILE:-"vue-comm.properties"};          SYS_GLOBAL_CONFIG=${SYS_GLOBAL_CONFIG:-"sys-global-config.properties"};          wget --post-data="username=${NACOS_USR}&password=${NACOS_PWD}" -S "${NACOS_URL}/nacos/v1/auth/users/login" -O login-token;          access_token=$(grep  -Eo '"accessToken":"([^"]*)"' login-token |awk -F \":\" '{print $2}');          access_token=${access_token/\"/};          rm -f /init-env/env.conf;          rm -f /init-env/env-sys.conf;          wget "${NACOS_URL}/nacos/v1/cs/configs?dataId=${CONFIG_FILE}&group=${NACOS_GROUP}&tenant=${NACOS_NAMESPACE}&accessToken=$access_token" -O  /init-env/env.conf;          wget "${NACOS_URL}/nacos/v1/cs/configs?dataId=${SYS_GLOBAL_CONFIG}&group=${NACOS_GROUP}&tenant=${NACOS_NAMESPACE}&accessToken=$access_token" -O  /init-env/env-sys.conf || return 0;          if [  $? -eq 0 -a -f "/init-env/env-sys.conf" ]; then            echo -e  "\n" >>  /init-env/env.conf;            cat /init-env/env-sys.conf >> /init-env/env.conf;          fi        env: #环境变量设置        - name: NACOS_NAMESPACE          value: __NACOS_NAMESPACE__        - name: NACOS_GROUP          value: __NACOS_GROUP__        - name: SYS_GLOBAL_CONFIG          value: __SYS_GLOBAL_CONFIG__        - name: CONFIG_FILE          value: __CONFIG_FILE__        - name: NACOS_URL          value: __NACOS_URL__        envFrom:        - secretRef:            name: __NACOS_AUTH__        volumeMounts:        - name: init-env          mountPath: /init-env/      containers:      - name: __DOMAIN_NAME__        image: __DOCKER_IMAGE__        imagePullPolicy: IfNotPresent #本地存在就不到远程拉取镜像        env: #环境变量设置        - name: TZ          value: Asia/Shanghai        - name: DOMAIN_NAME          value: __DOMAIN_NAME__.__NAME_SPACE__        resources: #资源限制          requests:            memory: "128Mi"            cpu: "100m" #最低需要 0.1个cpu          limits:            memory: "__LIMIT_MEMORY__Mi"            cpu: "1000m"        ports:        - containerPort: 80        readinessProbe: #就绪探针        #  httpGet:        #    path: /index.html        #    port: 80          tcpSocket:            port: 80          initialDelaySeconds: 30          periodSeconds: 15          timeoutSeconds: 5        livenessProbe: #健康检查        #  httpGet:        #    path: /index.html        #    port: 80          tcpSocket:            port: 80          initialDelaySeconds: 30          periodSeconds: 15          timeoutSeconds: 5        volumeMounts:        - name: time-config          mountPath: /etc/localtime          readOnly: true        - name: init-env          mountPath: /init-env/      imagePullSecrets:      - name: __DOCKER_REGISTRY_SECRET__      nodeSelector:        isDev: "true"      volumes:      - name: time-config        hostPath:          path: /etc/localtime      - name: init-env        emptyDir: {}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:持续集成CI/CD之CD的完整版最佳实践
下一篇:持续集成CI/CD之工具快速搭建
相关文章

 发表评论

暂时没有评论,来抢沙发吧~