Job
Jobs represent one-off tasks that run to completion and then stop.
A Kubernetes Job is a workload resource that is used to run a task to completion. Unlike Deployments or StatefulSets, which are designed for long-running applications, a Job is for one-time or batch tasks that need to start, run, and finish successfully.
- Task Completion → Ensures a specific task runs and finishes successfully.
- Pod Management → Creates and manages Pods until they complete successfully.
- Retry Mechanism → If a Pod fails, the Job automatically retries it based on the defined policy.
- Parallel Execution → Supports parallel tasks using multiple Pods.
Types
- Single Job (Default): Runs one Pod until it completes. Ideal for simple, single-instance tasks.
- Parallel Jobs: Runs multiple Pods in parallel to speed up large tasks.
- Completion Mode: The Job is considered complete when there have been
.spec.completions
successfully completed Pods.
- Completion Mode: The Job is considered complete when there have been
- Indexed Parallel Jobs: Provides unique identifiers (
JOB_COMPLETION_INDEX
in environment variables) for each pod—useful for partitioning tasks.
Job to Backup Database
Lets create a job that perform backup of our PostgreSQL database. You should already have a PostgreSQL database service up and running in your cluster. If not you can follow instruction in here: Persistent Volume.
Create PV and PVC
First lets create a Persistent Volume (PV) and Persistent Volume Claim (PVC) to store the backup data. In here I put both into single file called postgres-backup-pv-pvc.yaml
.
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-backup-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /mnt/data/postgres-backup
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-backup-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: manual
Apply the yaml
file and validate, we should see the PV and PVC that we just created.
➜ kubectl apply -f postgres-backup-pv-pvc.yaml
persistentvolume/postgres-backup-pv created
persistentvolumeclaim/postgres-backup-pvc created
➜ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
postgres-backup-pv 1Gi RWO Retain Bound default/postgres-backup-pvc manual <unset> 3s
postgres-pv 1Gi RWO Retain Bound default/postgres-pvc manual <unset> 18d
➜ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
postgres-backup-pvc Bound postgres-backup-pv 1Gi RWO manual <unset> 87s
postgres-pvc Bound postgres-pv 1Gi RWO manual <unset> 18d
Create Job to Dump Database
Now lets create a job to run pg_dump
command. This command is to makes consistent backups even if the database is being used concurrently.
We will use postgres
image because this image already have pg_dump
installed. So we don't need to install it manually every time this job run. We will use credentials available in our secrets. If your postgres service still haven't use any secrets you can follow this instructions: Secret.
Lets create a file called postgres-backup-job.yaml
and put below definition there.
apiVersion: batch/v1
kind: Job
metadata:
name: postgres-backup
spec:
template:
spec:
containers:
- name: postgres-backup
image: postgres:17
command: ["/bin/sh", "-c"]
args:
- |
echo "Starting PostgreSQL backup..."
pg_dump -h postgres.default.svc.cluster.local -d mydb > /backup/postgres_backup_$(date +%Y%m%d%H%M%S).sql
echo "Backup completed!"
env:
- name: PGUSER
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_USER
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PASSWORD
volumeMounts:
- mountPath: /backup
name: backup-storage
volumes:
- name: backup-storage
persistentVolumeClaim:
claimName: postgres-backup-pvc
restartPolicy: Never
apiVersion: batch/v1
: Tells Kubernetes to use thebatch/v1
API, which manages Jobs.kind: Job
: Resource type.metadata.name
: Names the Jobpostgres-backup
.spec
: Define job specification.template.spec
: The Pod specification (like a blueprint for what Pods the Job will create).containers
: Defines the list of containers within the pod.name: postgres-backup
: Name of this container.image: postgres:17
: Uses the official PostgreSQLv17
Docker image, which includes thepg_dump
utility.command
: Overrides the container's default entrypoint.["/bin/sh", "-c"]
: Executes a shell (sh) to run a multi-line script.
args
: Defines the script to run inside the container.
Backup Script:
echo "Starting PostgreSQL backup..."
pg_dump -h postgres.default.svc.cluster.local -d mydb > /backup/postgres_backup_$(date +%Y%m%d%H%M%S).sql
echo "Backup completed!"
- This script will run
pg_dump
with host pointed to our postgres service and database namemydb
. - It will use provided
PGUSER
andPGPASSWORD
in the environment variables. /backup/postgres_backup_$(date +%Y%m%d%H%M%S).sql
: Saves the backup to a timestamped file in/backup
directory (for unique names).
Lets apply this file using kubectl apply
and you should see your job with status Running
or even already Complete
.
➜ kubectl apply -f postgres-backup-job.yaml
job.batch/postgres-backup created
➜ kubectl get jobs
NAME STATUS COMPLETIONS DURATION AGE
postgres-backup Complete 1/1 3s 14s
We can check the logs to make sure that the script run properly using kubectl logs
command.
➜ kubectl logs jobs/postgres-backup
Starting PostgreSQL backup...
Backup completed!
Check Persistent Volume in Minikube
In minikube we can easily check the Persistent Volume content using minikube ssh
to make sure that the our backup script is correct.
minikube ssh
docker@minikube:~$ cd /mnt/data/postgres-backup
docker@minikube:/mnt/data/postgres-backup$ ls
postgres_backup_20250227101839.sql postgres_backup_20250227104217.sql
docker@minikube:/mnt/data/postgres-backup$ more postgres_backup_20250227101839.sql
--
-- PostgreSQL database dump
--
-- Dumped from database version 15.10 (Debian 15.10-1.pgdg120+1)
-- Dumped by pg_dump version 16.8 (Debian 16.8-1.pgdg120+1)
...
Automatic Cleanup for Finished Jobs
When your Job has finished, kubernetes will not delete the job. It's useful to keep that Job so that we can tell whether the Job succeeded or failed.
But after some given times we might want to cleanup that job. And kubernetes proved a way to do this using .spec.ttlSecondsAfterFinished
. Specify this field in the Job manifest/configuration, so that a Job can be cleaned up automatically some time after it finishes.
Lets try to add TTL configuration into our postgres-backup
job configuration. Edit the yaml
file, put this changes below (we set TTL to 60
).
...
spec:
ttlSecondsAfterFinished: 60
...
With this configuration the job will be deleted 1
minute after finished. Re-apply the configuration, and if after that the postgres-backup
job should be gone from the job list.
➜ kubectl apply -f postgres-backup-job.yaml
job.batch/postgres-backup configured
➜ kubectl get jobs
No resources found in default namespace.