首页 > 解决方案 > 将动态格式化的日期时间传递给 K8s 容器配置

问题描述

我有一个CronJob在 Kubernetes 的容器中运行一个进程。

此过程采用由 a--since--until标志定义的时间窗口。此时间窗口需要在容器启动时间(触发 cron 时)定义,并且是当前时间的函数。运行此过程的示例是:

$ my-process --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ") --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")

因此,对于上面的示例,我希望时间窗口从 1 小时前到未来 1 小时。Kubernetes 中有没有办法将格式化的日期时间作为命令参数传递给进程?

我正在尝试做的一个例子是以下配置:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: my-process
spec:
  schedule: "*/2 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: my-process
            image: my-image
            args:
            - my-process
            - --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ")
            - --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")

执行此操作时,文字字符串"$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ")"将作为--since标志传入。

这样的事情可能吗?如果是这样,我会怎么做?

标签: kubernetescontainerskubernetes-cronjob

解决方案


请注意,在您的环境中,CronJob您不运行bash或任何其他外壳,并且command substitution是外壳功能,没有它将无法工作。在您的示例中,容器中仅启动了一个命令my-process,并且由于它不是 shell,因此无法执行command substitution.

这个:

$ my-process --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ") --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")

将正常工作,因为它是在 a 中启动的,shell因此它可以利用 shell 功能,例如提到的command substitution

一件事:date -v -1H +"%Y-%m-%dT%H:%M:%SZ"没有在bash shell默认GNU/Linux date实现中正确扩展。在其他-v选项中无法识别,所以我猜您正在使用它MacOSX或某种BSD系统。在下面的示例中,我将使用适用于Debian.

因此,为了对其进行测试,GNU/Linux它将是这样的:

date --date='-1 hour' +"%Y-%m-%dT%H:%M:%SZ"

出于测试目的,我已使用此示例中的简单CronJob进行了一些修改:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            env:
            - name: FROM
              value: $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ")
            - name: TILL
              value: $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")
            args:
            - /bin/sh
            - -c
            - date; echo from $(FROM) till $(TILL)
          restartPolicy: OnFailure

它工作正常。下面可以看到CronJob执行结果:

$ kubectl logs hello-1569947100-xmglq
 Tue Oct  1 16:25:11 UTC 2019
 from 2019-10-01T15:25:11Z till 2019-10-01T17:25:11Z

除了使用环境变量的示例之外,我还使用以下代码对其进行了测试:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            args:
            - /bin/sh
            - -c
            - date; echo from $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ") till $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")
          restartPolicy: OnFailure

如您所见,这里command substitution也可以正常工作:

$ kubectl logs hello-1569949680-fk782
Tue Oct  1 17:08:09 UTC 2019
from 2019-10-01T16:08:09Z till 2019-10-01T18:08:09Z

它可以正常工作,因为在这两个示例中,我们首先bash shell在容器中生成,然后它运行其他命令,echo就像它的参数一样简单。您可以使用您的my-process命令,而不是echo只需要在一行中提供它的所有参数,如下所示:

args:
- /bin/sh
- -c
- my-process --since=$(date -v -1H +"%Y-%m-%dT%H:%M:%SZ") --until=$(date -v +1H +"%Y-%m-%dT%H:%M:%SZ")

此示例将不起作用,因为没有shell涉及。echo不是 shell 的命令将无法执行作为 shell 功能的命令替换:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            args:
            - /bin/echo
            - from $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ") till $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")
          restartPolicy: OnFailure

结果将是一个文字字符串:

$ kubectl logs hello-1569951180-fvghz
from $(date --date="-1 hour" +"%Y-%m-%dT%H:%M:%SZ") till $(date --date="+1 hour" +"%Y-%m-%dT%H:%M:%SZ")

这与您的命令类似,例如echois not ashell并且它无法执行command substitution

总结一下:解决方案是将您的命令包装为 shell 参数。在前两个示例echo中,命令与其他命令一起作为 shell 参数传递。

也许在以下示例中可以更清楚地看到它,但语法略有不同:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: debian
            command: ["/bin/sh","-c"]
            args: ["FROM=$(date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ'); TILL=$(date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ') ;echo from $FROM till $TILL"]
          restartPolicy: OnFailure

man bash说:

-c 如果存在 -c 选项,则从第一个非选项参数 command_string 中读取命令。

所以command: ["/bin/sh","-c"]基本上意味着运行一个 shell 并执行以下命令,然后我们使用args. inbash命令应该用分号分隔;,以便它们独立运行(无论执行前一个命令/命令的结果如何,都会执行后续命令)。

在以下片段中:

args: ["FROM=$(date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ'); TILL=$(date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ') ;echo from $FROM till $TILL"]

我们提供/bin/sh -c三个单独的命令:

FROM=$(date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ')

它将FROM环境变量设置为date --date='-1 hour' +'%Y-%m-%dT%H:%M:%SZ'命令执行的结果,

TILL=$(date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ')

它将TILL环境变量设置为date --date='+1 hour' +'%Y-%m-%dT%H:%M:%SZ'命令执行的结果

最后我们跑

echo from $FROM till $TILL

它使用这两个变量。

任何其他命令都可以做到这一点。


推荐阅读