Pull to refresh

Comments 85

Для ленивых, сделаю краткую выжимку: используйте свой entrypoint.sh и делайте там все, что захотите.
Поддерживаю. Я бы только поменял на что-то типа supervisord. Мне лично очень помогало на опеншифтовых контейнерах.
Это тогда будет дублирование функциональности.
Докер сам супервизором работать умеет и работает. Зачем еще один супервизор в контейнере?
Поддерживаю. Но иногда требуется запустить несколько процессов. И это немного лучше чем баш скрипт. Конечно это IMHO.
Граница, думаю, проходит где-то на том моменте, когда баш-скрипт начинает напоминать инит-систему. :)
docker контейнер и запуск более чем одного приложения в нем, ну это как бы даже не соответствует документации по docker, там написано что в одном контейнере лучше запускать не более одного приложения. Если у вас в контейнере надо делать крон, то это уже говорит о том что выбрали неправильный инструмент для решения задачи. Возьмите тогда LXC и будет счастье.
Именно так, большинство кто не читал документацию — пытаются использовать его как виртуальную машину пихая туда все сподряд, а это все лишь контейнер для одного приложения а все данные и логи он должен выкидывать наружу — а там уже можно и крон и прочее
а если в контейнера надо запускать consul-template, помимо основного сервиса?

по мне, consul-template, как и крон выносятся на хост тачку.
Хотя тут и есть вопросы с swarm и прочим.

мне в этом решении резко не понравилось, что
1) в этом случае контейнер перестаёт быть самодостаточной сущностью.
2) конфиг консул-темплейта на хосте становится сложным и зависит от состава запущенных контейнеров.
3) нужно монтировать внутрь ещё и конфиги.
т.е. выходит циклическая зависимость хост <-> контейнер, которую хотелось бы избежать.

1) точно так же он перестает ей быть, когда начинается решение неспецифических задач в нем. Например 2 сервиса, или куча шаблонизаторов конфигов.
2) я решил лейблами докер-сервиса
3) с моей точки зрения это гораздо удобнее, чем контролировать сервисы внутри.


Ну а так выходит непредсказуемость поведения контейнера.

1) генерация конфига для работоспособности содержимого — имхо вполне специфичная задача, которая имеет непосредственную связь 1 к 1 с сервисом.
2) а можно меня носом в мануал ткнуть, пожалуйста? я поизучаю на досуге.
3) это неудобно только тем, что неправильный шаблон может обнаружиться только после сборки тестинга (имеем поломанный билд). зато это очень удобно, что ты можешь выкинуть контейнер на любую машинку в и он сам себя правильно сконфигурит. Среда корректно определяется тем, какой консул-кластер — test / stage / prod.

1) опять же, ваш выбор. я разницы, где держать конфиги, не вижу. А вот доп сервисы в контейнере вижу.
2) https://docs.docker.com/engine/userguide/labels-custom-metadata/ отталкиваться от сюда. В swarm указываю, при старте конейнеров, условно, запустить 10 штук, на машина с лабелом блабла.
3) Опять же, не вижу тут проблем. Вопрос решается системой управления конфигурации.

Внесу небольшое дополнение по третьему пункту:


Конфигурация внутри контейнера — это совсем не удобно. Ее очень сложно быстро поменять, потому что нужно ждать пересборку контейнера, что бы сделать все правильно.

по факту значимые значения конфигурации хранятся в консуле и их можно прямо оттуда поменять на лету — consul-template сам перегенерит конфиг и передёрнет приложение.
А если ломается структура конфига — это так и так новый релиз => пересборка нового образа.
UFO just landed and posted this here
у меня конфигурация — это потенциально жирный json с метадатой, который нужно иногда менять быстро по желанию левой пятки заказчика.
Но при этом, ему не место в БД с обычными данными.
Прокидывать его через переменные окружения — чудовищная идея, которая ещё и принуждает меня контейнер рестартовать, когда можно дать команду на перечитывание конфига.
UFO just landed and posted this here
Оукееей. Допустим, это не моё приложение со специфичным конфигом. Например, rabbitmq или nginx, или тот же consul.
Т.е. любое стороннее приложение, разработчиков которого более чем устраивают простые текстовые файлы (иногда длинные).
consul-template пусть и неизящно, но позволяет подрихтовать конфиг на лету (без рестарта контейнера, что важно).

Или приложение уже давным-давно написано и не хочется лезть и менять в его код — мы просто пакуем его в контейнер, подкладываем рядом consul-template и небольшой entrypoint, который позаботится, чтоб всё хорошо стартовало-умирало.
Так мы относительно дёшево получаем неизменный артефакт для деплоя (здесь я мысленно проклял npm и миллиарды зависимостей).
А обучение приложения работать напрямую с consul по api — уже отдельная задача, которую можно спокойно выкинуть в беклог с невысоким приоритетом.
UFO just landed and posted this here
Важно, что костылей понадобилось немного — всё украдено за нас.

Докер даёт очень хорошую гарантию — в прод едут ровно те бинари и те npm-пакеты. которые проверялись на тестинге.
Плюс при грамотной упаковке элементов в контейнеры становится плевать, на какой физической машинке они бегут и сколько экземпляров одинакового сервиса поднято — и это тоже удобно.
Наши приложения в большинстве своём stateless, поэтому docker или аналоги напрашивались. Опять же на решение влияет хайп, количество готовых костылей и подпорок^W^W^W инструментов, чтоб это работало.
Это можно решать через зипованные образы lxc / openvz, но количество готовых костылей и подпорок для них меньше, чем для докера.
UFO just landed and posted this here
охотно верю. в будущем я осмотрюсь вокруг ещё раз и возможно выберу другой стек в соответствии с теми требованиями, которые будут стоять потом.
Вы правильно заметили, что внутри контейнера не рекомендуется запускать более одного приложения. И я не собираюсь утверждать обратное. Но ведь вас никто не заставляет внутри контейнера запускать больше одного cron задания. Тем более, если мы можем при старте указать любую необходимую конфигурацию (через инъекцию Environment Variables) для вашых cron скриптов и запустить столько контейнеров, сколько различных заданий у вас имеется.

И зачем мне использовать LXC, если у меня уже есть удобный, масштабируемый и единообразный для всех компонентов инструмент запуска приложений в контейнерах и проверенный временем и всем знакомый планировщик задач (cron)?
Тут фишка в том что не надо быть догматичным. Это хорошее правило…
Но вы решаете что такое «аппликация» и сколько процессов она должна стартануть что быть самодостаточной.
В «догме» нет ничего плохого, но важно понимать причину таких рекомендаций. В данном случае причиной является то, что Docker может управлять только одним процессом (с PID=1). Запуск нескольких служб внутри контейнера неизбежно приведет к тому, что внутри контейнера будет несколько служб с разными PID, что приведет к невозможности нормального функционирования контейнера.

Понимая проблему, можно находить решения, которые удачно вписываются в концепцию Docker, хотя на первый взгляд может показаться, что это не так.
что приведет к невозможности нормального функционирования контейнера
А в чём это будет проявлятся?
например, при остановке или перезапуске контейнера, все службы, у которых PID не равен 1, будут завершены некорректно, то есть без возможности закрыть открытые соединения, файлы, транзакции и пр.
Менеджер процессов решает это проблему полностью? На гитхабе туча докер сборок сделаных с помощью супервизора.
Я так полагаю, что решает.
trap «service cron stop; exit» SIGINT SIGTERM

Можно ведь тоже самое сделать для любых других процессов.

Пример с runit.
Можно, но запуск внутри контейнера служб никак несвязанных между собой создает уже неудобства в эксплуатации.
если запустить внутри пачку демонов тупо баш-скриптом, то остановить контейнер можно будет только по kill, что не есть хорошо — баш не сможет отправить сигналы демонам, которые от него отвязались.
Т.е. требуется что-то вроде supervisord для рулёжки процессами в контейнере.
Ну и неудобства в виде одного единственного stdout/stderr на весь контейнер, например.
Т.е. нужно лишний раз включать голову и решать вопросы, которых бы и не возникло, не пользуйся мы докером.
Один контейнер должен служить для конкретной задачи, но не для «одного приложения». Здесь неплохо этот момент описан. Так как нынче везде кричат про микросервисы, то рекомендую ещё смежную статью почитать Microservices — Not a free lunch!
docker контейнер и запуск более чем одного приложения в нем, ну это как бы даже не соответствует документации по docker, там написано что в одном контейнере лучше запускать не более одного приложения.


Приложения, сервиса… и не обезательно что это один процесс, хотя проще, да…
И вам решать что есть именно ваше приложение… Для микросервица очень вазжна акакрза его самодостаточность и его как можно меньшая зависимость от внешнего мира в плане конфигурации и прочих предположений о среде…

Честно говоря, я с трудом представляю юзкейсы, где такое надо (про велосипеды молчим). Мне видится более удобным вариантом запускать контейнер системным кроном. Возможно на выделенной тачке.

а если этот контейнер с cron сам дёргает по расписанию другие ручки в кластере? и совсем не хотелось бы, чтоб он умер вместе с машиной.
этакий кластер-менеджмент для бедных.

Мне думается это ошибка в архитектуре. Я не говорю о том, что таких кейсов не может быть. Но все таки контейнеру подразумевают какое-то CI и систему управления конфигурацией.

Ну мне подумалось, что это может быть аналогом kubernetes для бедных — дёргаем скриптами alive-чеки, смотрим где плохо или наоборот лишнее и в автоматическом режиме дёргаем ручки для масштабирования.
Это может быть вполне нормальным решением для портирования старой системы масштабирования вместо переезда на kubernetes / nomad / etc.

P.S. у нас джобы по расписанию запускаются контейнеров, только они сделаны велосипедными библиотеками для nodejs.

кстати, надо посомтреть поподробнее, что там предлагается.


Я думаю, что крон — это изменение данных в некой центральной точке. Потому проще держать отдельный инстанс.

наши крон-джобы — это наоборот, всякая периферия.
Досылка данных в очередь, если мгновенная отправка не прошла по какой-то причине (все сервисы должны уметь в семантику one or more), файлообмен с внешними системами итд.
Каждый адаптер для внешней системы — это отдельный сервис и нелогично отделять его работу по расписанию от него самого.

Возможно. Хотя мне кажется можно сделать иначе.

Это как раз тот случай, когда докер пытаются запихать туда, где его быть не должно.
думаю предадут анафеме, но в нынешнем виде докер почти не нужен в проде…
Он или много не умеет и нужны костыли или, что еще хуже, его пытаются запихнуть туда где он в принципе не нужен, но тупо моден сейчас

Вот либо я не умею готовить, либо руки кривые, либо еще что-то. Но факт остается фактом…


Пару лет назад, наверное, решил таки приспособить Vagrant для PHP разработки. Ведь все же кругом говорят о вагранте. Да и PhpStorm его круто поддерживает. Куча статей, мануалов, скринкастов… А MAMP же — это не круто, не модно и не молодежно. Началось уже не помню с чего, но, как оказалось, с Parallels (параллели использовал для запуска виндовой машины по работе, соответственно, без параллелей никак) Vagrant дружил не очень. Хорошо, давай ставить VirtualBox. Ой, VirtualBox не может жить вместе c Parallels? Пичалька… Ладно, давай разбираться как подружить Vagrant c параллелями. А, ну вот же, подружились! Запускаем!!! Ой, а чего так медленно читаем shared folder? Ведь параллели обещали, что все должно летать. Что, монитровать проект по ssh? Исходники на одной машине, а база на другой? Как-то непривычно. Ведь в MAMP'е же все лежит в одном месте! Э-э-э, ладно, MAMP, дружок, рано я от тебя отказался… Давай поработаем с тобой еще.


Настает время Docker'а. Все вокруг, докер, да докер. MS — Docker, AWS — Docker, все нарядно и молодежно! Да вот уже и готовые есть Dockerfile'ы и docker-compose для моих фреймворков. Как же хорошо-то! Ладно, давай пощупаем, что это за докер такой. А, не виртуалка… ага… понятно… слава тнб, не вагрант снова. Да и приходится на виндовом десктопе работать. А MySQL ставить на винду как-то не красиво… ОК, буду приспосабливать MySQL работать в Docker'е! Ага, понятно, $ docker run mysql. Ура!!! Заработало!!! Ой, а что это скорость у MySQL вапще никакая?! И это так у всех (после непродолжительного гугления)? Хорошо, Docker, я с тобой не прощаюсь. Но давай, всего хорошего тебе, до лучших времен.


В сухом остатке… ИМХО декларируемые фичи — это, безусловно, все очень круто и здорово. Но каждый раз натыкаешься на маленькие "но", которые практические перечеркивают все эти радости. И по сравнению с затраченным уже временем на ощупывание этих технологий быстрая сборка виртуалки в вагранте или мгновенный запуск контейнера докер уже не так греют душу.

Это вы зря так батенька резко, тут адепты секты docker. Рассказали бы народу про запуск Windows 95 в контейнере docker или других чудесах инженерной.
Про Vagrant:

Стоит заметить, что это лишь средство для конфигурации виртуальных машин, и ничего особо сложного он делает. Другое дело, что поддерживает не все возможности всех платформ, но про это можно было прочитать.

Про Docker:

На Windows в официальных релизах docker создает виртуальную машину с минимальным линуском и запускает все в ней. То есть к обычном докеру еще все проблемы вашей виртуалки приехали. Судя по предыдущему опыту, они от нее.
Докер не то решает что вы пытаетесь там ковырять.
Ну не нужен он вам, не используйте.
Вот тут может о том почему это не замена виртуалке и не об этом вообще
http://stackoverflow.com/questions/16047306/how-is-docker-different-from-a-normal-virtual-machine/25938347#25938347
Докер — это proof of concept, который оброс костылями и дополз до них до продакшена. :)

В rkt пытаются сделать то же самое правильно, вроде неплохо получается.
UFO just landed and posted this here
По моему мнению Docker запоздал так лет на 10. И его мнимая популярность держится на пиаре заинтересованных компаний. Как мы знаем, большинство готово «кушать» то, что им дают всякого рода гуру от маркетинга.

А вот от рынка виртуализации можно ожидать появления легковесных виртуальных машин, в Microsoft это уже сделали, начиная с Windows 2012 имеется такая фича. Что в конечном итоге и убьет хипсторские контейнеры.
Легковесные виртуалки (джейлы фряхи, openvz линукса, зоны в солярке) существуют и применяются значительно дольше, чем существует Docker.
Тем не менее контейнеры почему-то полетели.
Меня в докере подкупила идея разделения понятия образа и контейнера, а также иммутабельных слоёв ФС — это по-своему правильно и хорошо.
Стало на порядок проще воспроизводить тот бардак зависимостей (npm-пакетов), с которыми у меня сейчас сервис в проде работает — взял ворох докер-образов таких же, как на проде — и ковыряешь.
И докер не опоздал лет на 10, а пришёлся как раз вовремя — много компаний доросли до кластеров и начали задумываться над вопросом, а что делать, если нужно будет валить с одного облачного провайдера в другой.
Почему полетело: соглашусь с комментарием выше — в его пиар какое-то нереальное кол-во бабла влили. Его презентовали вообще везде и всюду — от самых маленьких приватных митапов до всемирных конференций, не пропустив, вроде, вообще ни одной.
Сам концепт то очень хорош, но уж больно костыльная реализация, что тоже выше уже заметили :)
docker при использовании docker-native сервисов работает в разы удобнее, чем при оркестрации через puppet+rpm.
Костыли начинаются, когда приходится поднимать сервисы, которым гораздо лучше без docker. Например, когда у сервиса есть любое внутреннее состояние, когда перезапуск != удалить контейнер и создать новый.
Стало на порядок проще воспроизводить тот бардак зависимостей (npm-пакетов)

Поэтому и взлетел, с Rails такая же ерунда.
можно ожидать появления легковесных виртуальных машин, в Microsoft это уже сделали, начиная с Windows 2012

В 2012 ускорили загрузку обычных ВМ, а в 2016 сделают поддержку docker. VMware умеет форкать ВМ и это тоже используется для docker в vSphere Integrated Containers (хз кто ими пользуется, но всё же).
Лишний раз доказывает, что IT-шный мир уже давно сошел с ума. Маркетинг преобладает над здравым смыслом.
С точки зрения администрирования докер оправдан как средство развёртывания ПО на современных фреймворках с кучей зависимостей (Nodejs, Rails, Go), чтобы не привязывать сборку к конкретным версиям и не писать километровые установочные скрипты.
А Instant Clones ещё используются для VDI, но это совсем другая тема.
Nodejs, Rails еще понятно, но как сюда попал go?
С ним то вообще проблем нет, есть бинарник и нет зависимостей!
Я не настоящий сварщик, но встречал нелестные отзывы в его сторону.
Можно много чего сказать хорошего и плохого, но зачем?
Лучше один раз увидеть, чем 100 раз услышать.
В отличии от комментаторов выше, я не вижу ничего странного в том, что в контейнере запускается нечто по расписанию. На мой взгля, во многих случаях это вовсе не «пытаются использовать его как виртуальную машину» и никак не противоречит мифической «документации по docker». Если, например, внутри контейнера живет процесс которому надо по расписанию нечто активировать, например обновить какие данные, нечто очистить/загрузить и прочее в этом роде, то дернуть процесс (сигналом либо каким прочим вызовом) из контейнерного крона вполне нормально, Идея делать это с хостовой машины — это, как мне кажется, совсем плохая идея, убивающая переносимость и прибивающая конкретный контейнер к конкретному инстансу ржавыми гвоздями.

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

У вас небольшая проблема в примере:
Если данные нужно скачивать на жесткий диск хостовой системы, то переносимость давно убита. А если оно просто прокидывается куда-то дальше, то разницы, откуда вызывать скрипт нет, то это можно делать и из хостовой машины.


Если брать более сложный случай, и нам нужна система, которая бы по расписанию запускала различные таски, написанные, скажем, на Python, то для таких задач есть более умные и простые системы, типа Celery или, скажем, nats.io.


Cron используют для простых задач, которые не требуют мониторинга, отслеживания и прочего. И тут не совсем понятно, какой будет профит от того, что бы обернем его в docker контейнер.

откуда, в моем примере, следует что данные надо скачивать и именно в файловую систему? Даже если и речь идет о подобных данных, то есть масса случаев когда они не персистент и это ответственность сервиса/контейнера их себе добыть. Это никак не ухудшает переносимость. Однако, в случаях когда данные прокидываются, тоже есть большая разница откуда вызывать скрипт. Если это скрипт (хотя я про скрипты ничего не говорил) делает нечто, что часть вашего сервиса, то его оторванность от вашего сервиса это совсем не тоже самое, как технически так и концептуально. И идея запускать это нечто на хосте, означает, что хост к такому должен быть подготовлен, что непонятно зачем надо. Ну и перенести это все просто средствами докера будет невозможно, т.к. часть работы делает внешний скрипт.

Есть много случаев, когда задачи по расписанию чего-то в контейнере – это его внутреннее дело. Например, есть микросервис, который раз в день берет немного данных из внешнего мира, парсит их и вносит новые в некий store, специально для этого сервиса существующий. А все остальное время этот сервис отдает данные по запросам. Мониторинг к этому всему слабо относится — т.е. он никак не мешает мониторить как процесс так и конечное состояние.
Как быть если cron должен иметь доступ к файловой системе проекта? Например, чтобы запускать там какие нибудь консольные скрипты.
Вы можете расширить ваш образ с проектом, добавив туда возможность запуска cron. И создавать контейнер с переопределенным cmd:
docker run --name cron --detach project_image start-cron

В этом случае cron заданиям будут доступна вся файловая система образа проекта.
Не совсем понял. Cron будет в том же контейнере что и основной проект? `start-cron` это какой то специальный баш скрипт?
start-cron да, это специальный скрипт. Он подробно описан в этой статье. Так вот этот скрипт, должен лежать в одном образе вместе с вашим проектом. После этого просто создаете два контейнера из одного образа:
docker run --detach --name project_container project_image
docker run --detach --name cron_container project_image start-cron
Все равно не понял. В вашем примере ведь контейнеры полностью изолированны. Как я в первом контейнере получу результат работы крона из второго контейнера? К примеру, в проекте есть какой нибудь консольный скрипт, который должен по крону парсить данные из внешнего источника и сохранять их в базу или на диск.
Если же вам нужна синхронизация между контейнерами в runtime, то для этого у docker есть опции --link, --volume, --volumes-from. Последняя опция позволяет подмонтировать в новый контейнер все точки монтирования из указанного существующего контейнера. Например, вот так делается общая папка /data для двух разных контейнеров:
docker run --detach --volume /var/project/data:/data --name project_container project_image
docker run --detach --volume /var/project/data:/data --name cron_container project_image start-cron

--link позволяет объединять контейнеры в общую сеть, позволяя им обращаться друг к другу по имени.
по поводу плясок вокруг «как крону передать env» — по моему можно несколько проще. В entrypoint сделать export > env.file а в кроне, в качестве SHELL, дать скрипт, который первым делом этот env.file применит.

Хм… а передача сразу в команду docker run параметра --env-file=[] не может помочь в таком случае?

помочь в каком случае? передать env в контейнер это не проблема, проблема – как передать env в cron

Хм, я думал что переменные из файлов окружения сразу полностью в него записываются и могут быть доступны везде. Или cron не может достучатся до глобального окружения?

cron бежит со своим окружением. это не специфика контейнера/докера, но крона

Спасибо большое за информацию, вот с таким раньше не сталкивался.

Да, такой вариант возможен. Но тогда надо будет всегда помнить о SHELL.
ну, строго говоря, мы тут и так городим свой entrypoint.sh. Без особого труда тут можно сделать и какой sed для автоматической замены SHELL на то, что надо, и больше об этом не думать.
Обновил статью. Подробности в самом тексте.
А появилось ли что-нибудь новое для запуска крон-джобов в Docker за последние три+ года? Мне, как .NET девелоперу без большого бекграунтда в командной строке Linux, смотря на описанное в статье, хочется написать простое консольное приложение с Quartz.NET и делать там все что нужно, понимая где логи, как они пишутся и пр. и пр.

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

Согласен. Но вопрос именно про Docker.
Понадобилось использовать крон в докере, крайне благодарен за статью! Без нее, не решил бы проблему.
Sign up to leave a comment.