в docker, tips

Docker совет №34: Разница между форматами CMD


Инструкция CMD может быть определена в двух форматах, которые называются exec и shell. Оба выполняют практически идентичные вещи, но все же между ними есть существенно различие. Давайте разберемся!

Заданная в exec-формате команда будет запущена «как есть», вместе со всеми переданными ей аргументами. Пример команды в exec-формате:

CMD ["gunicorn", "-c", "python:config.gunicorn", "hello.app:create_app()"]

Заданная в shell-формате команда запускается через shell-оболочку контейнера и позволяет использовать функционал самого shell (например, конвейер или &&). Пример такой команды:

CMD gunicorn -c "python:config.gunicorn" "hello.app:create_app()"

В теории, использование команд в shell-формате выглядит предпочтительнее, но могут возникнуть проблемы с корректной обработкой сигналов в docker-контейнере. Немного поясню: если вы запускаете команду в exec-формате, то выполнив внутри запущенного контейнера команду ps вы увидите:

PID   USER     TIME   COMMAND
  1   root     0:00   {gunicorn} /usr/local/bin/python /usr/local/bin/gunicorn
 15   root     0:02   {gunicorn} /usr/local/bin/python /usr/local/bin/gunicorn
188   root     0:00   ps

Если же вы запускаете команду в shell-формате, то картина будет выглядеть иначе:

PID   USER     TIME   COMMAND
  1   root     0:00   /bin/sh -c gunicorn -c python:config.gunicorn hello.app:create_app()
  6   root     0:00   {gunicorn} /usr/local/bin/python /usr/local/bin/gunicorn
 16   root     0:00   {gunicorn} /usr/local/bin/python /usr/local/bin/gunicorn
 29   root     0:00   ps

Разработчики docker советуют использовать именно exec-формат для запуска команд, везде, где это возможно. Если же вам крайне необходимо выполнять какие-либо shell-сценарии при старте docker-контейнера, используйте для этих целей ENTRYPOINT.

Что касается docker-compose, то есть возможность конвертации команд из shell-формата в exec-формат, и выглядеть это может так:

    command: >
      gunicorn -c "python:config.gunicorn" "hello.app:create_app()"

Или можно сразу задать команду в exec-формате:

    command: ["gunicorn", "-c", "python:config.gunicorn", "hello.app:create_app()"]

Добавить комментарий