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

时间:2016-12-16 20:34:01

标签: kubernetes kubernetes-cronjob

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

  1. 连接到现有Pod
  2. 执行脚本
  3. 断开
  4. 我有其他方法可以做到这一点,但他们感觉不对。

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

    2. 创建一个具有" Cron Pod"它还包含应用程序,以及许多非Cron Pods"这只是应用程序。 Cron Pod将使用不同的图像(一个安排了cron任务)。

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

      有没有办法通过ScheduledJobs / CronJobs执行此操作?

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

5 个答案:

答案 0 :(得分:2)

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

相反,作业可以专门用于运行作业的应用程序实例,然后在作业完成后将其删除。为此,您可以使用与部署相同的作业图像,但可以通过设置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

答案 1 :(得分:1)

这似乎是一种反模式。为什么不能只将工作人员吊舱作为工作吊舱运行?

尽管您似乎非常确信您需要执行此操作。这就是我要做的。

带您的工作人员吊舱并将您的Shell执行包装在一个简单的Web服务中,几乎可以使用任何一种语言工作10分钟。露出港口,并在该名工人前布置服务。然后,您的工作窗格可以简单地卷曲..svc.cluster.local:/(除非您对dns感到困惑)。

答案 2 :(得分:1)

这应该有所帮助。

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

答案 3 :(得分:0)

创建一个计划的容器,该容器使用Kubernetes API通过exec函数在目标容器上运行所需的命令。容器图片应包含client libraries才能访问API-其中许多可用,或者您可以构建自己的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调用。像下面这样的角色足以列出pod并运行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

答案 4 :(得分:0)

我设法通过使用doctl(DigitalOcean的命令行界面)和kubectl创建自定义图像来做到这一点。 CronJob对象将使用这两个命令来下载集群配置并针对容器运行命令。

以下是CronJob示例:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: drupal-cron
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: drupal-cron
              image: juampynr/digital-ocean-cronjob:latest
              env:
                - name: DIGITALOCEAN_ACCESS_TOKEN
                  valueFrom:
                    secretKeyRef:
                      name: api
                      key: key
              command: ["/bin/bash","-c"]
              args:
                - doctl kubernetes cluster kubeconfig save drupster;
                  POD_NAME=$(kubectl get pods -l tier=frontend -o=jsonpath='{.items[0].metadata.name}');
                  kubectl exec $POD_NAME -c drupal -- vendor/bin/drush core:cron;
          restartPolicy: OnFailure

这是CronJob使用的Docker映像:https://hub.docker.com/repository/docker/juampynr/digital-ocean-cronjob

如果您不使用DigitalOcean,请弄清楚如何下载群集配置,以便kubectl可以使用它。例如,对于Google Cloud,您必须下载gcloud

这是我实施此https://github.com/juampynr/drupal8-do的项目存储库。