Reputation: 666
I have the following Helm Job for a Django application to run the migrations and to collect the static files:
apiVersion: batch/v1
kind: Job
metadata:
name: django-app-job
labels:
app.kubernetes.io/name: django-app-job
helm.sh/chart: django-app
app.kubernetes.io/instance: staging-admin
app.kubernetes.io/managed-by: Tiller
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "1"
"helm.sh/hook-delete-policy": hook-succeeded,hook-failed
spec:
template:
metadata:
labels:
app.kubernetes.io/name: django-app-job
app.kubernetes.io/instance: foobar
spec:
restartPolicy: OnFailure
containers:
- name: django-app
command:
- "/bin/bash"
- "-c"
- "python3 ./manage.py migrate"
- "&&"
- "python3 ./manage.py collectstatic --noinput"
But this only executes the migrate to update the DB schema but it nevers run the collect static. Even if the migration run ok. The job doesn't fails because if not the upgrade will fail and that doesn't happens.
But if I change the command to this:
containers:
- name: django-app
command:
- "/bin/bash"
- "-c"
- "python3 ./manage.py migrate && python3 ./manage.py collectstatic --noinput"
now the jobs run the migrations and the collect static. What is the difference between the 2 commands?
Upvotes: 0
Views: 511
Reputation: 159485
At a low level, all Unix commands are actually executed as a sequence of words. Normally the shell splits up command lines into words for you, but in a Kubernetes manifest, you have to manually specify one word at a time.
In your example, the Bourne shell sh -c
option reads the next single word only and executes it as a command, applying the normal shell rules. Any remaining words are used as positional parameters if the command happens to use variables like $1
.
You can demonstrate this outside of Kubernetes in your local shell, using quoting to force the shell to break up words the way you want:
# Option one
'/bin/sh' '-c' 'echo foo' '&&' 'echo bar'
# Prints "foo"
# Option two
'/bin/sh' '-c' 'echo foo && echo bar'
# Prints "foo", "bar"
One trick that shows up somewhat often is to use YAML block scalars to write a single string across multiple lines, giving something that sort of looks like a shell script but isn't actually.
command: ['/bin/sh', '-c']
args: >-
python3 ./manage.py migrate
&&
python3 ./manage.py collectstatic --noinput
Upvotes: 2