我为Django应用程序提供了以下Helm Job,以运行迁移并收集静态文件:
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"
但这仅执行迁移以更新数据库模式,但从不运行collect static。即使迁移运行正常。这项工作不会失败,因为如果升级失败,那升级就不会失败。
但是如果我将命令更改为此:
containers:
- name: django-app
command:
- "/bin/bash"
- "-c"
- "python3 ./manage.py migrate && python3 ./manage.py collectstatic --noinput"
现在,作业将运行迁移并收集静态数据。这两个命令有什么区别?
答案 0 :(得分:2)
从根本上来说,所有Unix命令实际上都是按单词序列执行的。通常情况下,shell会为您将命令行分割成多个单词,但是在Kubernetes清单中,您必须一次手动指定一个单词。
在您的示例中,Bourne shell sh -c
option仅读取下一个单词,并应用正常的shell规则将其作为命令执行。如果该命令碰巧使用了$1
之类的变量,则所有剩余的单词都将用作位置参数。
您可以在本地Shell的Kubernetes外部进行演示,使用引号强制Shell分解所需的单词:
# Option one
'/bin/sh' '-c' 'echo foo' '&&' 'echo bar'
# Prints "foo"
# Option two
'/bin/sh' '-c' 'echo foo && echo bar'
# Prints "foo", "bar"
经常出现的一个技巧是使用YAML block scalars在多行中编写单个字符串,从而提供类似于shell脚本的内容,但实际上并非如此。
command: ['/bin/sh', '-c']
args: >-
python3 ./manage.py migrate
&&
python3 ./manage.py collectstatic --noinput