Как сохранить работающий контейнер в Kubernetes?

124

Теперь я пытаюсь запустить простой контейнер с оболочкой (/ bin / bash) в кластере Kubernetes.

Я думал, что есть способ поддерживать работу контейнера в контейнере Docker, используя pseudo-ttyопцию и отсоединение ( -tdопция в docker runкоманде).

Например,

$ sudo docker run -td ubuntu:latest

Есть ли в Kubernetes такая возможность?

Я пробовал запустить контейнер с помощью такой kubectl run-containerкоманды:

kubectl run-container test_container ubuntu:latest --replicas=1

Но контейнер выходит на несколько секунд (точно так же, как запуск с помощью docker runкоманды без параметров, о которой я упоминал выше). И ReplicationController снова запускает его повторно.

Есть ли способ, чтобы контейнер работал в Kubernetes, как -tdпараметры в docker runкоманде?

Springwell
источник
Использование этого изображения (как предлагается в документации Kubernetes ) весьма удобно:kubectl run curl --image=radial/busyboxplus:curl -i --tty
Matheus Santana
Этот вопрос был упомянут в этом видео: Kubernetes очень сложный путь в Datadog с заголовком слайда «Культ карго» . Из википедии: термин « программист культа карго» может применяться, когда неквалифицированный или начинающий компьютерный программист (или неопытный в решении проблемы под рукой) копирует некоторый программный код из одного места в другое, практически не понимая, как он работает и требуется ли он в новом месте.
tgogos

Ответы:

50

Контейнер закрывается, когда завершается его основной процесс. Сделать что-то вроде:

docker run -itd debian

Откровенно говоря, держать контейнер открытым - это хитрость, которую следует использовать только для быстрых тестов и примеров. Если вам нужен контейнер для тестирования на несколько минут, я бы сделал:

docker run -d debian sleep 300

Это имеет то преимущество, что контейнер автоматически выйдет, если вы забудете об этом. В качестве альтернативы вы можете поместить что-то подобное в whileцикл, чтобы он работал вечно, или просто запустить приложение, например top. Все это должно быть легко сделать в Kubernetes.

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

Адриан Муат
источник
Спасибо за ваш ответ. Теперь я пытаюсь понять поведение контейнеров, когда одновременно работают десятки контейнеров. Бесконечный цикл и использование другой тяжелой команды не позволяют мне узнать, как ведут себя контейнеры. Вот почему мне нужен простой контейнер, например, только запуск / bin / bash.
Springwell
А пока я попробую запустить catбез аргументов topи sleepс аргументом большого числа.
Springwell
30
sleep infinityработает во многих случаях (не в busybox)
rwilson04
1
Для этого есть множество причин. Например, вы можете развернуть свои поды с выпусками Helm и внедренной конфигурацией, что сделает воссоздание подобных сред раздражающим и громоздким. Но наличие контейнера с такой конфигурацией на случай сбоя / удаления других модулей может быть бесконечно полезным.
Ричард Левехьерте
Потому что мой сервис состоит из нескольких процессов.
Константин Ван
135

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

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:latest
    # Just spin & wait forever
    command: [ "/bin/bash", "-c", "--" ]
    args: [ "while true; do sleep 30; done;" ]
Джоэл Б.
источник
Но это лучшая практика?
аниш Джоши
3
@aneeshjoshi Я бы не сказал, что это лучшая практика . Это всего лишь пример модуля, который будет работать без немедленного выхода. Лучше всего создавать контейнеры для выполнения той работы, для которой они были разработаны (работа, которая выполняется до конца, веб-сервер, который работает постоянно и т. Д.). Я разместил это в качестве примера, потому что Kubernetes может сначала расстраивать, когда вы продолжаете создавать поды только для того, чтобы они исчезли, поскольку команда по умолчанию завершается немедленно.
Joel B
@JoelB Спасибо. Мне было интересно, как это сделать «правильно».
аниш Джоши
1
спасибо за это, так как мне нужен контейнер, который может жить некоторое время, позволяя мне войти в него. Я пытался сделать то же самое с более светлым изображением, чем ubuntuи пробовал bashизображение, но не смог заставить его работать. Есть идеи, как сделать то же самое с bashизображением?
cryanbhu
1
@cryanbhu Для более светлого изображения вы можете использовать alpine, спецификация контейнера может выглядеть так: {"name": "util", "image": "alpine", "command": [ "/bin/sh", "-c", "--" ], "args": [ "while true; do sleep 30; done;" ]}(только json, потому что здесь yaml не будет форматироваться в комментариях). Важный бит /bin/shвместо /bin/bash.
bschlueter
111

Вы можете использовать этот CMD в своих Dockerfile:

CMD exec /bin/bash -c "trap : TERM INT; sleep infinity & wait"

Это сохранит ваш контейнер в живых до тех пор, пока он не остановится. Использование trap и wait заставит ваш контейнер немедленно реагировать на запрос остановки . Без прерывания / ожидания остановка займет несколько секунд.

Для изображений на основе busybox (используемых в изображениях на основе alpine) сон не знает аргумента бесконечности. Этот обходной путь дает тот же немедленный ответ, что docker stopи в приведенном выше примере:

CMD exec /bin/sh -c "trap : TERM INT; (while true; do sleep 1000; done) & wait"
itsafire
источник
Я использую то же самое в yaml развертывания kubernetes для целей отладки
sdkks
это дает мне «сон: недопустимое число 'бесконечность'»
arunkjn
@arunkjn Спасибо за это. Вы, вероятно, застряли с изображением, в котором используется busybox (например, изображения alpine). См. Обновленный ответ.
itsafire 04
25
  1. В вашем Dockerfile используйте эту команду:

    CMD ["sh", "-c", "tail -f /dev/null"]
    
  2. Создайте свой образ докера.

  3. Отправьте его в свой кластер или аналогичный, просто чтобы убедиться, что изображение доступно.
  4. kubectl run debug-container -it --image=<your-image>
    
Раду Габриэль
источник
Отличные советы по отладке контейнера.
kta
16

Чтобы POD продолжал работать, он должен выполнять определенную задачу, иначе Kubernetes сочтет это ненужным, поэтому он останавливается. Есть много способов сохранить работоспособность POD.

Я столкнулся с аналогичными проблемами, когда мне нужно было, чтобы POD просто работал непрерывно, не выполняя каких-либо полезных операций. Вот два способа, которые у меня сработали:

  1. Запуск команды сна при запуске контейнера.
  2. Запуск бесконечного цикла внутри контейнера.

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

Однако я опишу оба способа (учитывая, что вы используете контейнер busybox):

1. Команда сна

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  containers:
  - name: busybox
    image: busybox
    ports:
    - containerPort: 80
    command: ["/bin/sh", "-ec", "sleep 1000"]
  nodeSelector:
    beta.kubernetes.io/os: linux

2. Бесконечный цикл

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  containers:
  - name: busybox
    image: busybox
    ports:
    - containerPort: 80
    command: ["/bin/sh", "-ec", "while :; do echo '.'; sleep 5 ; done"]
  nodeSelector:
    beta.kubernetes.io/os: linux

Выполните следующую команду, чтобы запустить модуль:

kubectl apply -f <pod-yaml-file-name>.yaml

Надеюсь, поможет!

Arbaaz
источник
Могу я спросить, что такое сон? Это внутренняя команда Ubuntu? Или докер-команда?
Фараз
@Faraz Это команда оболочки Linux, она не специфична для докеров.
Арбааз,
11

Мне удалось заставить это работать с командой sleep infinityв Kubernetes, которая будет держать контейнер открытым. См. Этот ответ, чтобы узнать об альтернативах, если это не сработает.

rwilson04
источник
Это не дает ответа на вопрос. Чтобы критиковать или запросить разъяснения у автора, оставьте комментарий под его сообщением. - Из отзыва
Will
1
@ Уверен, что это так. sleep infinityсохраняет контейнер открытым, обеспечивая тот же тип функциональности, о котором задается вопрос (для большинства типов контейнеров). Он также предоставляет ссылку на альтернативы для случаев, когда эта конкретная команда не работает
rwilson04
Это было из обзора. Если вы добавите текст комментария к ответу, то это качественный ответ :) Моя первоначальная отметка / рекомендация была основана на том, что ваш комментарий не удался, что заставило меня подумать, что это должен был быть комментарий. Добавлено быстрое редактирование и проголосовали за.
Уилл
«... бесконечность сна в Kubernetes» - неосведомленное утверждение. Это означает, что на картинке нет ни юникса, ни докера.
mmla
11

Самая простая команда для манифеста модуля k8s, позволяющая запускать контейнер навсегда:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:latest
    # Just sleep forever
    command: [ "sleep" ]
    args: [ "infinity" ]
Влодек Б.
источник
5

Используйте эту команду внутри Dockerfile, чтобы контейнер работал в кластере K8s:

  • CMD хвост -f / dev / null
Омар Халед
источник
3

В моем случае модуль с initContainer не удалось инициализировать. Запуск, docker ps -aа затем docker logs exited-container-id-hereдал мне сообщение журнала, которое kubectl logs podnameне отображалось. Тайна раскрыта :-)

Стефан Л
источник
1

Для этого есть много разных способов, но один из самых элегантных :

kubectl run -i --tty --image ubuntu:latest ubuntu-test --restart=Never --rm /bin/sh
Иван Арацкий
источник
Почему вы считаете это самым элегантным решением?
mordowiciel
1

Мои несколько центов по этой теме. Предполагая, что kubectlэто работает, ближайшая команда, которая будет эквивалентна команде docker, которую вы упомянули в своем вопросе, будет примерно такой.

$ kubectl run ubuntu --image=ubuntu --restart=Never --command sleep infinity

Выше команда будет создавать единую Podв defaultпространстве имен , и он будет выполнять sleepкоманду сinfinity аргументом -за образом , вы будете иметь процесс , который запускается в контейнере на переднем плане угаснуть.

Послесловие, с которым вы можете взаимодействовать Pod, запустив kubectl execкоманду.

$ kubectl exec ubuntu -it -- bash

Этот метод очень полезен для создания ресурса Pod и специальной отладки.

Лукаш Дыновски
источник
1
Прекрасно работает. Не нужно --restart=Never, просто позвонитеkubectl run ubuntu --image=ubuntu -- sleep infinity
Ноам Манос