Cronjobber i Kubernetes
Hva en en Cronjob?
Kort fortalt er det en måte å kjøre et program på et intervall. I *nix-verdenen brukes følgende oppsett (med noen eksempler):
Minutt | Time | Dag i mnd | Måned | Dag i uka | Resultat |
---|---|---|---|---|---|
* | * | * | * | * | Hvert minutt, året rundt |
*/10 | * | * | * | * | Hvert tiende minutt, året rundt |
10 | 17 | * | 8 | * | Kl. 17:10, hver dag, i august |
10 | 3 | * | * | 1 | kl. 03:10, hver mandag, året rundt |
Kurant verktøy for å generere crontab-linjer: https://crontab-generator.org/
Hva forsøker man å løse?
aID har pleid å kjøre cron-jobbene sine i de samme podene som svarer på brukertrafikk.
Det skaper flere utfordringer, bland annet:
- Hvem skal gjøre jobben? I en horisontalt skalert app er det n* kandidater til å kjøre en cron, men det er ikke dermed sikkert at man kan kjøre den samme jobben flere steder samtidig. Lett at de går i beina på hverandre feks. Dette har vi da løst med en tabell i mysql der instansene blir enige seg i mellom om hvem som skal kjøre hvilken jobb. Det er vel ikke nødvendig å si at det introduserer kompleksitet :)
- Alle appene må være skalert til å ta unna all forventet brukertrafikk, pluss nok overhead til å ta unna den tyngste jobben. Vi har for eksempel en jobb som henter ut masse data til #team-data. Slike store uthentinger og masseringer skaper behov for en del minne - som egentlig kun blir brukt av én av podene.
- Poden som skal ta unna en spesielt tung jobb blir da mer opptatt en de andre podene, men den får ikke mindre brukertrafikk av den grunn. Poden vil derfor være tregere til å respondere og i værste fall feile hele requesten.
Ved å kjøre jobbene separat fra podene som svarer på brukertrafikk blir det mye lettere å stramme inn på ressursene man trenger og man kan fjerne kompleksisteten rundt hvem gjør hvilke jobber når.
Kubernetes konfigurasjon
Opprette en CronJob config. En per jobb du vil kjøre.
Kubernetes dokumentasjon: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs
For å kunne bruke felles image (og minst mulig kopiering av samme konfigurasjon) setter vi opp jobben i /base. Den står da med suspend: true
. For at jobben skal kjøre må den aktivers i de relevante miljøene. Se lenge ned.
base/aidos/cronjob-database-metrics.yaml
:
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: database-metrics-reporter
namespace: aidos
spec:
suspend: true
concurrencyPolicy: Forbid
schedule: '*/5 * * * *'
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
containers:
- name: aidos-job
image: aidos # <- Dette er samme name som images.name i kustomization.yaml under
imagePullPolicy: Always
command:
- '/app/bin/aidos-job'
args: ['database-metrics-reporter']
env: [...]
Last inn den nye cronjobben din og definer et image som skal brukes
Dersom du definerer et image navn i base/app/kustomization.yaml, så kan du bruke dette i alle deploy / cron definisjonene. Når du da deployer en ny versjon av appen din, vil samme image bli brukt til å kjøre cron.
Husk å bruke samme image name i /base/app/deployment.yaml!
base/aidos/kustomization.yaml
:
---
resources:
[...]
- cronjob-database-metrics.yaml
images:
- name: "aidos"
newName: "eu.gcr.io/amedia-core/amedia/aidos"
newTag: "master-7166e10"
Aktiver jobben i de miljøene du ønsker (ved å patche suspend til false)
production|snapX/aidos/cronjob-database-metrics-patch.yaml
:
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: database-metrics-reporter
namespace: aidos
spec:
suspend: false
Husk å laste patchen din
production|snapx/aidos/kustomize.yaml
:
---
patches:
- [...]
- path: cronjob-database-metrics-patch.yaml
Feilsøking
kustomize
CLIet er nyttig for å sjekke at konfigurasjonen blir som du hadde tenkt. Du finner den nok i din favorikk package manager for OSet du sitter på :)
Eksempel på verifisering av at suspend blir satt til false i prod på den ene jobben som finnes PT for aidos.
$ pwd
/home/emil/Source/amedia/k8s-objects/kustomize
$ kustomize build production/aidos | grep suspend
suspend: false