当它们的configmap被更改/更新时,我如何自动重新启动Kubernetes pod和与部署相关的pod ?


我知道有关于在配置映射发生变化时自动重启pod的讨论,但据我所知,这在Kubernetes 1.2中还没有。

因此(我认为)我想做的是“滚动重新启动”与使用配置映射的pod相关联的部署资源。在Kubernetes中,在不改变实际模板的情况下强制滚动重启部署是否可能?如果可能的话,如何实现?这是目前最好的方式还是有更好的选择?


当前回答

我发现最好的方法是运行Reloader

它允许您定义要监视的配置映射或秘密,当它们更新时,将执行部署的滚动更新。这里有一个例子:

你有一个部署foo和一个名为foo- ConfigMap的ConfigMap。您希望在每次更改configmap时滚动部署的pod。你需要运行Reloader:

kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml

然后在部署中指定这个注释:

kind: Deployment
metadata:
  annotations:
    configmap.reloader.stakater.com/reload: "foo-configmap"
  name: foo
...

其他回答

在配置映射更新时向pod发送信号是一个正在工作的功能(https://github.com/kubernetes/kubernetes/issues/22368)。

你总是可以写一个自定义的pid1来通知confimap已经改变并重新启动你的应用程序。

您还可以例如:在两个容器中挂载相同的配置映射,在第二个容器中暴露一个http健康检查,如果配置映射内容的哈希值发生变化,该检查将失败,并将其作为第一个容器的活动探测(因为pod中的容器共享相同的网络名称空间)。当探测失败时,kubelet将为您重新启动第一个容器。

当然,如果您不关心pod在哪些节点上,您可以简单地删除它们,复制控制器将为您“重新启动”它们。

考虑使用kustomize(或kubectl apply -k),然后利用它强大的configMapGenerator特性。例如,来自:https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/configmapgenerator/

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# Just one example of many...
- name: my-app-config
  literals:
  - JAVA_HOME=/opt/java/jdk
  - JAVA_TOOL_OPTIONS=-agentlib:hprof

  # Explanation below...
  - SECRETS_VERSION=1

然后在部署中引用my-app-config即可。当使用kustomize构建时,它会自动查找并更新my-app-config的引用,并使用更新的后缀,例如my-app-config-f7mm6mhf59。

额外的好处是,更新秘密:我还使用此技术强制重新加载秘密(因为它们以同样的方式受到影响)。虽然我个人完全单独管理我的秘密(使用Mozilla sops),但您可以将配置映射与您的秘密捆绑在一起,例如在您的部署中:

# ...
spec:
  template:
    spec:
      containers:
        - name: my-app
          image: my-app:tag
          envFrom:
            # For any NON-secret environment variables. Name is automatically updated by Kustomize
            - configMapRef:
                name: my-app-config

            # Defined separately OUTSIDE of Kustomize. Just modify SECRETS_VERSION=[number] in the my-app-config ConfigMap
            # to trigger an update in both the config as well as the secrets (since the pod will get restarted).
            - secretRef:
                name: my-app-secrets

然后,像我上面所做的那样,在ConfigMap中添加一个像SECRETS_VERSION这样的变量。然后,每次更改my-app-secrets时,只需增加SECRETS_VERSION的值,这除了触发kustomize'd ConfigMap名称的更改外,没有其他用途,这也应该导致重新启动pod。然后就变成:

我发现最好的方法是运行Reloader

它允许您定义要监视的配置映射或秘密,当它们更新时,将执行部署的滚动更新。这里有一个例子:

你有一个部署foo和一个名为foo- ConfigMap的ConfigMap。您希望在每次更改configmap时滚动部署的pod。你需要运行Reloader:

kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml

然后在部署中指定这个注释:

kind: Deployment
metadata:
  annotations:
    configmap.reloader.stakater.com/reload: "foo-configmap"
  name: foo
...

目前这个问题的最佳解决方案(在兄弟回答的https://github.com/kubernetes/kubernetes/issues/22368链接中有深入引用)是使用部署,并将configmap视为不可变的。

当您想要更改配置时,请创建一个带有您想要进行更改的新ConfigMap,并将部署指向新的ConfigMap。如果新的配置被破坏,部署将拒绝缩小您的工作ReplicaSet。如果新的配置有效,那么旧的ReplicaSet将被缩放为0副本并删除,新的pod将使用新的配置启动。

虽然没有编辑ConfigMap那么快,但是更安全。

另一种方法是将其插入部署的命令部分:

...
command: [ "echo", "
  option = value\n
  other_option = value\n
" ]
...

或者,为了使它更像configmap,使用一个额外的部署,它只会在命令节中托管该配置,并在其上执行kubectl create,同时在其名称中添加一个唯一的“版本”(比如计算内容的哈希值),并修改所有使用该配置的部署:

...
command: [ "/usr/sbin/kubectl-apply-config.sh", "
  option = value\n
  other_option = value\n
" ]
...

我可能会发布kubectl-apply-config.sh,如果它最终能够工作的话。

(不要那样做;看起来太糟糕了)