Подтвердить что ты не робот

Cron Jobs в Кубернете - подключитесь к существующему Pod, выполните script

Я уверен, что мне не хватает чего-то очевидного. Я просмотрел документацию для ScheduledJobs/CronJobs на Kubernetes, но я не могу найти способ сделать следующее по расписанию:

  • Подключиться к существующему Pod
  • Выполнить script
  • Отключить

У меня есть альтернативные способы сделать это, но они не чувствуют себя хорошо.

  • Расписание задачи cron для: kubectl exec -it $(kubectl get pods --selector = some-selector | head -1)/path/to/ script

  • Создайте одно развертывание с "Cron Pod", в котором также находится приложение, и многие "Non Cron Pods", которые являются только приложением. Cron Pod будет использовать другое изображение (одно с запланированными заданиями cron).

Я бы предпочел использовать Kubernetes ScheduledJobs, если это возможно, чтобы предотвратить одновременное выполнение одного и того же задания, а также потому, что это делает меня более подходящим способом.

Есть ли способ сделать это с помощью ScheduledJobs/CronJobs?

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

4b9b3361

Ответ 1

Насколько я знаю, нет "официального" способа сделать это так, как вы хотите, и это я считаю по дизайну. Предполагается, что Pods будет эфемерным и горизонтально масштабируемым, а Джобс предназначен для выхода. Наличие задания "cron" для существующего контейнера не соответствует этому модулю. Планировщик понятия не имел, завершена ли работа.

Вместо этого 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"

И работа, которая подключается к одной базе данных, но с другой "точкой входа":

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"

Или подход с постоянным объемом будет выглядеть примерно так:

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

С таким заданием, прикрепленным к одному и тому же тому:

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

Ответ 2

Это похоже на анти-шаблон. Почему вы не можете просто запустить свой рабочий модуль в качестве рабочего модуля?

Независимо от того, вы, кажется, уверены, что вам нужно это сделать. Вот что я бы сделал.

Возьмите свой рабочий модуль и оберните выполнение оболочки в простой веб-сервис, это 10 минут работы практически с любым языком. Разоблачите порт и поставьте службу перед этим работником. Тогда ваши рабочие модули могут просто свернуться..svc.cluster.local:/(если вы не зациклены на dns).

Ответ 3

Это должно помочь.

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/30 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            kubectl exec -it  <podname> "sh script.sh ";
          restartPolicy: OnFailure

Ответ 4

Создайте запланированный модуль, который использует API Kubernetes для запуска нужной команды на целевых модулях через функцию exec. Образ модуля должен содержать клиентские библиотеки для доступа к API - многие из них доступны, или вы можете создать свою собственную.

Например, вот решение, использующее клиент Python, который запускается для каждого модуля ZooKeeper и запускает команду обслуживания базы данных:

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>"))

и связанный Dockerfile:

FROM ubuntu:18.04
LABEL maintainer "reDock Inc."

ADD ./cleanupZk.py /

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

CMD /cleanupZk.py

Обратите внимание, что если у вас есть кластер с поддержкой RBAC, вам может потребоваться создать учетную запись службы и соответствующие роли, чтобы сделать этот вызов API возможным. Для перечисления модулей и запуска exec достаточно такой роли, как требуется в приведенном выше примере сценария:

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"]

Пример связанного задания cron:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: zk-maint
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: zk-maint-pod-list-exec
  namespace: default
subjects:
- kind: ServiceAccount
  name: zk-maint
  namespace: default
roleRef:
  kind: Role
  name: pod-list-exec
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: zk-maint
  namespace: default
  labels:
    app: zk-maint
    tier: jobs
spec:
  schedule: "45 3 * * *"
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: zk-maint
            image: myorg/zkmaint:latest
          serviceAccountName: zk-maint
          restartPolicy: OnFailure
          imagePullSecrets:
          - name: azure-container-registry