Search code examples
linuxkubernetessh

Why I have to specify - sh - -c - command instead of just - command in k8s livenessProbe exec command (and potentially elsewhere)


I'm trying to exec command in livenessProbe, I have connected to the container interactively and tested the command: exit $(test $(date +%H) -eq 3 && echo 1 || echo 0) which produced the desired result, however when I specify livenessProbe:

livenessProbe:
  exec:
    command:
    - exit $(test $(date +%H) -eq 3 && echo 1 || echo 0)

it produces an error:

(combined from similar events): Liveness probe errored: rpc error: code = Unknown desc = failed to exec in container: failed to start exec "53fd8ffa05772ae7cebf99fadbf3767d902e40a58a8910f3fd501cfc8a65757d": OCI runtime exec failed: exec failed: unable to start container process: exec: "exit $(test $(date +%H) -eq 3 && echo 1 || echo 0)": executable file not found in $PATH: unknown

it works fine with:

livenessProbe:
  exec:
    command:
    - sh
    - -c
    - exit $(test $(date +%H) -eq 3 && echo 1 || echo 0)

I want to understand why is that the case? Are there cases where I don't need to specify (ba)sh -c ?


Solution

  • A script written in a language is not the program that is used to run it.

    Let's instead of shell, imagine python. Imagine:

    livenessProbe:
      exec:
        command:
          - import datetime; exit(datetime.datetime.now().hour == 3)
    

    You would expect a lot of errors. The command contains the command to execute, not a script written in some langauge.

    what kubernetes does differently compared to how that command is executed when pasted in the console

    Inside console (the terminal application) there is a shell running. You type your command inside the shell which the shell (the program connected to your terminal program) displays what you type for you and then the shell interprets what you type. You can type in your shell to try to execute a command named exit $(test $(date +%H) -eq 3 && echo 1 || echo 0) by applying appropriate quoting. The quoting depends on the shell that you are using, many people use different shell. In Bash:

    $ 'exit $(test $(date +%H) -eq 3 && echo 1 || echo 0)'
    -bash: exit $(test $(date +%H) -eq 3 && echo 1 || echo 0): command not found
    

    Which is the same error as executable file not found you see from docker, as in bash is not able to find the command named exit $(test $(date +%H) -eq 3 && echo 1 || echo 0) in PATH.

    This is the command that kubernetes tries to execute. Instead, you want to execute a program that interprets that script. As the code you posted is a shell script - contains such constructs as $( or && or || , you have to run the shell to interpret it, just like you would run python to interpret a python script or perl to interpret perl script.

    In many contexts (some) shell is the interpreter run implicitly, always, for example system() from C programming language or when doing ssh. In many context you do not what shell this is, for example gitlab-ci.yml executes bash or sh depending on what is available. But in many contexts, like when doing exec in C programming language, you specify the actual program to execute.

    You might be interested in: https://en.wikipedia.org/wiki/Shell_(computing) https://en.wikipedia.org/wiki/Interpreter_(computing) https://en.wikipedia.org/wiki/Exec_(system_call) https://man7.org/linux/man-pages/man3/system.3.html .