Shell form и exec form это по сути два стиля написания команд в Dockerfile.

Форма Пример  
Shell form RUN apt-get update && apt-get install -y curl оболочечная (shell)
Exec form RUN [“apt-get”, “update”, “&&”, “apt-get”, “install”, “-y”, “curl”] исполняемая (exec)

Как видно из таблицы для человека более приятная форма shell, нет никаких разбивок и проще для написания.

Shell form

RUN apt-get update && apt-get install -y curl

Команда выше выполняется через оболочку, т.е. Docker в тайне от вас выполняет эту команду так /bin/sh -c "apt-get update && apt-get install -y curl".

Благодаря такому преобразованию можно использовать в команде &&, |, переменные, перенаправления (>, >>).

Но при выполнении команды в формате Shell процесс внутри контейнера будет не сама команда а оболочка, которая выполняет её (sh). Т.е. при передаче сигнала SIGTERM его получит сама оболочка, а не команда, вызываемая внутри неё.

🦴Dockerfile.shell

FROM ubuntu
CMD sleep 100
docker build -t shell:1.0 -f Dockerfile.shell .
docker run -it --name shellc shell:1.0

В другом терминале я зайду в контейнер и проверю запущенные процессы в контейнере.

docker exec shellc ps
PID TTY          TIME CMD
1 ?        00:00:00 sh
6 ?        00:00:00 sleep
7 ?        00:00:00 ps

Exec form

Теперь напишу туже самую команду, только в формате Exec.

🦴Dockerfile.exec

FROM ubuntu
CMD ["sleep", "100"]
docker build -t exec:1.0 -f Dockerfile.exec .
docker run -it --name execc exec:1.0

Теперь также выполню команду, которая выведет запущенные процессы внутри контейнера.

docker exec execc ps
PID   USER     TIME  COMMAND
1 root      0:00 sleep 100
6 root      0:00 ps

Из вывода видно, что тут главный процесс PID 1 — это sleep сам по себе, а не sh как в случае с Shell form, потому что напрямую вызывается команда, а не оборачивается в sh.

Где и что использовать?

На самом деле если разбираться более детально в этой теме, то можно легко запутаться. В целом я не вижу особого смысла делать большой акцент на этой теме, просто возьмите за правило, что:

  • Для RUN просто используйте shell вариант, например, RUN apt-get update. Конечно ничто на мешает записать эту команду в EXEC варианте (RUN [“apt-get”, “update”]), но зачем?
  • Для ENTRYPOINT наоборот используйте EXEC
  • Для CMD также используйте EXEC только если только не вынуждены использовать shell
  • Для ENTRYPOINT + EXEC используйте всегда EXEC

SHELL FORM vs EXEC FORM