How to set multiple commands in one yaml file with Kubernetes?
Solution 1
command: ["/bin/sh","-c"]
args: ["command one; command two && command three"]
Explanation: The command ["/bin/sh", "-c"]
says "run a shell, and execute the following instructions". The args are then passed as commands to the shell. In shell scripting a semicolon separates commands, and &&
conditionally runs the following command if the first succeed. In the above example, it always runs command one
followed by command two
, and only runs command three
if command two
succeeded.
Alternative: In many cases, some of the commands you want to run are probably setting up the final command to run. In this case, building your own Dockerfile is the way to go. Look at the RUN directive in particular.
Solution 2
My preference is to multiline the args, this is simplest and easiest to read. Also, the script can be changed without affecting the image, just need to restart the pod. For example, for a mysql dump, the container spec could be something like this:
containers:
- name: mysqldump
image: mysql
command: ["/bin/sh", "-c"]
args:
- echo starting;
ls -la /backups;
mysqldump --host=... -r /backups/file.sql db_name;
ls -la /backups;
echo done;
volumeMounts:
- ...
The reason this works is that yaml actually concatenates all the lines after the "-" into one, and sh runs one long string "echo starting; ls... ; echo done;".
Solution 3
If you're willing to use a Volume and a ConfigMap, you can mount ConfigMap data as a script, and then run that script:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: my-configmap
data:
entrypoint.sh: |-
#!/bin/bash
echo "Do this"
echo "Do that"
---
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: "ubuntu:14.04"
command:
- /bin/entrypoint.sh
volumeMounts:
- name: configmap-volume
mountPath: /bin/entrypoint.sh
readOnly: true
subPath: entrypoint.sh
volumes:
- name: configmap-volume
configMap:
defaultMode: 0700
name: my-configmap
This cleans up your pod spec a little and allows for more complex scripting.
$ kubectl logs my-pod
Do this
Do that
Solution 4
If you want to avoid concatenating all commands into a single command with ;
or &&
you can also get true multi-line scripts using a heredoc:
command:
- sh
- "-c"
- |
/bin/bash <<'EOF'
# Normal script content possible here
echo "Hello world"
ls -l
exit 123
EOF
This is handy for running existing bash scripts, but has the downside of requiring both an inner and an outer shell instance for setting up the heredoc.
Solution 5
I am not sure if the question is still active but due to the fact that I did not find the solution in the above answers I decided to write it down.
I use the following approach:
readinessProbe:
exec:
command:
- sh
- -c
- |
command1
command2 && command3
I know my example is related to readinessProbe, livenessProbe, etc. but suspect the same case is for the container commands. This provides flexibility as it mirrors a standard script writing in Bash.
Related videos on Youtube
scho
Updated on August 05, 2022Comments
-
scho almost 2 years
In this official document, it can run command in a yaml config file:
apiVersion: v1 kind: Pod metadata: name: hello-world spec: # specification of the pod’s contents restartPolicy: Never containers: - name: hello image: "ubuntu:14.04" env: - name: MESSAGE value: "hello world" command: ["/bin/sh","-c"] args: ["/bin/echo \"${MESSAGE}\""]
If I want to run more than one command, how to do?
-
Michael Hausenblas over 8 yearsYes, very valid, however, I think there are also good use cases to extend
command
as it overrides the Dockerfile'sEntrypoint
;) -
Oliver about 6 yearsVery cool, but I think it is simpler to have the script inline, just use multiline syntax. I show this in a separate answer.
-
aclowkay almost 6 yearsAny idea on how to do this with container lifecycle? It has no args
-
Tim Allclair almost 6 years@aclokay you can just specify the arguments as additional command strings. The separation between command & args in the Container is just to make overriding the arguments easier. They are functionally equivalent.
-
sekrett almost 6 yearsNice, but when you request an edit with kubectl, it will be in one line again. :)
-
aclowkay over 5 years@sekrett oh no ! :(
-
kellyfj over 5 yearsThis worked quite nicely - the key is the semicolon on each line. This is a particularly good solution when the commands are many and would be multiline with the solution above. Makes git diff a breeze
-
Jingpeng Wu over 5 yearsThis is what I was looking for. using the environment variable as arguments with this solution works nicely.
-
L3K0V almost 5 yearsWhat about when I need to pass double quotes. For example imagine this command: printf '%s @%s\n' "$(echo 'user')" "$(echo 'host')"
-
nelsonspbr almost 5 years+1 Beautiful, plus multi-line commands work perfectly:
command: ['/bin/bash', '-c']
args:
- exec &> /path/to/redirected/program.output;
` python /program.py` ` --key1=val1` ` --key2=val2` ` --key3=val3` -
Abdul over 4 yearswhat -c does here?
-
Tim Allclair over 4 years@Abdul it means run the script provided as an argument, rather than starting an interactive shell or loading the script from a file.
-
Yogi Ghorecha over 4 yearsif you keep
&
instead of&&
that means, it's not compulsory that the first command must be succeed.if first command is not succeed then it will go for the next, if you use&
like this:args: ["command one; command two & command three"]
-
GACy20 over 3 yearsThis makes no sense to me... Isn't
-c
an argument? Then why the heck would you put it insidecommand
and notargs
? Then why not put everything insidecommand
since that means thatcommand
does not have to contain only the executable but it can also add arguments... why bother separating the two? Why wouldn'tcommand: ["/bin/sh", "-c", "command one; command two && command three""]
work exactly like your example? This would make sense if you had to writecommand: "/bin/sh"
and thenargs: ["-c", "..."]
-
WurmD almost 3 yearsBut then if you go to edit the deployment yaml, it will be in one line, unreadable again
-
piscesgeek almost 3 yearsEditing a live resource with
kubectl edit
and the likes is an anti-pattern and a bad idea anyway. Your running configuration should always match what's written on your manifests. That's what declarative configuration and version control systems are for. -
prince yadav almost 3 yearshow we can setting up the heredoc?
-
prince yadav almost 3 yearsby doing that getting the while running
$SHELL
output:\bin\ash
-
lauksas over 2 yearsway cleaner and it works better, thanks for the idea.
-
orkenstein over 2 yearsThis is the most flexible solution
-
aandis over 2 yearsWhy are command and args of list type instead of string.
-
MEMark over 2 years@YogiGhorecha In sh/bash/zsh a single
&
means to run that command in the background. You are probably thinking of;
-
Krishna ps over 2 yearsthanks for the example
-
Krishna ps over 2 yearsthanks for the snippet.