Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Docker run a command without invoking a command shell?

I'm learning about Docker at the moment, and going through the Dockerfile reference, specifically the RUN instruction. There are two forms of RUN - the shell form, which runs the command in a shell, and the exec form, which "does not invoke a command shell" (quoted from the Note section).

If I understood the documentation correctly, my question is - If, and how can, Docker run a command without a shell?

Note that the answers to Can a command be executed without a shell?'s don't actually answer the question.

like image 502
dayuloli Avatar asked Feb 15 '17 18:02

dayuloli


2 Answers

If I understand your question correctly, you're asking how something can be run (specifically in the context of docker) without invoking a command shell.

The way things are run in the linux kernel are usually using the exec family of system calls.

You pass it the path to the executable you want to run and the arguments that need to be passed to it via an execl call for example.


This is actually what your shell (sh, bash, ksh, zsh) does under the hood anyway. You can observe this yourself if you run something like strace -f bash -c "cat /tmp/foo"

In the output of that command you'll see something like this:

execve("/bin/cat", ["cat", "/tmp/foo"], [/* 66 vars */]) = 0

What's really going on is that bash looks up cat in $PATH, it then finds that cat is actually an executable binary available at /bin/cat. It then simply invokes it via execve. and the correct arguments as you can see above.

You can trivially write a C program that does the same thing as well. This is what such a program would look like:

#include<unistd.h>

int main() {

    execl("/bin/cat", "/bin/cat", "/tmp/foo", (char *)NULL);

    return 0;
}

Every language provides its own way of interfacing with these system calls. C does, Python does and Go, which is what's used to write Docker for the most part, does as well. A RUN instruction in the docker likely translates to one of these exec calls when you hit docker build. You can run an strace -f docker build and then grep for exec calls in the log to see how the magic happens.


The only difference between running something via a shell and directly is that you lose out on all the fancy stuff your shell will do for you, such as variable expansion, executable searching etc.

like image 80
ffledgling Avatar answered Sep 21 '22 20:09

ffledgling


A program can execute another program without a shell; you just create a new process and load an executable onto it, so you don't need the shell for that. The shell is needed for a user to start a program because it is the user interface to the system. Also, a program is not able to run a built-in command like cd or rm without a shell because there's no executable to be found (there are alternative ways, thought, but not as simple).

like image 20
Fabio Ceconello Avatar answered Sep 21 '22 20:09

Fabio Ceconello