K8s基于Reloader的ConfigMap/Secret热更新

背景

K8s中部署的工作负载使用ConfigMapSecret时,存在两种方式:

  • 环境变量 Env 方式挂载
  • 文件方式挂载

当更新ConfigMapSecret时,挂载到Pod中的数据存在两种情况:

  • Env 方式挂载的环境变量不会同步更新
  • 文件方式挂载的数据会同步更新(存在秒级延时)

大部分场景下,在更新了ConfigMapSecret中的信息后,都希望Pod内业务能读取到最新的值。通常都会手动去滚动更新一下Pod,重新读取环境变量或文件内容。当前社区已经有对应的开源工具Reloader实现了ConfigMap/Secret更新时自动触发Pod的滚动更新。

Reloader介绍

Reloader 通过watch ConfigMapSecret 中的变化,对 DeploymentDaemonSetStatefulSet 等负载的 Pod 进行滚动升级。

兼容性

Reloader 兼容的 K8s 版本为>=1.9。

常用配置

以下使用Deployment举例:

  • Deployment 中使用的所有 ConfigMap 和 Secret 变动都会触发 Pod 滚动更新
    在Deployment 的metadata.annotations中添加reloader.stakater.com/auto: "true"
    kind: Deployment
    metadata:
      annotations:
        reloader.stakater.com/auto: "true"
    spec:
      template:
    
  • Deployment 中的部分 ConfigMap 和 Secret 变动会触发 Pod 滚动更新
    在Deployment 的metadata.annotations中添加reloader.stakater.com/search: "true"
    kind: Deployment
    metadata:
      annotations:
        reloader.stakater.com/search: "true"
    spec:
      template:
    
    同时在需要触发 Pod 更新的 ConfigMap 或 Secret 中的metadata.annotations中添加reloader.stakater.com/match: "true"
    kind: ConfigMap
    metadata:
      annotations:
        reloader.stakater.com/match: "true"
    data:
      key: value
    
  • Deployment 中指定 ConfigMap 或 Secret 的变动触发 Pod 滚动更新
    在Deployment 的metadata.annotations中添加configmap.reloader.stakater.com/reload: "foo-configmap,bar-configmap,baz-configmap",指定这些 ConfigMap 才会触发 Pod 的更新。多个 ConfigMap 使用逗号分隔
    kind: Deployment
    metadata:
      annotations:
        configmap.reloader.stakater.com/reload: "foo-configmap,bar-configmap,baz-configmap"
    spec:
      template: 
        metadata:
    
    在Deployment 的metadata.annotations中添加secret.reloader.stakater.com/reload: "foo-secret,bar-secret,baz-secret",指定这些 Secret 才会触发 Pod 的更新。多个 Secret 使用逗号分隔
    kind: Deployment
    metadata:
      annotations:
        secret.reloader.stakater.com/reload: "foo-secret,bar-secret,baz-secret"
    spec:
      template: 
        metadata:
    

其他配置

  • 忽略 ConfigMap 或 Secret 变动(全局
    在 Reloader deployment的spec.template.spec.container.args中添加参数:

    参数 描述
    --resources-to-ignore=configMaps 忽略 configMaps 变动
    --resources-to-ignore=secrets 忽略 secrets 变动

    --resources-to-ignore参数只支持忽略一种资源,若要同时忽略 configMaps 和 secrets 的变动,则只需要把 Reloader 副本数降为0。

  • 忽略 Namespace 中的变动
    在 Reloader deployment的spec.template.spec.container.args中配置参数--namespaces-to-ignore={namespace}

  • 覆盖默认相关annotation

    参数 描述
    --auto-annotation 覆盖默认的annotation reloader.stakater.com/auto
    --auto-search-annotation 覆盖默认的annotation reloader.stakater.com/search
    --search-match-annotation 覆盖默认的annotation reloader.stakater.com/match
    --configmap-annotation 覆盖默认的annotation configmap.reloader.stakater.com/reload
    --secret-annotation 覆盖默认的annotation secret.reloader.stakater.com/reload

更多信息参考:https://github.com/stakater/Reloader

实战验证

测试环境准备

  • 创建namespace
    输入命令,创建一个namespace,名为ns1
kubectl create ns ns1
  • 安装reloader
    输入如下命令,安装reloader相关deployment。
$ kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml
  • 创建configmap
    使用kubectl apply -f cm.yaml命令创建configmap。cm.yaml文件内容如下:
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config-file
  namespace: ns1
  annotations:
#    reloader.stakater.com/match: "true"
data:
  info.yaml: |
    user=aliens
    age=22
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-config-env
  namespace: ns1
  annotations:
#    reloader.stakater.com/match: "true"
data:
  COUNTRY: china
  CITY: beijing
  • 创建deployment
    使用kubectl apply -f nginx-deploy.yaml命令创建configmap。nginx-deploy.yaml文件内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: ns1
  annotations:
#    configmap.reloader.stakater.com/reload: "test-config-file"
#    reloader.stakater.com/search: "true"
     reloader.stakater.com/auto: "true"
spec:
  selector: 
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        env:
          # Define the environment variable
          - name: COUNTRY
            valueFrom:
              configMapKeyRef:
                name: test-config-env
                key: COUNTRY
          - name: CITY
            valueFrom:
              configMapKeyRef:
                name: test-config-env
                key: CITY
        volumeMounts:
        - name: foo
          mountPath: "/etc/foo"
          readOnly: true
      volumes:
      - name: foo
        configMap:
          name: test-config-file

Reloader功能验证

  1. 更新configmap(以文件方式挂载)
    使用命令kubectl -nns1 edit cm test-config-file编辑configmap,设置user的值为ted。查看pod已经滚动更新。
➜ kubectl edit cm -nns1 test-config-file
configmap/test-config-file edited
➜ kubectl get pods -nns1
NAME                     READY   STATUS              RESTARTS   AGE
nginx-5dff48f5dd-m528h   0/1     ContainerCreating   0          6s
nginx-6f455f8cd5-9h7pp   1/1     Running             0          34m

查看新启动pod中configmap所挂载的文件内容,发现user的值已经变为ted

➜ kubectl exec -it nginx-5dff48f5dd-m528h  -nns1 -- cat /etc/foo/info.yaml
user=ted
age=22
  1. 更新configmap(以环境变量方式注入)
    使用命令kubectl -nns1edit cm test-config-env编辑configmap,设置CITY的值为shenzhen。查看pod已经滚动更新。
➜ kubectl edit cm -nns1 test-config-env
configmap/test-config-env edited
➜ kubectl get pods -nns1
NAME                     READY   STATUS              RESTARTS   AGE
nginx-5b4cb86669-9cv6k   0/1     ContainerCreating   0          6s
nginx-5dff48f5dd-m528h   1/1     Running             0          9m35s

查看新启动pod中configmap所注入的环境变量,发现CITY的值已经变为shenzhen

➜ kubectl exec -it nginx-5b4cb86669-9cv6k -nns1 -- env|grep CITY
CITY=shenzhen

注意事项

  • Reloader自动触发滚动更新,可能会导致业务中断。使用该功能时需要评估pod滚动更新对业务带来的影响。
  • reloader.stakater.com/auto的优先级高于reloader.stakater.com/search

你可能感兴趣的:(K8s基于Reloader的ConfigMap/Secret热更新)