【问题标题】:Restart a Kubernetes Job or Pod with a different command使用不同的命令重新启动 Kubernetes 作业或 Pod
【发布时间】:2021-12-18 14:00:30
【问题描述】:

我正在寻找一种从命令行快速运行/重新启动 Job/Pod 并覆盖要在创建的容器中执行的命令的方法。

就上下文而言,我有一个 Kubernetes 作业,它作为我们部署过程的一部分被执行。有时 Job 崩溃,我需要在 Job 创建的容器内运行某些命令 来调试和修复问题(随后的 Jobs 会成功)。

到目前为止,我这样做的方式是:

  • 复制作业的 YAML,保存到文件中
  • 清理 YAML(删除 Kubernetes 管理的字段)
  • command: 字段更改为tail -f /dev/null(以便容器保持活动状态)
  • kubectl apply -f job.yaml && kubectl get all && kubectl exec -ti pod/foobar bash
  • 在容器内运行命令
  • kubectl delete job/foobar 完成后

这是非常乏味的。我正在寻找一种方法来执行以下操作

kubectl restart job/foobar --command "tail -f /dev/null"

# or even better
kubectl run job/foobar --exec --interactive bash

我无法使用run 命令创建 Pod:

kubectl run --image xxx -ti

因为我尝试重新启动的作业具有某些 volumeMounts 和我需要重用的其他配置。所以我需要像kubectl run --from-config job/foobar 这样的东西。


有没有办法实现这一点,还是我一直在处理 YAML 定义文件?


编辑:Job YAML 看起来大约。像这样:

apiVersion: batch/v1
kind: Job
metadata:
    name: database-migrations
    labels:
        app: myapp
        service: myapp-database-migrations
spec:
    backoffLimit: 0
    template:
        metadata:
            labels:
                app: myapp
                service: myapp-database-migrations
        spec:
            restartPolicy: Never
            containers:
                - name: migrations
                  image: registry.example.com/myapp:977b44c9
                  command:
                      - "bash"
                      - "-c"
                      - |
                          set -e -E
                          echo "Running database migrations..."
                          do-migration-stuff-here
                          echo "Migrations finished at $(date)"
                  imagePullPolicy: Always
                  volumeMounts:
                      -   mountPath: /home/example/myapp/app/config/conf.yml
                          name: myapp-config-volume
                          subPath: conf.yml
                      -   mountPath: /home/example/myapp/.env
                          name: myapp-config-volume
                          subPath: .env
            volumes:
                - name: myapp-config-volume
                  configMap:
                      name: myapp
            imagePullSecrets:
                -   name: k8s-pull-project

【问题讨论】:

  • 您能否提供一个示例 YAML 并说明您究竟想在其中更改什么(清理 YAML(删除 Kubernetes 管理的字段))?什么是 Kubernetes 管理的字段?您是否考虑过为此使用 bash 脚本?
  • 您好,感谢您的评论。我添加了我想要(重新)创建的作业的 YAML。 Kubernetes 管理的字段是例如metadata.managedFieldsmetadata.generateNamestatus 等等。基本上,我在上面发布的 YAML 与您使用 kubectl get <resource> -o yaml 得到的结果之间的差异。我可以通过 bash 脚本来做到这一点,但是我需要将该脚本分发给其他开发人员,所以我想看看是否有更快的“本地”方式来做到这一点。
  • 这对我来说不是很清楚:您正在尝试执行作业创建的已完成 pod,以便调试问题并手动运行脚本? pod 完成后,您将无法执行到此 pod。

标签: kubernetes kubectl kubernetes-jobs


【解决方案1】:

您建议的命令不存在。查看this reference,您可以在其中找到所有可用的命令。

基于that documentationJob 的任务是创建一个或多个 Pod 并继续重试执行它们,直到达到指定数量的成功终止的 Pod。然后Job 跟踪成功完成。您不能只更新作业,因为这些字段不可更新。要做你想做的事,你应该删除当前的工作并重新创建一个。


我建议您将所有配置保存在文件中。如果您在配置作业命令时遇到问题,实践表明您应该在 yaml 中修改这些设置并应用于集群 - 如果您的部署崩溃 - 通过将配置存储在文件中,您就有了备份。

如果您对如何改进此任务感兴趣,可以尝试下面描述的这 2 个示例:

首先我创建了几个文件:

示例作业 (job.yaml):

apiVersion: batch/v1
kind: Job
metadata:
  name: test1
spec:
  template:
    spec:
      containers:
      - name: test1
        image: busybox
        command: ["/bin/sh", "-c", "sleep 300"]
        volumeMounts:
        - name: foo
          mountPath: "/script/foo"
      volumes:
      - name: foo
        configMap:
          name: my-conf
          defaultMode: 0755
      restartPolicy: OnFailure

patch-file.yaml:

spec:
  template:
    spec:
      containers:
      - name: test1
        image: busybox
        command: ["/bin/sh", "-c", "echo 'patching test' && sleep 500"]

configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-conf
data:
  test: |
    #!/bin/sh
    echo "skrypt test"

  1. 如果你想自动化这个过程,你可以使用plugin

插件是一个独立的可执行文件,其名称以kubectl- 开头。要安装插件,请将其可执行文件移动到 PATH 上的任意位置。

不需要插件安装或预加载。插件可执行文件接收来自kubectl 二进制文件的继承环境。插件根据其名称确定它希望实现的命令路径。

这里是可以代替你工作的文件

插件根据其文件名确定它将实现的命令路径。

kubectl-job:

#!/bin/bash
kubectl patch -f job.yaml -p "$(cat patch-job.yaml)" --dry-run=client -o yaml | kubectl replace --force -f - && kubectl wait --for=condition=ready pod -l job-name=test1 && kubectl exec -it $(kubectl get pod -l job-name=test1 --no-headers -o custom-columns=":metadata.name") -- /bin/sh

这个命令使用了一个额外的文件(patch-job.yaml,见这个link)——我们可以在其中对job进行更改。

那么你应该改变这个文件的权限并移动它:

sudo chmod +x .kubectl-job
sudo mv ./kubectl-job /usr/local/bin

一切都完成了。现在就可以使用了。

$ kubectl job
job.batch "test1" deleted
job.batch/test1 replaced
pod/test1-bdxtm condition met
pod/test1-nh2pv condition met
/ #

如您所见,Job 已被替换(删除和创建)。


  1. 也可以使用单行命令,示例如下:
kubectl get job test1 -o json | jq "del(.spec.selector)" | jq "del(.spec.template.metadata.labels)" | kubectl patch -f - --patch '{"spec":  {"template":  {"spec":  {"containers": [{"name": "test1", "image": "busybox", "command": ["/bin/sh", "-c",  "sleep 200"]}]}}}}' --dry-run=client -o yaml | kubectl replace --force -f -

使用此命令,您可以“手动”更改作业输入参数。这是输出:

job.batch "test1" deleted
job.batch/test1 replaced

如您所见,此解决方案也有效。

【讨论】:

  • 虽然这仍然比我想到的理想更麻烦,但我从您的回答中学到了很多,这绝对是一个改进!非常感谢
猜你喜欢
  • 2021-07-15
  • 2021-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多