How to Add Env Vars to a Kubernetes CronJob
A Kubernetes CronJob pod starts with a clean environment - it inherits nothing from your shell. If your backup Job can't reach the S3 endpoint, the fix is an explicit env: block in the CronJob manifest.
Why the Job pod can't reach S3
When you run aws s3 ls s3://db-snapshots/ in your terminal it works fine - because
your shell has AWS_ENDPOINT_URL, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY
exported. But a CronJob pod is not your shell. Every container starts with only
the env vars the manifest explicitly defines. If env: is absent, boto3 and the
AWS CLI see nothing - no endpoint URL, no credentials - and the Job fails before
writing a single byte.
The error in kubectl logs job/<name> will say something like:
botocore.exceptions.NoRegionError: You must specify a region.
or a connection/DNS error pointing at the default AWS endpoints instead of the local S3-compatible service.
Triggering a manual Job to read the logs
You don't have to wait for the schedule to fire:
kubectl create job --from=cronjob/db-snapshot debug-1
kubectl logs job/debug-1
--from=cronjob/<name> creates a one-off Job with the same pod spec as the
CronJob. Once you see the error, you know what env vars are missing.
Adding the env block to the CronJob
Open the CronJob manifest and add an env: block to the container that runs
the backup script:
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-snapshot
spec:
schedule: "0 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: snapshot
image: backup-image:latest
command: ["python3", "/app/snapshot.py"]
env:
- name: AWS_ENDPOINT_URL
value: http://moto-endpoint:5000
- name: AWS_ACCESS_KEY_ID
value: test
- name: AWS_SECRET_ACCESS_KEY
value: test
- name: AWS_DEFAULT_REGION
value: us-east-1
restartPolicy: Never
Apply it, then trigger a new Job to confirm it completes:
kubectl apply -f cronjob.yaml
kubectl create job --from=cronjob/db-snapshot retry-1
kubectl wait --for=condition=complete job/retry-1 --timeout=60s
kubectl logs job/retry-1
kubectl wait blocks until the Job reaches Complete (exit 0) or the timeout
fires. If it completes cleanly, the backup ran. Confirm with:
aws s3 ls s3://db-snapshots/
In production: pull credentials from a Secret
Hardcoding credentials in a manifest is a development shortcut - fine for a
local S3 mock, not for production. The production pattern uses envFrom with
a secretRef so the values never appear in the manifest or in kubectl get:
envFrom:
- secretRef:
name: aws-backup-creds
Many teams go further and use IRSA (IAM Roles for Service Accounts) or Workload Identity so the pod receives short-lived STS credentials automatically and you never manage static keys at all.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Adding an
env:block to a CronJob container so it can reach an AWS-compatible endpoint - Triggering a manual Job from a CronJob with
kubectl create job --from=cronjob/... - Reading Job pod logs with
kubectl logs job/<name>to diagnose env-related failures
FAQ
Why does a Kubernetes CronJob pod not have my shell's env vars?
Every container gets a clean, isolated environment. Shell exports are process-local and never propagate to spawned containers. The only env vars a pod sees are those explicitly listed in the manifest's env: or envFrom: fields.
How do I add AWS credentials to a Kubernetes CronJob?
Add an env: block under the container spec with AWS_ENDPOINT_URL, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_DEFAULT_REGION. In production, reference a Kubernetes Secret via envFrom: secretRef: instead of hardcoding values.
How do I manually trigger a Kubernetes CronJob to test it?
Run kubectl create job --from=cronjob/<name> <job-name>. This creates a one-off Job using the same pod spec as the CronJob, so you can read its logs immediately without waiting for the schedule.
What is a Kubernetes CronJob?
A Kubernetes CronJob runs a Job on a cron schedule - it creates a pod at each scheduled time to run a task (backups, reports) and cleans up finished pods. It is the in-cluster equivalent of a crontab entry.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →