更改/更新配置图时,如何自动重启 Kubernetes pod 和与部署关联的 pod?
我知道有人谈论过当配置映射发生变化时自动重启 Pod 的能力,但据我所知,这在 Kubernetes 1.2 中尚不可用。
所以(我认为)我想做的是与使用配置映射的 pod 关联的部署资源的“滚动重启”。是否有可能,如果可以,如何在不更改实际模板中的任何内容的情况下强制滚动重启 Kubernetes 中的部署?这是目前最好的方法还是有更好的选择?
更改/更新配置图时,如何自动重启 Kubernetes pod 和与部署关联的 pod?
我知道有人谈论过当配置映射发生变化时自动重启 Pod 的能力,但据我所知,这在 Kubernetes 1.2 中尚不可用。
所以(我认为)我想做的是与使用配置映射的 pod 关联的部署资源的“滚动重启”。是否有可能,如果可以,如何在不更改实际模板中的任何内容的情况下强制滚动重启 Kubernetes 中的部署?这是目前最好的方法还是有更好的选择?
当前解决此问题的最佳解决方案(在兄弟答案中链接的https://github.com/kubernetes/kubernetes/issues/22368中深入引用)是使用部署,并认为您的 ConfigMap 是不可变的。
当您想要更改配置时,请使用您想要进行的更改创建一个新的 ConfigMap,并将您的部署指向新的 ConfigMap。如果新配置被破坏,Deployment 将拒绝缩减您的工作 ReplicaSet。如果新配置有效,那么您的旧 ReplicaSet 将被缩放为 0 个副本并被删除,并且新的 Pod 将使用新配置启动。
不如就地编辑 ConfigMap 快,但更安全。
在配置地图更新时发出 pod 信号是一项正在开发中的功能 ( https://github.com/kubernetes/kubernetes/issues/22368 )。
您始终可以编写一个自定义 pid1 来通知 confimap 已更改并重新启动您的应用程序。
您还可以例如:在 2 个容器中挂载相同的配置映射,在第二个容器中公开一个 http 健康检查,如果配置映射内容的哈希发生变化,该检查将失败,并将其作为第一个容器的活跃度探测(因为容器中的pod 共享相同的网络命名空间)。当探测失败时,kubelet 将为您重新启动您的第一个容器。
当然,如果您不关心 pod 在哪些节点上,您可以简单地删除它们,复制控制器将为您“重新启动”它们。
我发现最好的方法是运行Reloader
它允许您定义 configmaps 或要观察的秘密,当它们更新时,将执行您的部署的滚动更新。这是一个例子:
您有一个部署foo
和一个名为foo-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
...
通常,配置映射或机密作为配置文件注入容器中。根据应用程序的不同,如果使用后续helm upgrade
的 .
该sha256sum
函数可以与该include
函数一起使用,以确保在另一个规范发生更改时更新部署模板部分:
kind: Deployment
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
[...]
就我而言,由于某些原因,$.Template.BasePath
它不起作用,但$.Chart.Name
确实:
spec:
replicas: 1
template:
metadata:
labels:
app: admin-app
annotations:
checksum/config: {{ include (print $.Chart.Name "/templates/" $.Chart.Name "-configmap.yaml") . | sha256sum }}
您可以更新与您的部署无关的元数据注释。它将触发滚动更新
例如:
spec:
template:
metadata:
annotations:
configmap-version: 1
在部署位于子图表中并且控制它的值位于父图表的值文件中时遇到此问题。这是我们用来触发重启的:
spec:
template:
metadata:
annotations:
checksum/config: {{ tpl (toYaml .Values) . | sha256sum }}
显然,这将在任何值更改时触发重启,但它适用于我们的情况。仅当子图表本身中的 config.yaml 发生更改时,子图表中最初的内容才会起作用:
checksum/config: {{ include (print $.Template.BasePath "/config.yaml") . | sha256sum }}
如果k8>1.15;然后,作为 CI/CD 的一部分,重新启动推出对我来说效果最好,其中应用程序配置路径与卷挂载挂钩。部署清单 YML 中的重新加载器插件或设置restartPolicy: Always
对我不起作用。无需更改应用程序代码,适用于静态资产和微服务。
kubectl rollout restart deployment/<deploymentName> -n <namespace>
我也为这个问题纠结了一段时间,并希望以一种优雅但快速的方式解决这个问题。
这是我的 20 美分:
如果您要更新标签,则使用此处提到的标签的答案将不起作用。但如果你总是添加标签,它会起作用。更多细节在这里。
根据我的说法,这里提到的答案是快速执行此操作的最优雅的方法,但存在处理删除的问题。我正在补充这个答案:
我在其中一个 Kubernetes Operator 中执行此操作,其中在一个协调循环中只执行一个任务。
v2
.cm-v2
创建具有标签的ConfigMap :如果它不存在并返回version: v2
。product: prime
如果它存在,请往下看。product: prime
但没有标签的部署version: v2
,如果找到这样的部署,删除它们并返回。否则请往下走。product: prime
但没有version: v2
ELSE GO BELOW的ConfigMap。deployment-v2
带有标签的部署,product: prime
并将version: v2
配置映射附加为cm-v2
返回,否则什么都不做。而已!它看起来很长,但这可能是最快的实现,并且原则上将基础设施视为牛(不变性)。
此外,当您的 Kubernetes 部署具有重新创建更新策略时,上述解决方案也有效。对于其他场景,逻辑可能需要很少的调整。
考虑使用kustomize
(or 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
例如
奖励,更新秘密:我也使用这种技术来强制重新加载秘密(因为它们以同样的方式受到影响)。虽然我个人完全分开管理我的秘密(使用Mozillasops
),但您可以将配置映射与您的秘密捆绑在一起,例如在您的部署中:
# ...
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
SECRETS_VERSION
然后,只需像我在上面所做的那样将一个变量添加到您的 ConfigMap 中。然后,每次更改my-app-secrets
时,只需增加 的值SECRETS_VERSION
,这除了触发kustomize
'd ConfigMap 名称的更改之外没有其他用途,这也应该导致您的 pod 重新启动。那么它就变成了:
将不可变属性添加到配置映射完全避免了这个问题。使用配置散列有助于无缝滚动更新,但无助于回滚。您可以查看这个开源项目 - 'Configurator' - https://github.com/gopaddle-io/configurator.git。'Configurator ' 使用自定义资源通过以下方式工作:
Configurator 将部署生命周期与 configMap 联系起来。更新配置映射时,会为该配置映射创建一个新版本。附加到 configMap 的所有部署都会获得滚动更新,其中包含与之相关的最新 configMap 版本。
当您将部署回滚到旧版本时,它会反弹到执行滚动更新之前的 configMap 版本。
通过这种方式,您可以维护配置映射的版本,并促进与配置映射一起滚动和回滚到您的部署。
另一种方法是将其粘贴到部署的命令部分:
...
command: [ "echo", "
option = value\n
other_option = value\n
" ]
...
或者,要使其更像 ConfigMap,请使用额外的部署,它将仅在该command
部分中托管该配置并在其上执行kubectl create
,同时在其名称中添加一个唯一的“版本”(例如计算内容的哈希)并修改所有使用该配置的部署:
...
command: [ "/usr/sbin/kubectl-apply-config.sh", "
option = value\n
other_option = value\n
" ]
...
kubectl-apply-config.sh
如果它最终工作,我可能会发布。
(不要那样做;它看起来太糟糕了)