Home > Software design >  Why is the k8s container spec "command" field an array?
Why is the k8s container spec "command" field an array?

Time:10-28

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":

  1. One leads to the page Get a Shell to a Running Container, which I am not interested in. I am interested in the start-up command of the container.

  2. One mention is concerned with running several piped commands in a shell environment, however the provided example uses a single string: command: ["/bin/sh"].

  3. 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?

CodePudding user response:

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)

CodePudding user response:

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.

  • Related