There are multiple ways to run once-off jobs in OpenShift, in this article I will cover a few different approaches.

Using oc run

oc run will spin up a new job in a pod for you, using the -i -tty keeps it in the foreground so you can figure out when the job has been completed.

$ oc run -i --tty bashing --image=registry.access.redhat.com/rhel7/rhel:latest --restart=Never --command -- /bin/bash -c "for i in {1..5}; do echo hi stuff; sleep 20; done"

The above command will result in the following output:

Waiting for pod jobs/bashing to be running, status is Pending, pod ready: false
Waiting for pod jobs/bashing to be running, status is Pending, pod ready: false
If you don't see a command prompt, try pressing enter.
                                                      hi stuff
hi stuff
hi stuff
hi stuff
Waiting for pod jobs/bashing to terminate, status is Running
Waiting for pod jobs/bashing to terminate, status is Running
$

Running Pods

Simple pod job running a script

A simple pod running a loop, notice we are using the generateName so that the pod will get a unique identifier. The restart policy is Never, this means once the pod job has completed or errored it will not be restarted. We will need to inspect the logs of the job pod, and/or check the status of the pod to see whether the pod ran with success.

oc create -f - <<EOF
---
apiVersion: v1
kind: Pod
metadata:
  generateName: bashing-
  labels:
    script: echos
spec:
  containers:
  - name: bashing
    image: registry.access.redhat.com/rhel7/rhel:latest
    command: ["/bin/bash", "-c", "for i in {1..5}; do echo hi stuff; sleep 20; done" ]
  restartPolicy: Never
...
EOF

pod "bashing-uj6bw" created
$ oc logs -f pods/bashing-uj6bw
hi stuff
hi stuff
hi stuff
hi stuff
hi stuff

Running a pod with attached scripts

Create a ConfigMap which will contain a couple of bash scripts, this will be mounted by the pod and executed. The scripts are very simple echo scripts.

apiVersion: v1
data:
hiparam-loop.sh: |
#!/bin/sh
for i in {1..5}; do echo hi $i $1; sleep 10; done
histuff-loop.sh: |
#!/bin/sh
for i in {1..5}; do echo hi $i stuff; sleep 20; done
hiworld-loop.sh: |
#!/bin/sh
for i in {1..5}; do echo hi world $i ; sleep 10; done
kind: ConfigMap
metadata:
name: scripts
view raw configmap.yml hosted with ❤ by GitHub
oc create -f https://gist.githubusercontent.com/welshstew/690ee4e6352d8ff28a62be0f1921eb32/raw/bc0fec80a44be00db3a8b08b868a8eff44f95404/configmap.yml

export SCRIPT_NAME=hiparam-loop

oc create -f - <<EOF
---
apiVersion: v1
kind: Pod
metadata:
  generateName: $(basename $SCRIPT_NAME .sh | tr [:upper:] [:lower:])-
  labels:
    jobid: bash-$(date +%Y%m%d)
    script: $SCRIPT_NAME
  annotations:
    command: $SCRIPT_NAME $@
spec:
  containers:
  - name: bashing
    image: registry.access.redhat.com/rhel7/rhel:latest
    command: ["/bin/bash", "/opt/scripts/$SCRIPT_NAME.sh", "$@"]
    volumeMounts:
    - mountPath: /opt/scripts
      name: bash-scripts
  volumes:
  - name: bash-scripts
    configMap:
      name: scripts
  restartPolicy: Never
...
EOF

Running Jobs

Jobs are another kubernetes feature, so instead of defining executions as pods, we can define them as a job. Please see the upstream documentation for more details

Pros to running tasks as jobs:

  • cleans up the pods
  • can run multiple pods in parallel
oc create -f - <<EOF
---
apiVersion: extensions/v1beta1
kind: Job
metadata:
  name: bash-hello-loop
spec:
  selector:         
    matchLabels:
      app: bash-hello-loop
  parallelism: 1    
  completions: 1    
  template:         
    metadata:
      name: bash-hello-loop
      labels:
        app: bash-hello-loop
    spec:
      containers:
      - name: bashing
        image: registry.access.redhat.com/rhel7/rhel:latest
        command: ["/bin/bash", "/opt/scripts/histuff-loop.sh"]
        volumeMounts:
        - mountPath: /opt/scripts
          name: bash-scripts
      volumes:
      - name: bash-scripts
        configMap:
          name: scripts
      restartPolicy: Never
...
EOF

job "bash-hello-loop" created
$ oc get jobs
NAME              DESIRED   SUCCESSFUL   AGE
bash-hello-loop   1         1            3m

Running Scheduled Jobs

You can also run jobs on a schedule (i.e. as cron jobs)

Running the below code will create a new scheduled job which will run every 5 minutes. The scheduled job is created from the template in the gist.

oc new-project jobs
oc create -f https://gist.githubusercontent.com/welshstew/690ee4e6352d8ff28a62be0f1921eb32/raw/bc0fec80a44be00db3a8b08b868a8eff44f95404/configmap.yml
oc create -f https://gist.githubusercontent.com/welshstew/690ee4e6352d8ff28a62be0f1921eb32/raw/bc0fec80a44be00db3a8b08b868a8eff44f95404/scheduledjob-helloworld-template.yml
oc new-app --template=scheduledjob-helloworld

ScheduledJob Template

apiVersion: v1
kind: Template
labels:
template: scheduledjob-helloworld
metadata:
annotations:
description: Scheduled Task to Print HelloWorld
iconClass: icon-shadowman
tags: scheduledjob,bash
creationTimestamp: null
name: scheduledjob-helloworld
objects:
- apiVersion: batch/v2alpha1
kind: ScheduledJob
metadata:
name: ${JOB_NAME}
spec:
concurrencyPolicy: Forbid
failedJobsHistoryLimit: ${{FAILED_JOBS_HISTORY_LIMIT}}
jobTemplate:
spec:
template:
spec:
activeDeadlineSeconds: 500
containers:
- command:
- /bin/bash
- -c
- /opt/scripts/histuff-loop.sh
image: registry.access.redhat.com/rhel7/rhel:latest
name: ${JOB_NAME}
volumeMounts:
- mountPath: /opt/scripts
name: bash-scripts
dnsPolicy: ClusterFirst
restartPolicy: Never
terminationGracePeriodSeconds: 30
volumes:
- configMap:
name: scripts
name: bash-scripts
schedule: ${SCHEDULE}
successfulJobsHistoryLimit: ${{SUCCESS_JOBS_HISTORY_LIMIT}}
parameters:
- description: Name of the Scheduled Job to Create.
displayName: Job Name
name: JOB_NAME
required: true
value: scheduledjob-helloworld
- description: Cron Schedule to Execute the Job
displayName: Cron Schedule
name: SCHEDULE
required: true
value: '*/5 * * * *'
- description: The number of successful jobs that will be retained
displayName: Successful Job History Limit
name: SUCCESS_JOBS_HISTORY_LIMIT
required: true
value: "5"
- description: The number of failed jobs that will be retained
displayName: Failed Job History Limit
name: FAILED_JOBS_HISTORY_LIMIT
required: true
value: "5"

codergists