记一次K8s-ConfigMap热更新探索实录

时间:2024-11-21 11:34:34

一、前言

在k8s中,ConfigMap这一概念相信很多小伙伴都知道吧?它是Kubernetes中一种机制,很多应用在其初始化或者运行期间要依赖一些配置信息,可让你将配置数据注入到应用的Pod内部,允许你将配置清单与镜像内容,以保持容器化的应用程序的可移植性。前几天在某一公众号看到关于网友留言提出疑问:应用程序配置如环境变量或者以ConfigMap的方式可以不重建实现动态更新吗?,先不说结论,那么我们就这个问题进行实验

二、实施流程

我们可以将配置文件注入到Configmap中,而ConfigMap可以基于环境变量以及数据卷挂载的形式注入到Pod资源中。

2.1、创建ConfigMap

基于YAML创建一个ConfigMap来存储Nginx静态配置,先定义index.html页面内容

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: mdt-demo
  name: indexhtml
  
data:
  index.html: |
    <html>
    <body>
        <h1>Welcome to 宇轩辞白技术博客!https://blog.51cto.com/u_11880730</h1>
    </body>
    </html>

记一次K8s-ConfigMap热更新探索实录_ConfigMap

2.2、创建Nginx Deployment

创建Nginx 资源,将ConfigMap挂载为数据卷

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: mdt-demo
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.cn-beijing.aliyuncs.com/devops-op/nginx:stable-alpine
        ports:
        - containerPort: 80
        volumeMounts:	#以数据卷存储的方式进行挂载,指定挂载卷组名称
          - name: config-volume	#与configmap定义的数据卷名称一致
            mountPath: /usr/share/nginx/html  #定义数据卷挂载的容器目录位置
      volumes:
        - name: config-volume  #定义configmap 的数据卷名称
          configMap:
            name: indexhtml  #指定前面定义好的configmap名称

2.3、创建Service

创建Nginx service资源,定义访问端口,便于后续验证测试

apiVersion: v1
kind: Service
metadata:
  namespace: mdt-demo
  name: my-service
spec:
  selector:
    app: nginx
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80 

三、验证

3.1、ConfigMap是否热更新

尝试更新ConfigMap内容,验证当对其内容进行变更是否会同步至Pod所挂载的路径资源文件中

记一次K8s-ConfigMap热更新探索实录_ConfigMap_02

将configmap里面的idnex.html内容修改如下:

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: mdt-demo
  name: indexhtml
  
data:
  index.html: |
    <html>
    <body>
        <h1>Welcome to 宇轩辞白技术博客!https://blog.51cto.com/u_11880730</h1>
        <h1>Welcome to 宇轩辞白技术博客!https://blog.51cto.com/u_11880730</h1>
    </body>
    </html>

此时,等待一会再次使用curl,会看到已经更新

记一次K8s-ConfigMap热更新探索实录_ConfigMap_03

3.2、验证subPath是否支持热更新

我们在验证一下引用"subPath"机制指定子路径验证一下是否会热更新

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: mdt-demo
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: harbor.51trust.net/zyyl/nginx:stable-alpine
        ports:
        - containerPort: 80
        volumeMounts:	#这里制定了两个挂载路径,分别为引用了subPath和没有引用subPath
          - name: config-volume
            mountPath: /usr/share/nginx/html/index.html
            subPath: index.html	
          - name: config-volume
            mountPath: /tmp/
      volumes:
        - name: config-volume
          configMap:
            name: indexhtml 

关于subpath知识点拓展

在deployment资源定义中,subPath和mountPath有什么区别?

subPath用于指定configmap特定的子路径挂载,可以选择性的将ConfigMap中特定的子文件路径进行挂载指定,而如果不加subPath,会直接将ConfigMap中的子路径文件全部挂载到容器中

记一次K8s-ConfigMap热更新探索实录_ConfigMap_04

有人可能会说,subpath不就是单独指定configmap子路径文件嘛,我不引用subPath,直接只用mountpath后面跟上绝对路径不行吗?

   volumeMounts:
          - name: config-volume
            mountPath: /usr/share/nginx/html/index.html
      volumes:
        - name: config-volume
          configMap:
            name: indexhtml

答案是肯定不行的,这样会报错

记一次K8s-ConfigMap热更新探索实录_ConfigMap_05

随后更新index.html内容,看看容器中所挂载的目录文件是否更新,为了更加直观,我们可以直接切换到Pod里面看

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: mdt-demo
  name: indexhtml
  
data:
  index.html: |
    <html>
    <body>
        <h1>Welcome to 宇轩辞白技术博客 非常棒!https://blog.51cto.com/u_11880730</h1>
    </body>
    </html>

记一次K8s-ConfigMap热更新探索实录_ConfigMap_06

可以发现,ConfigMap虽说均已数据卷形式挂载,但是"Volume subPath"所挂载的文件并不支持热更新,还是之前旧版本内容

官方参考链接:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

记一次K8s-ConfigMap热更新探索实录_ConfigMap_07

如想使其生效,只能重建Pod即可完成ConfigMap更新

3.3、验证env是否支持热更新

cat  nginx-env-cm.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: mdt-demo
data:
  SPECIAL_LEVEL: very
  SPECIAL_TYPE: charm

记一次K8s-ConfigMap热更新探索实录_ConfigMap_08

在已有的Deployment资源中引用以环境变量(ENV)的方式挂载ConfigMap

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: mdt-demo
  name: my-nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: harbor.51trust.net/zyyl/nginx:stable-alpine
        env:
        - name: SPECIAL_LEVEL_KEY #定义最终环境变量名称
          valueFrom:
            configMapKeyRef:
              name: special-config	#指定configmap名称
              key: SPECIAL_LEVEL	#指定configmap中的变量名称
        - name: SPECIAL_TYPE_KEY  ##定义最终环境变量名称
          valueFrom:
            configMapKeyRef:
              name: special-config  #指定configmap名称
              key: SPECIAL_TYPE  #指定configMap中的变量名称
        ports:
        - containerPort: 80
        volumeMounts:
          - name: config-volume
            mountPath: /usr/share/nginx/html/index.html
            subPath: index.html
          - name: config-volume
            mountPath: /tmp/
      volumes:
        - name: config-volume
          configMap:
            name: indexhtml 

记一次K8s-ConfigMap热更新探索实录_ConfigMap_09

可以发现环境变量已在容器中生效,于是乎尝试修改configmap中的值,看看是否热更新

#vim  nginx-env-cm.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: mdt-demo
data:
  SPECIAL_LEVEL: very-new
  SPECIAL_TYPE: charm-new

记一次K8s-ConfigMap热更新探索实录_ConfigMap_10

可以发现,以环境变量挂载的ConfigMap不支持热更,需将Pod重载才能完成生效

记一次K8s-ConfigMap热更新探索实录_ConfigMap_11

四、总结

环境变量无法动态更新,ConfigMap 通过挂载的方式可以动态更新,但挂载时不能使用 subPath,ConfigMap/Secret 作为 volume 挂载在 Pod 中,如果 ConfigMap 的值发生变化,最大的等待时间就是 kubelet 的同步周期(默认1分钟),但是作为环境变量的 env 和 volume subPath 不支持热更新,环境变量在 Pod 启动的时候就已经固定了。