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/
Ответы
Ответ 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