1. Обзор
В Dockerfile мы часто сталкиваемся с такими инструкциями, как run
, cmd
или entrypoint
. На первый взгляд, все они используются для указания и запуска команд. Но какая между ними разница? И как они взаимодействуют друг с другом?
В этом уроке мы ответим на эти вопросы. Мы представим, что делает каждая из этих инструкций и как они работают. Мы также рассмотрим, какую роль они играют в создании образа и запуске контейнера Docker .
2. Настройка
Для начала создадим скрипт log-event.sh.
Он просто добавляет одну строку в файл, а затем печатает ее:
#!/bin/sh
echo `date` $@ >> log.txt;
cat log.txt;
А теперь давайте создадим простой Dockerfile:
FROM alpine
ADD log-event.sh /
Он будет использовать наш скрипт, добавляя строки в log.txt
в различных сценариях.
3. Команда запуска
Инструкция запуска
выполняется, когда мы собираем образ. Это означает, что команда, переданная для запуска,
выполняется поверх текущего изображения в новом слое. Затем результат фиксируется на изображении. Давайте посмотрим, как это выглядит в действии.
Во-первых, мы добавим инструкцию запуска
в наш Dockerfile:
FROM alpine
ADD log-event.sh /
RUN ["/log-event.sh", "image created"]
Во-вторых, давайте создадим наш образ с помощью:
docker build -t myimage .
Теперь мы ожидаем получить образ Docker, содержащий файл log.txt
с одной строкой созданного изображения
внутри. Давайте проверим это, запустив контейнер на основе образа:
docker run myimage cat log.txt
При просмотре содержимого файла мы увидим такой вывод:
Fri Sep 18 20:31:12 UTC 2020 image created
Если мы запустим контейнер несколько раз, мы увидим, что дата в нашем лог-файле не меняется. Это имеет смысл, поскольку шаг запуска
выполняется во время сборки образа , а не во время выполнения контейнера.
Давайте теперь снова построим наше изображение. Мы замечаем, что время создания в нашем журнале не изменилось. Это происходит потому, что Docker кэширует результат выполнения инструкции , если Dockerfile не изменился. Если мы хотим аннулировать кеш, нам нужно передать параметр –no-cache
команде сборки.
4. Команда cmd
С помощью инструкции cmd
мы можем указать команду по умолчанию, которая выполняется при запуске контейнера. Давайте добавим запись cmd
в наш Dockerfile и посмотрим, как это работает:
...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]
После создания образа давайте теперь запустим его и проверим вывод:
$ docker run myimage
Fri Sep 18 18:27:49 UTC 2020 image created
Fri Sep 18 18:34:06 UTC 2020 container started
Если мы запустим это несколько раз, мы увидим, что запись о созданном образе
остается неизменной. Но контейнер запускал
обновления записей при каждом запуске. Это показывает, как cmd
действительно выполняется каждый раз при запуске контейнера.
Обратите внимание, что на этот раз мы использовали немного другую команду запуска docker
для запуска нашего контейнера. Давайте посмотрим, что произойдет, если мы запустим ту же команду, что и раньше:
$ docker run myimage cat log.txt
Fri Sep 18 18:27:49 UTC 2020 image created
На этот раз cmd
, указанный в Dockerfile, игнорируется. Это потому, что мы указали аргументы для команды запуска docker
.
Давайте продолжим и посмотрим, что произойдет, если у нас есть более одной записи cmd
в Dockerfile. Давайте добавим новую запись, которая будет отображать другое сообщение:
...
RUN ["/log-event.sh", "image created"]
CMD ["/log-event.sh", "container started"]
CMD ["/log-event.sh", "container running"]
После создания образа и повторного запуска контейнера мы получим следующий вывод:
$ docker run myimage
Fri Sep 18 18:49:44 UTC 2020 image created
Fri Sep 18 18:49:58 UTC 2020 container running
Как мы видим, записи о запуске контейнера
нет, только работающий
контейнер .
Это потому, что вызывается только последний cmd, если указано более одного.
5. Команда точки входа
Как мы видели выше, cmd
игнорируется при передаче каких-либо аргументов при запуске контейнера. Что, если мы хотим большей гибкости? Допустим, мы хотим настроить добавляемый текст и передать его в качестве аргумента команде запуска docker
. Для этого воспользуемся точкой входа.
Мы укажем команду по умолчанию для запуска при запуске контейнера. Более того, теперь мы можем предоставлять дополнительные аргументы.
Давайте заменим запись cmd
в нашем Dockerfile на точку входа:
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT ["/log-event.sh"]
Теперь давайте запустим контейнер, предоставив пользовательскую текстовую запись:
$ docker run myimage container running now
Fri Sep 18 20:57:20 UTC 2020 image created
Fri Sep 18 20:59:51 UTC 2020 container running now
Мы можем видеть, как точка входа
ведет себя аналогично cmd .
Кроме того, это позволяет нам настроить команду, выполняемую при запуске.
Как и в случае с cmd
, в случае нескольких записей точек
входа учитывается только последняя.
6. Взаимодействие между cmd
и точкой входа
Мы использовали как cmd
, так и точку входа
, чтобы определить команду, выполняемую при запуске контейнера. Давайте теперь продолжим и посмотрим, как использовать cmd
и точку входа
в комбинации.
Одним из таких вариантов использования является определение аргументов по умолчанию для точки входа.
Давайте добавим запись cmd
после точки входа в наш Dockerfile :
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT ["/log-event.sh"]
CMD ["container started"]
Теперь давайте запустим наш контейнер без каких-либо аргументов и со значениями по умолчанию, указанными в cmd
:
$ docker run myimage
Fri Sep 18 21:26:12 UTC 2020 image created
Fri Sep 18 21:26:18 UTC 2020 container started
Мы также можем переопределить их, если выберем это:
$ docker run myimage custom event
Fri Sep 18 21:26:12 UTC 2020 image created
Fri Sep 18 21:27:25 UTC 2020 custom event
Следует отметить различное поведение точки входа
при использовании в форме оболочки. Давайте обновим точку входа в нашем Dockerfile :
...
RUN ["/log-event.sh", "image created"]
ENTRYPOINT /log-event.sh
CMD ["container started"]
В этой ситуации при запуске контейнера мы увидим, как Docker игнорирует любые аргументы, переданные либо в docker run,
либо в cmd
.
7. Заключение
В этой статье мы увидели различия и сходства между инструкциями Docker: run
, cmd
и entrypoint
. Мы наблюдали, в какой момент они вызываются. Кроме того, мы рассмотрели их использование и то, как они работают вместе.