0

我有 Kubernetes CronJob 的这个规范

---
kind: CronJob
apiVersion: batch/v1beta1
metadata:
  name: do-registry-cleanup

spec:
  schedule: "* * * * *"
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 4
  jobTemplate:
    spec:
      template:
        spec:
          automountServiceAccountToken: false
          restartPolicy: OnFailure
          containers:
          - name: podtest2
            image: alpine
            args:
            - wget
            - http://some_real_url/test/pod/2
            imagePullPolicy: Always
            lifecycle:
              postStart:
                exec:
                  command:
                  - "sh"
                  - "-c"
                  - "sleep 2s;"

当我这样做时,kubectl describe pod some_pod_name我得到这个输出(截断)

Normal   Pulling              105s  kubelet, general-rl8c  pulling image "alpine"
Normal   Pulled               105s  kubelet, general-rl8c  Successfully pulled image "alpine"
Normal   Created              105s  kubelet, general-rl8c  Created container
Normal   Started              104s  kubelet, general-rl8c  Started container
Warning  FailedPostStartHook  104s  kubelet, general-rl8c  Exec lifecycle hook ([sh -c sleep 2s;]) for Container "podtest2" in Pod "do-registry-cleanup-1566391980-dvjdn_default(9d87fe8a-c412-11e9-8744-d2e7c0045fbd)" failed - error: command 'sh -c sleep 2s;' exited with 137: , message: ""
Normal   Killing              104s  kubelet, general-rl8c  Killing container with id docker://podtest2:FailedPostStartHook

因为在这个例子中 wget 是请求 url,我知道 sleep 命令被执行了,没有被破坏。我的问题是为什么:

  1. 为什么会发生?
  2. 这有什么副作用?

一些额外的信息。如果命令是 "cmd1; sleep; cmd2" 那么 cmd2 不执行。所以由于某种原因 sleep cmd 在容器中调用错误。

4

2 回答 2

1

参考官方文档:

Pod 生命周期

一旦容器进入运行状态,就会执行postStart钩子(如果有的话)。

容器在成功完成执行或由于某种原因失败时进入Terminated状态。无论如何,都会显示原因和退出代码,以及容器的开始和结束时间。在容器进入 Terminated 之前,会执行preStop钩子(如果有)。

生命周期钩子

有两个暴露给容器的钩子:

启动后

这个钩子在容器创建后立即执行。但是,不能保证钩子会在容器 ENTRYPOINT 之前执行。没有参数传递给处理程序。

预停

在容器因 API 请求或管理事件(例如活动探测失败、抢占、资源争用等)而终止之前立即调用此钩子。如果容器已经处于终止或完成状态,则调用 preStop 挂钩失败。它是阻塞的,意味着它是同步的,所以它必须在删除容器的调用被发送之前完成。没有参数传递给处理程序

实际上,为 PreStop 编写的内容也适用于 PostStart。

基本上,Kubelet 不会等到所有钩子都完成。它只是在主容器退出后终止所有内容。

对于PreStop,我们只能增加宽限期,但对于PostStart ,我们可以让主容器等到 hook 完成。这是一个例子:

kind: CronJob
apiVersion: batch/v1beta1
metadata:
  name: test1
spec:
  schedule: "* * * * *"
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 4
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: test1
            image: nginx
            command: ["bash", "-c", "touch file1; while [ ! -f file2 ] ; do ls file*; sleep 1 ; done; ls file*"]
            lifecycle:
              postStart:
                exec:
                  command: ["bash", "-c", "sleep 10; touch file2"]

如果您检查 pod 的日志,您会看到钩子在主容器终止之前创建了文件。你可以看到这个循环已经运行了 12 次,而不是 10 次。这意味着 PostStart 在主容器开始运行后 2 秒后启动。这意味着,容器在启动后会延迟一段时间进入运行状态。

$ kubectl describe cronjob/test1 | grep Created
  Normal  SuccessfulCreate  110s  cronjob-controller  Created job test1-1566402420
$ kubectl describe job/test1-1566402420 | grep Created
  Normal  SuccessfulCreate  2m28s  job-controller  Created pod: test1-1566402420-d5lfr
$ kubectl logs pod/test1-1566402420-d5lfr -c test1
file1
file1
file1
file1
file1
file1
file1
file1
file1
file1
file1
file1
file2
于 2019-08-21T16:02:59.750 回答
0

尝试command: ["/bin/sh", "-c", "sleep 2s"]

于 2019-08-21T15:11:26.667 回答