According to this official kubernetes documentation page, it is possible to provide "a command" and args to a container.
The page has 13 occurrences of the string "a command" and 10 occurrences of "the command" -- note the use of singular.
There are (besides file names) 3 occurrences of the plural "commands":
One mention is concerned with running several piped commands in a shell environment, however the provided example uses a single string: command: ["/bin/sh"]
.
The third occurrence is in the introductory sentence:
This page shows how to define commands and arguments when you run a container in a Pod.
All examples, including the explanation of how command
and args
interact when given or omitted, only ever show a single string in an array. It even seems to be intended to use a single command
only, which would receive all specified args
, since the field is named with a singular.
The question is: Why is this field an array?
I assume the developers of kubernetes had a good reason for this, but I cannot think of one. What is going on here? Is it legacy? If so, how come? Is it future-readiness? If so, what for? Is it for compatibility? If so, to what?
Edit:
As I have written in a comment below, the only reason I can conceive of at this moment is this: The k8s developers wanted to achieve the interaction of command
and args
as documented AND allow a user to specify all parts of a command in a single parameter instead of having a command span across both command
and args
.
So essentially a compromise between a feature and readability.
Can anyone confirm this hypothesis?
I think the reason the command
field is an array is because it directly overrides the entrypoint of the container (and args
the CMD) which can be an array, and should be one in order to use command
and args
together properly (see the documentation)
Because the execve(2) system call takes an array of words. Everything at a higher level fundamentally reduces to this. As you note, a container only runs a single command, and then exits, so the array syntax is a native-Unix way of providing the command rather than a way to try to specify multiple commands.
For the sake of argument, consider a file named a file; with punctuation
, where the spaces and semicolon are part of the filename. Maybe this is the input to some program, so in a shell you might write
some_program 'a file; with punctuation'
In C you could write this out as an array of strings and just run it
char *const argv[] = {
"some_program",
"a file; with punctuation", /* no escaping or quoting, an ordinary C string */
NULL
};
execvp(argv[0], argv); /* does not return */
and similarly in Kubernetes YAML you can write this out as a YAML array of bare words
command:
- some_program
- a file; with punctuation
Neither Docker nor Kubernetes will automatically run a shell for you (except in the case of the Dockerfile shell form of ENTRYPOINT
or CMD
). Part of the question is "which shell"; the natural answer would be a POSIX Bourne shell in the container's /bin/sh
, but a very-lightweight container might not even have that, and sometimes Linux users expect /bin/sh
to be GNU Bash, and confusion results. There are also potential lifecycle issues if the main container process is a shell rather than the thing it launches. If you do need a shell, you need to run it explicitly
command:
- /bin/sh
- -c
- some_program 'a file; with punctuation'
Note that sh -c
's argument is a single word (in our C example, it would be a single entry in the argv
array) and so it needs to be a single item in a command:
or args:
list. If you have the sh -c
wrapper it can do anything you could type at a shell prompt, including running multiple commands in sequence. For a very long command it's not uncommon to see YAML block-scalar syntax here.