configmap 多个pod挂载 configmap 挂载目录_json

写在前面

为了不违反广告法,我竭尽全力,不过“最佳实践”确是标题党无疑,如果硬要说的话 只能是个人最佳实践。

问题引出

可能很多新手都会遇到同样的问题:我要我的Asp.net Core 应用传统方式直接部署(host),docker部署(docker-compose),kubernetes(以下称k8s)下部署,都用统一的方式读取配置,怎么实现呢?。

大家知道,我们默认平时配置文件以appsettings.jsonappsettings.{EnvironmentName}.json 形式存在,这样在host方式下面没有问题,但在docker下,如果直接把配置打包到镜像,那每次改一下下配置就需要重新打包,那成本太大了。另外在k8s下面又有Secret、ConfigMap等多种方式管理配置,如何把多种配置存储和读取,有机结合、同一份代码统一管理使用,是我们今天的主题。

下面我用一个Api网关Ocelot作为示例(demo),讲讲我处理的方式,希望能给大家带来一定启发。

一、先把配置文件改成Yaml格式

注:

其实不改为yml也可以的!!

主要考虑到后面在docker、k8s等里面,更好管理,比如yaml的注释和json的注释语法不一致等等问题;

比如我原来的appsettings.json长这样:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "AddAdministration": {
    "Path": "/administration",
    "IdentityServer": {
      "Authority": "http://172.16.3.117:5100",
      "ApiName": "ocelot",
      "RequireHttpsMetadata": false,
      "ApiSecret": "secret"
    }
  }
}

改成 appsettings.yml

Logging:
  LogLevel:
    Default: Information
    Microsoft: Warning
    Microsoft.Hosting.Lifetime: Information
AllowedHosts: '*'
AddAdministration:
  Path: /administration
  IdentityServer:
    Authority: 'http://172.16.3.117:5100'
    ApiName: ocelot
    RequireHttpsMetadata: false
    ApiSecret: secret

是不是看起来简单清晰了很多,其实我现在越来越喜欢用yml了

既然配置源的格式变了,那读取配置的方法也肯定变了,起码config.AddJsonFile(“xx.json”) 要改为 config.AddYamlFile(“xx.yml”)

新增引用的扩展:NetEscapades.Configuration.Yaml

加载配置文件改写为:

.AddYamlFile("appsettings.yml", optional: false, reloadOnChange: true)
.AddYamlFile($"appsettings.{env.EnvironmentName}.yml", optional: true, reloadOnChange: true)

二、Docker使用

“但在docker下,如果直接把配置打包到镜像,那每次改一下下配置就需要重新打包,那成本太大了”

我前面提出了这个问题,如想不重新打包,Volume(挂载)就好了。

把你的配置文件放到/home/heidemo/config目录后,比如我们什么的示例配置文件:appsettings.yml

docker run --rm=true -v /home/heidemo/config:/config   gebiwangshushu/hei-ocelot-apigateway:1.0

这样就可以随性更新/home/heidemo/config下的配置信息而不需要每次都重新build镜像了,这样是支持热更新的,当然如果你修改的那个配置是需要重启程序才可以加载的,那还是要用docker-compose 重启下对应服务的;

三、docker-compose使用

我们知道 Docker是 官方编排(Orchestration)项目之一,如果我们在Docker环境下挂载配置的话,那在docker-compose下面的配置也是挂载的,我们来看下我们掐头去尾后的 docker-compose.yml:

version: '3.4'

services:
  hei.ocelot.apigateway:
    ...

    volumes:
      - /home/heidemo/config:/app/config

    ...

没错,docker-compose 额挂载就这么定义,这样可以实现跟Docker一样的挂载效果;

大家可以用以上配置 clone我的demo,然后 docker-compose up一下,看看效果;

四、k8s使用

前面的docker、docker-compose 的方式还是非常容易理解的,就是挂载;那我们在k8s下面运行的时候,它的容器实例是动态的运行到集群的各台机器上的,那如果我们我们只用文件挂载很明显就不满足要求了,我们来看看怎么实现。

先准备一个configMap,hei-ocelot-config.yml

apiVersion: v1
kind: ConfigMap
metadata:
  name: hei-ocelot-apigateway
  namespace: dotnetcore
data:
  appsettings.yml: |
    Logging:
      LogLevel:
        Default: Information
        Microsoft: Warning
        Microsoft.Hosting.Lifetime: Information
    AllowedHosts: '*'
    AddAdministration:
      Path: /administration
      IdentityServer:
         Authority: 'http://172.16.1.30:31100' #这里的授权中心可以配置你自己的
        ApiName: ocelot
        RequireHttpsMetadata: false
        ApiSecret: secret

完整请看这里

大家可以看到,我们的data节点是跟我们程序里面的appsettings.json一样一样的,这也是我们比较喜欢不再用json的原因。

创建configMap:

kubectl apply -f hei-ocelot-config.yml

查看configMap:

kubectl describe configmaps hei-ocelot-apigateway -n dotnetcore

configmap 多个pod挂载 configmap 挂载目录_json_02

使用configMap:

这里是使用示例,在我的demo根目录下面完整配置deploy.yml 是可以直接部署的。

apiVersion: apps/v1
kind: Deployment
metadata:
 name: hei-ocelot-apigateway
 namespace: dotnetcore
spec:
 replicas: 1
 selector:
  matchLabels:
   app: hei-ocelot-apigateway
 template:
  metadata:
   labels:
    app: hei-ocelot-apigateway
  spec:
   containers:
    - name: hei-ocelot-apigateway
      image: gebiwangshushu/hei-ocelot-apigateway:1.1
      ports:
       - containerPort: 80
      volumeMounts:
       - name: hei-ocelot-apigateway
         mountPath: "/app/config"
         readOnly: true
   volumes:
    - name: hei-ocelot-apigateway
      configMap:
       name: hei-ocelot-apigateway

可以看到我们在k8s下面也是用volumes的方式使用我们的configMap的,其中挂载目录volumeMounts:mountPath是”/app/config”,我们进入运行中pod看下配置:

kubectl exec -it hei-ocelot-apigateway-795495f7c8-vpmhb sh -n dotnetcore

cd /app/config

我们可以看到我们的pod里面的/app/config ,确确实实有我们要的配置;

configmap 多个pod挂载 configmap 挂载目录_docker_03

这里因为我们是volumes  的方式的,大家可以试着改下上面的configMap— hei-ocelot-config.yml 再重新apply 一下,会看到这里的配置是几乎是即时更新的(有一点点延迟);

PS:有一个问题有些在startup使用的配置,即时更新了也需要重启下应用,这个我暂时还没想到什么办法好办法,各位老哥有什么思路的可以直接甩我一脸~

总结

其实写完我觉得也有点怪怪,说新手引导吧,不够保姆式、说经验分享,不够精简,下次我定好好想,认真写好点;

然后我的主题,其实思考过同样问题的读者,全文就一句:volumes挂载配置做到各种环境下的配置统一;

最后,我提出了一个问题:On K8s的时候, 程序启动使用的配置,如何在配置文件更新的情况后重启程序应用新配置(或者叫热加载配置?当然这里不是指配置文件的reloadOnChange=true);

本文示例源码

github:https://github.com/gebiWangshushu/Hei.Ocelot.ApiGateway