如何安排Pod的重启

73

根据时间自动重启Pod是否可能?

例如,我希望每天早上8点重启我的集群的Pod。

7个回答

177

使用 cronjob,但不是用来运行您的 pod,而是安排一个 Kubernetes API 命令来每天重启部署 (kubectl rollout restart)。这样,如果出现问题,旧的 pod 将不会关闭或删除。

Rollouts 创建新的 ReplicaSets,并等待它们启动后,才会杀死旧的 pod 并重新路由流量。服务将继续不间断地运行。

您必须设置 RBAC,以便从集群内部运行的 Kubernetes 客户端具有执行对 Kubernetes API 所需调用的权限。

---
# Service account the client will use to reset the deployment,
# by default the pods running inside the cluster can do no such things.
kind: ServiceAccount
apiVersion: v1
metadata:
  name: deployment-restart
  namespace: <YOUR NAMESPACE>
---
# allow getting status and patching only the one deployment you want
# to restart
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-restart
  namespace: <YOUR NAMESPACE>
rules:
  - apiGroups: ["apps", "extensions"]
    resources: ["deployments"]
    resourceNames: ["<YOUR DEPLOYMENT NAME>"]
    verbs: ["get", "patch", "list", "watch"] # "list" and "watch" are only needed
                                             # if you want to use `rollout status`
---
# bind the role to the service account
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deployment-restart
  namespace: <YOUR NAMESPACE>
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deployment-restart
subjects:
  - kind: ServiceAccount
    name: deployment-restart
    namespace: <YOUR NAMESPACE>

并且cron作业规范本身:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: deployment-restart
  namespace: <YOUR NAMESPACE>
spec:
  concurrencyPolicy: Forbid
  schedule: '0 8 * * *' # cron spec of time, here, 8 o'clock
  jobTemplate:
    spec:
      backoffLimit: 2 # this has very low chance of failing, as all this does
                      # is prompt kubernetes to schedule new replica set for
                      # the deployment
      activeDeadlineSeconds: 600 # timeout, makes most sense with 
                                 # "waiting for rollout" variant specified below
      template:
        spec:
          serviceAccountName: deployment-restart # name of the service
                                                 # account configured above
          restartPolicy: Never
          containers:
            - name: kubectl
              image: bitnami/kubectl # probably any kubectl image will do,
                                     # optionaly specify version, but this
                                     # should not be necessary, as long the
                                     # version of kubectl is new enough to
                                     # have `rollout restart`
              command:
                - 'kubectl'
                - 'rollout'
                - 'restart'
                - 'deployment/<YOUR DEPLOYMENT NAME>'

如果您希望该cronjob等待部署完成后再执行,可以将cronjob命令更改为:

command:
 - bash
 - -c
 - >-
   kubectl rollout restart deployment/<YOUR DEPLOYMENT NAME> &&
   kubectl rollout status deployment/<YOUR DEPLOYMENT NAME>

11
虽然这并没有严格回答提出的问题,但我认为这是定期重启群集中容器的最佳选择! - cyberconte
8
这个答案挽救了我们的生命,并在调查和修复根本原因时帮助我们克服了巨大的事件和财务损失。谢谢你! - Ahmed Ayoub
4
注意:所有 CronJob 的计划时间都基于 kube-controller-manager 的时区。如果您的控制平面在 Pod 或裸容器中运行 kube-controller-manager,则为 kube-controller-manager 容器设置的时区决定了 cron job 控制器使用的时区。 - Ricardo Cardona Ramirez
7
一个对立观点:不要使用具有自我修改k8s集群能力的资源进行托管,将这些任务隔离在一个独立的cronjob工具中,该工具应该是由管理您的集群的服务提供商提供的,例如GKE的https://cloud.google.com/scheduler,或者在AWS的情况下,在其他ECS集群中运行高度敏感的作业的第二个ECS集群。 - yurisich
3
更新:在 CronJob 中将 batch/v1beta1 更改为 batch/v1 以使其正常工作。 - chill appreciator
显示剩余4条评论

40

对于具有重启策略为Always的Pod(这是不应该由cron job处理的 - 请参阅创建cron job规范Pod模板),另一种快速而粗糙的选项是一个只测试时间并按计划重新启动pod的livenessProbe。

例如:启动后等待1小时,然后每分钟检查一次,如果时间是3点(上午),则失败并重新启动,否则通过。

livenessProbe:
  exec:
    command:
    - exit $(test $(date +%H) -eq 3 && echo 1 || echo 0)
  failureThreshold: 1
  initialDelaySeconds: 3600
  periodSeconds: 60

时间粒度取决于你返回日期和测试的方式 ;)



当然,如果您已经将活动探针用作实际 活动探针,则此方法不起作用 ¯ \ _(ツ)_/¯


3
这种方法会导致在指定的时间段内不断重新启动,就像整整一分钟。精确到秒可能会有遗漏的风险。也许检查运行时间是否超过24小时会更简单和合适? - Philluminati
3
这种方法通过在启动后等待一小时才重新开始探测(initialDelaySeconds),避免了重启风暴,所以在3:00到3:01之间它会失败,然后一旦它重新启动,就会等待一小时再次开始检查时间(对于一个相当大的vert.x应用程序,启动时间约为25秒,第一次探测开始在4:01到4:02之间)。 - Ryan Lowe
11
上述的活跃性命令不能用这种方式写在一行上。但是,您可以将“-bash”、“-c”和“-exit $(test $(date +%H) -eq 3 && echo 1 || echo 0)”分别放在三行中使用。 - Masood Khaari
2
这种方法存在一些停机时间。在存活探针失败并且容器重新启动之前,Pod 无法接受流量。如果所有容器恰好同时重新启动,则会出现服务中断。 - OhJeez
2
@OhJeez,这绝对是真的。livenessProbe会导致所有从该部署中的pod同时重新启动,因此您下面描述的cronjob应该是生产环境的首选答案 :) - Ryan Lowe
显示剩余8条评论

13

我借鉴了@Ryan Lowe的想法,但做了一些修改。它将重新启动24小时以上的Pod。

      livenessProbe:
        exec:
          command:
             - bin/sh
            - -c
            - "end=$(date -u +%s);start=$(stat -c %Z /proc/1 | awk '{print int($1)}'); test $(($end-$start)) -lt 86400"

3
/proc/1 不是一个可靠的信息源,时间戳可能与实际情况非常不同。当可用并且进程ID已知(在我的情况下为“1”)时,我会使用 ps -p 1 -o etimes --no-headers - kivagant

6
这方面有一个专门的资源:CronJob。下面是一个例子:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: your-cron
spec:
  schedule: "*/20 8-19 * * 1-5"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            app: your-periodic-batch-job
        spec:
          containers:
          - name: my-image
            image: your-image
            imagePullPolicy: IfNotPresent
          restartPolicy: OnFailure

如果您想在启动新pod时替换旧pod,请将spec.concurrencyPolicy更改为Replace。使用Forbid,如果旧的pod仍在运行,则新的pod创建将被跳过。


7
我不太清楚这是如何运作的。它是否部署了一个新的 Pod,因此 Kubernetes 会自动删除其中一个旧的 Pod? - span
这句话的含义是your-image命令会触发Pod重新启动。 - Stuart Harland
@StuartHarland 你确定吗?我的理解是your-image是你的服务,并且它会一直运行,直到下一次cron作业启动时,Replace停止它并启动一个新实例。当然,你提出的方式也可以工作,但似乎过于复杂了。 - tgdavies

2
根据cronjob-in-kubernetes-to-restart-delete-the-pod-in-a-deployment,您可以创建一个kind: CronJob,其中包含一个具有containersjobTemplate。因此,您的CronJob将启动这些容器,并且activeDeadlineSeconds为一天(直到重启)。根据您的示例,然后将是schedule: 0 8 * * ?,表示上午8点。

2
livenessProbe:
  exec:
    command:
    - bash
    - -c
    - "exit 1"
  failureThreshold: 1
  periodSeconds: 86400

其中86400是所需的时间段,以秒为单位(在此示例中每天重新启动1次)


1
我们通过修改部署清单文件的 CRON 作业(每三小时传递一个随机参数)来实现此操作:
我们特别使用 Spinnaker 触发部署:
我们在 Spinnaker 中创建了一个 CRON 作业,如下所示:
配置步骤如下: enter image description here 补丁清单如下:(K8S 在 YAML 更改时重新启动 PODS,为了解决这个问题,请查看帖子底部) enter image description here 由于所有 Pod 可能同时重新启动导致停机时间,我们有一个滚动重启策略,其中 maxUnavailablePods 为 0%。
 spec:
  # replicas: 1
     strategy:
      type: RollingUpdate
       rollingUpdate:
        maxSurge: 50%
          maxUnavailable: 0%

这将产生新的Pod,然后终止旧的Pod。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接