Running a Job¶
The simplest workload you can set up in RAIL is running a Job. It will schedule a Pod that runs its container to completion and then stops.
In this example we will run a Job that runs a Python program that computes plenty of digits of 𝜋. We will use the standard Dockerhub Python container and we will use a ConfigMap to provide the Python script that we want to run. We will also use the kustomize tool as a simpler way to create the ConfigMap.
We have prepared the example in the <https://git.app.uib.no/gisle/k8s-pi-job> repo. Here you can inspect the content of the kustomization.yaml file which results in two resources a Job and a ConfigMap that you can view by running this on your workstation:
kubectl kustomize git@git.app.uib.no:gisle/k8s-pi-job.git?ref=f1f411f93f953c01b24b9b0e0b172afd2185d743
This will output the Kubernetes resources you need for this job.
This output can then be piped to kubectl apply -f -
to create the objects in the cluster.
You can also apply this directly with:
kubectl apply -k git@git.app.uib.no:gisle/k8s-pi-job.git?ref=f1f411f93f953c01b24b9b0e0b172afd2185d743
Then inspect the state of the job with:
kubectl describe job pi
When the job finishes you can read the output generated with:
kubectl logs job/pi
The job and the pod are automatially deleted after 10 minutes (as specified by
the ttlSecondsAfterFinished
setting). If you want to clean up before this
time run this command:
kubectl delete -k git@git.app.uib.no:gisle/k8s-pi-job.git?ref=f1f411f93f953c01b24b9b0e0b172afd2185d743
For reference, this is the resource specification file describing the job above:
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
ttlSecondsAfterFinished: 600
template:
spec:
securityContext:
runAsUser: 10000
restartPolicy: Never
containers:
- name: pi
image: python:3
command: ["python", "/app/pi.py", "10000"]
volumeMounts:
- name: app
mountPath: /app
# RAIL requires us to specify how resource hungry each container is
resources:
requests:
cpu: 200m
memory: 5Mi
limits:
cpu: 200m
memory: 20Mi
# This states the defaults for the securityContext and will get rid of
# the warning that you should set these values. These values can not be
# set at the Pod-level, so they need to be specified here.
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
seccompProfile:
type:
RuntimeDefault
In order to comply with the demands of the RAIL platform we had to use the ":3"
tag for the image instead of defaulting to ":latest"
which is not allowed, and we hade to override the user that it runs under with securityContext.runAsUser
since this container by default runs as root. The id 10000 is just conventional, any number other that 0 will do. You can put the securityContext.runAsUser
specification either at the Pod-level as done here, or inside the container record.
The resources block must be specified for each container in RAIL. This specifies the resources the container normally will consume as well as upper limits. More information available from Container Resources Specification.
Another approach¶
Instead of using the base Python container and providing the script using a ConfigMap we might want to build a custom container that contains all we need and run that. This require a Dockerfile and a system that can build and publish the image to a container registry – and our git.app.uib.no service provide just this. The <https://git.app.uib.no/gisle/k8s-pi-job> repository is set up with both the Dockerfile and the build instructions for producing the image in the .gitlab-ci.yml file.
This is the Dockerfile required:
FROM python:3-alpine
RUN mkdir /app
COPY pi.py /app
WORKDIR /app
USER 10000
The essence of the .gitlab-ci.yml is simply:
build_container:
stage: build
variables:
dir: .
image_name: pi-job
dockerfile: Dockerfile
extends:
- .build_container_image
rules:
- if: '$REUSE_CONTAINER == null'
This will cause the container image pi-job to be built and published to the git.app.uib.no:4567 registry. The full address to the image in the repo will then be git.app.uib.no:4567/gisle/k8s-pi-job/pi-job:<tag>.
To actually run this job we now require this one Kubernetes resource file:
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
ttlSecondsAfterFinished: 600
template:
spec:
restartPolicy: Never
containers:
- name: pi
image: git.app.uib.no:4567/gisle/k8s-pi-job/pi-job:f32c04f6
command: ["python", "pi.py", "10000"]
# RAIL requires us to specify how resource hungry each container is
resources:
requests:
cpu: 200m
memory: 5Mi
limits:
cpu: 200m
memory: 20Mi
# This states the defaults for the securityContent and will get rid of
# the warning that you should set these values. These values can not be
# set at the Pod-level, so they need to be specified here.
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
seccompProfile:
type:
RuntimeDefault
It’s the same as above, but simplified since we now don’t have to mess with volumes to mount the ConfigMap and we don’t have to override the securityContext.runAsUser
either since our custom container has already overridden the default user id.
To run this job just pipe this file to kubectl apply -f-
and to clean up the job pipe this file to kubectl delete -f-
.
The resource file above works when the registry is connected to a public Git project, which also gives you a public registry that can be fetched from without providing authentication information. If you publish from a protected or private project, then you need to provide authentication information by setting up the imagePullSecrets
list. We have a separate document on UiB GitLab as Container Image Registry that explains how to get an access token and configure authentication.