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?
10 Answers
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.
9My 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;".
6If 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-configmapThis cleans up your pod spec a little and allows for more complex scripting.
$ kubectl logs my-pod
Do this
Do that 3 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 EOFThis 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.
3I 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 && command3I 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.
IMHO the best option is to use YAML's native block scalars. Specifically in this case, the folded style block.
By invoking sh -c you can pass arguments to your container as commands, but if you want to elegantly separate them with newlines, you'd want to use the folded style block, so that YAML will know to convert newlines to whitespaces, effectively concatenating the commands.
A full working example:
apiVersion: v1
kind: Pod
metadata: name: myapp labels: app: myapp
spec: containers: - name: busy image: busybox:1.28 command: ["/bin/sh", "-c"] args: - > command_1 && command_2 && ... command_n 2 Here is my successful run
apiVersion: v1
kind: Pod
metadata: labels: run: busybox name: busybox
spec: containers: - command: - /bin/sh - -c - | echo "running below scripts" i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done name: busybox image: busybox Here is one more way to do it, with output logging.
apiVersion: v1
kind: Pod
metadata: labels: type: test name: nginx
spec: containers: - image: nginx name: nginx volumeMounts: - name: log-vol mountPath: /var/mylog command: - /bin/sh - -c - > i=0; while [ $i -lt 100 ]; do echo "hello $i"; echo "$i : $(date)" >> /var/mylog/1.log; echo "$(date)" >> /var/mylog/2.log; i=$((i+1)); sleep 1; done dnsPolicy: ClusterFirst restartPolicy: Always volumes: - name: log-vol emptyDir: {} 1 Here is another way to run multi line commands.
apiVersion: batch/v1 kind: Job metadata: name: multiline spec: template: spec: containers: - command: - /bin/bash - -exc - | set +x echo "running below scripts" if [[ -f "if-condition.sh" ]]; then echo "Running if success" else echo "Running if failed" fi name: ubuntu image: ubuntu restartPolicy: Never backoffLimit: 1
Just to bring another possible option, secrets can be used as they are presented to the pod as volumes:
Secret example:
apiVersion: v1
kind: Secret
metadata: name: secret-script
type: Opaque
data: script_text: <<your script in b64>>Yaml extract:
....
containers: - name: container-name image: image-name command: ["/bin/bash", "/your_script.sh"] volumeMounts: - name: vsecret-script mountPath: /your_script.sh subPath: script_text
.... volumes: - name: vsecret-script secret: secretName: secret-scriptI know many will argue this is not what secrets must be used for, but it is an option.