Command и args в спеке контейнера
Как поля command и args перебивают ENTRYPOINT и CMD образа и почему контейнер иногда уходит в Completed за секунду.
Что такое command и args
У каждого Docker-образа есть две точки входа. ENTRYPOINT - главный
исполняемый файл. CMD - аргументы к нему. Без переопределения
контейнер выполняет ENTRYPOINT + CMD.
В Kubernetes эти две точки переопределяют поля command и args в
spec контейнера. Соответствие однозначное: ENTRYPOINT в Dockerfile
отвечает полю command, CMD отвечает полю args.
Заданное command перебивает ENTRYPOINT. Заданное args перебивает
CMD. Можно задать только одно поле, оба, или ничего. Если не задано
ничего, работает то, что зашито в образ.
Минимальный YAML
containers:
- name: shouter
image: busybox:1.36
command: ["sh"]
args: ["-c", "echo hi; sleep 3600"]
Внутри контейнера выполнится sh -c 'echo hi; sleep 3600'. Значение
command становится argv[0] (имя самого процесса в списке аргументов).
Значения args - всё остальное.
Четыре случая
- Не заданы ни
command, ниargs. ЗапуститсяENTRYPOINT + CMDиз образа. Обычный путь. - Задан только
command. ENTRYPOINT перебит, CMD взят из образа. Случай редкий и опасный: свойcommandплюс чужойCMDдают неожиданную строку. - Задан только
args. ENTRYPOINT из образа, аргументы свои. Так делают, когда образ собран правильно и нужно поменять только параметры. - Заданы оба поля. Запуск из образа полностью игнорируется.
Почему busybox без аргументов завершается
У образа busybox ENTRYPOINT пуст, а CMD - это sh. Без
аргументов контейнер запускает sh, тот видит, что stdin (стандартный ввод) не
интерактивный, и сразу выходит. Pod за секунду уходит в Completed.
То же происходит с alpine, debian-slim и любым образом, где по
умолчанию запускается shell. Чтобы Pod жил, нужен sleep или бесконечный
цикл. Поэтому в примерах часто встречается sleep 3600 или
while true; do sleep 30; done.
Кавычки и массивы
В YAML command и args - это списки строк. Каждый элемент списка
становится отдельным argv. Поэтому такая запись:
command: ["sh", "-c", "echo hi; sleep 3600"]
Это три аргумента: sh, -c, и одна строка echo hi; sleep 3600.
Символы ;, &&, | внутри строки интерпретирует sh, а не
Kubernetes.
YAML сам приводит строку к числу: command: [echo, "01"] без кавычек
превращается в [echo, 1]. Значения кавычат.
Частая ошибка:
command: ["sh", "-c", "echo", "hi; sleep 3600"]
Здесь четыре аргумента. sh -c ждёт одну строку, а получает echo.
Он выполнит пустую команду, а hi; sleep 3600 уйдёт в argv[0] и не
исполнится. Результат не тот, что задумано.
верно, 3 элемента:
["sh","-c","echo hi; sleep 3600"]
sh -c получает скрипт целиком
ошибка, 4 элемента:
["sh","-c","echo","hi; sleep 3600"]
sh -c получает только echo
остальное уходит в argv0
Если есть сомнения, весь скрипт собирают одной строкой после sh -c
и не дробят его. Так меньше шансов сломать экранирование.
Связанные команды
kubectl logs <pod>
kubectl describe pod <pod> # видно Command и Args в Containers
kubectl exec <pod> -- ps aux # что реально запустилось
kubectl get pod <pod> -o jsonpath='{.spec.containers[0].command}'
kubectl explain pod.spec.containers.args
Что часто ломается
- Pod в Completed за секунду. Entrypoint - shell, аргументов нет,
shell вышел. Нужны
commandплюсargsили sleep. argsбезcommand. У образа странный entrypoint, и аргументы склеиваются неправильно. Оба поля задают явно.
Домашка
Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-commands-and-args # развернуть стартовое состояние
./run.sh verify k8s-commands-and-args # проверить текущий шаг
Коротко
commandперебивает ENTRYPOINT образа,argsперебивает CMD.- Оба поля это списки строк, каждый элемент становится отдельным аргументом.
sh -cждёт весь скрипт одной строкой, дробить его нельзя.- Образы с shell по умолчанию сразу выходят: Pod уходит в Completed, пока не добавят sleep или цикл.
- Что реально запустилось, видно в
kubectl describe podиkubectl exec -- ps aux.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс