Kronnetes中的Cron Jobs - 连接到现有的Pod,执行脚本

Aei*_*sor 20 kubernetes kubernetes-cronjob

我确定我错过了一些明显的东西.我查看了Kubernetes上ScheduledJobs/CronJobs的文档,但是我找不到按计划执行以下操作的方法:

  1. 连接到现有Pod
  2. 执行脚本
  3. 断开

我有其他方法可以做到这一点,但他们感觉不对.

  1. 安排一个cron任务:kubectl exec -it $(kubectl get pods --selector = some-selector | head -1)/ path/to/script

  2. 创建一个具有"Cron Pod"的部署,该部署也包含应用程序,以及许多"Non Cron Pod",它们只是应用程序.Cron Pod将使用不同的图像(一个安排了cron任务).

如果可能的话,我宁愿使用Kubernetes ScheduledJobs来防止同一个Job同时运行多次,也因为它让我感觉更合适.

有没有办法通过ScheduledJobs/CronJobs来做到这一点?

http://kubernetes.io/docs/user-guide/cron-jobs/

Sim*_*n I 8

据我所知,没有“官方”的方式可以按照你想要的方式做到这一点,我相信这是设计。Pods 应该是短暂的和水平可扩展的,而 Jobs 被设计为退出。将 cron 作业“附加”到现有 pod 不适合该模块。调度程序不知道作业是否完成。

相反,Job 可以启动一个专门用于运行 Job 的应用程序实例,然后在 Job 完成后将其关闭。为此,您可以为作业使用与部署相同的图像,但通过设置command:.

如果他们的工作需要访问由您的应用程序创建的数据,那么该数据将需要在应用程序/Pod 之外持久化,您可以采用几种方法,但显而易见的方法是数据库或持久卷。例如,使用数据库看起来像这样:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: APP
spec:
  template:
    metadata:
      labels:
        name: THIS
        app: THAT
    spec:
      containers:
        - image: APP:IMAGE
          name: APP
          command:
          - app-start
          env:
            - name: DB_HOST
              value: "127.0.0.1"
            - name: DB_DATABASE
              value: "app_db"
Run Code Online (Sandbox Code Playgroud)

以及连接到同一数据库但具有不同“入口点”的作业:

apiVersion: batch/v1
kind: Job
metadata:
  name: APP-JOB
spec:
  template:
    metadata:
      name: APP-JOB
      labels:
        app: THAT
    spec:
      containers:
      - image: APP:IMAGE
        name: APP-JOB
        command:
        - app-job
        env:
          - name: DB_HOST
            value: "127.0.0.1"
          - name: DB_DATABASE
            value: "app_db"
Run Code Online (Sandbox Code Playgroud)

或者持久卷方法看起来像这样:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: APP
spec:
  template:
    metadata:
      labels:
        name: THIS
        app: THAT
    spec:
      containers:
        - image: APP:IMAGE
          name: APP
          command:
          - app-start
          volumeMounts:
          - mountPath: "/var/www/html"
            name: APP-VOLUME
      volumes:
        - name:  APP-VOLUME
          persistentVolumeClaim:
            claimName: APP-CLAIM

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name: APP-VOLUME
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /app

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: APP-CLAIM
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  selector:
    matchLabels:
      service: app
Run Code Online (Sandbox Code Playgroud)

使用这样的作业,附加到同一个卷:

apiVersion: batch/v1
kind: Job
metadata:
  name: APP-JOB
spec:
  template:
    metadata:
      name: APP-JOB
      labels:
        app: THAT
    spec:
      containers:
      - image: APP:IMAGE
        name: APP-JOB
        command:
        - app-job
        volumeMounts:
        - mountPath: "/var/www/html"
          name: APP-VOLUME
    volumes:
      - name:  APP-VOLUME
        persistentVolumeClaim:
          claimName: APP-CLAIM
Run Code Online (Sandbox Code Playgroud)

  • 我和OP有同样的问题。我们拥有的一个用例是运行在单独 pod 中运行的 gitlab 综合安装的备份。通过在 gitlab 的 pod 内运行命令来触发备份当然没有选项可以跨 pod 共享其数据(即“ReadWriteMany”),当然也没有选项在同一卷上启动 gitlab 的第二个实例(万无一失的破坏方式)它的内部数据库)。您对此有何看法? (4认同)

Ram*_*man 6

创建一个计划的 pod,它使用 Kubernetes API 通过exec函数在目标 pod 上运行您想要的命令。pod 映像应包含用于访问 API的客户端库——其中许多都可用,或者您可以构建自己的库。

例如,这是一个使用 Python 客户端的解决方案,该客户端执行每个 ZooKeeper pod 并运行数据库维护命令:

import time

from kubernetes import config
from kubernetes.client import Configuration
from kubernetes.client.apis import core_v1_api
from kubernetes.client.rest import ApiException
from kubernetes.stream import stream
import urllib3

config.load_incluster_config()

configuration = Configuration()
configuration.verify_ssl = False
configuration.assert_hostname = False
urllib3.disable_warnings()
Configuration.set_default(configuration)

api = core_v1_api.CoreV1Api()
label_selector = 'app=zk,tier=backend'
namespace = 'default'

resp = api.list_namespaced_pod(namespace=namespace,
                               label_selector=label_selector)

for x in resp.items:
  name = x.spec.hostname

  resp = api.read_namespaced_pod(name=name,
                                 namespace=namespace)

  exec_command = [
  '/bin/sh',
  '-c',
  'opt/zookeeper/bin/zkCleanup.sh -n 10'
  ]

  resp = stream(api.connect_get_namespaced_pod_exec, name, namespace,
              command=exec_command,
              stderr=True, stdin=False,
              stdout=True, tty=False)

  print("============================ Cleanup %s: ============================\n%s\n" % (name, resp if resp else "<no output>"))

Run Code Online (Sandbox Code Playgroud)

以及相关的 Dockerfile:

FROM ubuntu:18.04

ADD ./cleanupZk.py /

RUN apt-get update \
  && apt-get install -y python-pip \
  && pip install kubernetes \
  && chmod +x /cleanupZk.py

CMD /cleanupZk.py
Run Code Online (Sandbox Code Playgroud)

请注意,如果您有一个启用 RBAC 的集群,您可能需要创建一个服务帐户和适当的角色才能使此 API 调用成为可能。像下面这样的角色就足以列出 pod 并运行 exec,例如上面的示例脚本需要:

FROM ubuntu:18.04

ADD ./cleanupZk.py /

RUN apt-get update \
  && apt-get install -y python-pip \
  && pip install kubernetes \
  && chmod +x /cleanupZk.py

CMD /cleanupZk.py
Run Code Online (Sandbox Code Playgroud)

相关 cron 作业的示例:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-list-exec
  namespace: default
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources: ["pods"]
    verbs: ["get", "list"]
  - apiGroups: [""] # "" indicates the core API group
    resources: ["pods/exec"]
    verbs: ["create", "get"]
Run Code Online (Sandbox Code Playgroud)