Pull to refresh

Comments 86

Я нырнул в мир Docker буквально пару месяцев назад и это просто потрясающе! Кроме того, что я построил проект, который благодаря Docker стал модульным, безопасным и прекрасным, я наконец смог переехать на Arch Linux благодаря тому, что теперь я и у себя на ноуте могу с минимальными накладными расходами (виртуалка с Linux на Linux мне не нравилась совсем, а с chroot много мороки) иметь окружение идентичное с боевыми серверами.

Тема управления кластеров с Docker контейнерами сейчас особенно популярна, лично я остановился на Docker Swarm. Преимущества:
  • официально поддерживается Docker
  • прост в настройке и использовании

К недостаткам Docker Swarm я бы отнёс:
  • возможно, слишком прост для построения изолированных инфраструктур
  • возможно, команде Docker лучше было бы фокусироваться на самом Docker, а не распылять усилия и заходить на территорию kerbernetes/fleet/mesos/...

Лично мне Docker Swarm нравится и пока что я им доволен как никогда. А какие у вас мысли по этому поводу? Стоит ли морочиться с Kubernetes для кластера из 10 машин?
Я рассматривал Docker Swarm когда выбирал систему управления контейнерами. Выбор между Kubernetes и Docker Swarm сводится к необходимому функционалу. Это связано с тем, что изначальные задачи у них различаются.
Docker Swarm — способ использовать несколько машин как единую виртуальную среду для запуска контейнеров.
Kubernetes же позволяет не только запустить несколько машин, но и занимается балансировкой нагрузки, контролем запущенности и обновлением контейнеров (есть функция rolling-update позволяющая без простоя обновить pod'ы внутри RC).

Морочиться стоит в случае если:
  • Есть необходимость регулярного безпростойного деплоя
  • Необходимо обеспечить высокую отказоустойчивость
  • Необходимо обеспечить горизонтальную масштабируемость и балансировку не прибегая к «зоопарку» ПО
  • Вы не боитесь использовать в продакшне ПО находящееся в стадии альфа стадии разработки

Возможно я ошибаюсь на счёт Swarm, буду благодарен за дополнительную информацию по опыту работы с ним.
Мой опыт подтверждает ваши слова относительно того, что Swarm — это просто абстракция, которая, на сколько это возможно, стирает границы между разными машинами. Пока что у меня на нём работает тестовый кластер, который изначально был запланирован только для внутрикорпоративнх экспериментов, так что высоких требований по uptime у него нет, так что Swarm отлично подошёл как простой способ управления всем хозяйством с одной машины.
Вообще, Docker + Swarm вытеснили весь головняк с CFEngine, который хоть и решал проблемы, но всегда происходили какие-то накладки в конфигах, вылавливание которых порой занимало больше времени чем хотелось, так что в этом смысле мне нравится эта связка для текущих задач.
Mesos/Kubernetes/swarm/fleet это немного разные животные.

IMO Mesos+Kubernetes всех победят, но пока все еще в глубокой альфе. Как и Swarm.
Fleet хороший, но он более сложен в управлении.

Из приятных вещей могу предложить tutum.co
A la Kubernetes уже сегодня. Для среднего бизнеса.
Очень хороший.
Если я правильно понял, что tutum.co — это вообще другое животное, это SaaS, который к тому же требует использования облачных провайдеров.

На счёт глубокой альфы Swarm ничего сказать не могу — у меня больше месяца аптайм с ним и ничего не падало ещё.
Нет. Вы поняли не правильно.
Кто-нибудь пробовал использовать ОС заточенные под Docker (RancherOS, CoreOS, Atomic, Snappy Ubuntu, ...)? Меня интересует личный опыт, так как статей я поначитался уже много; больше всего привлекает RancherOS, но они как-то сбавили темпы и это меня расстраивает.
У меня есть небольшой опыт использования CoreOS совместно с Docker. Выбор пал на эту ОС как на активно развивающуюся, настраиваемую конфигом и имеющую возможность кластеризоваться «by design».
К сожалению опыт прошёл в формате «продакшн тест» и, пока что, далее не продвинулся.
Были ли моменты, когда хотелось что-то сделать вопреки CoreOS? :)

На самом деле, моя проблема с выбором ОС сейчас связана с одной небольшой деталью — в ядрах до 4.0 есть утечка памяти в ядре (в одном специфическом случае, в который нормальные люди не попадают обычно), так что я хожу по всем проектам и пинаю людей на апдейт ядра.
Честно говоря, вопреки CoreOS сделать ничего не хотелось, хотя и пришлось несколько изменить подход к организации сервисов согласно логике CoreOS.

А бага интересна, читал про неё, но лично не сталкивался. Надеюсь, что её всё-же устранят.
Её устранили в 4.0 ядре, поэтому и хожу пинаю чтоб обновляли. boot2docker быстро откликнулись и обновили (я думал, что мне на первое время хватит, но оказалось, что я не угадал с направлением), а RancherOS уже две недели не отзываются, а они мне нравятся минимализмом и web-интерфейс у них интересный, хочу попробовать, а ещё они автоматически поднимают ipsec между контейнерами, что позволяет поднимать связанные контейнеры через интернет (интересно, но пока не придумал применения особо).
Кстати про ipsec.
Flannel входящая в состав Kubernetes создаёт единое адресное пространство для всех контейнеров в пределах кластера, что позволяет свободно разносить ноды кластера по разным ЦОДам.

Как только они добавят механизм резервирования в систему управления можно будет проводить «учения» на целом ЦОДе.

Но и сейчас, потеря мастер-ноды не нарушает работу сервиса.
Flannel пока не поддерживает шифрование.
Но имеет возможность работать, например, внутри VPN-тоннеля.
Внимание всем «виртуализациям сети». Weave/flannel тормознутые.
Это не всегда важно, но иногда может быть.
Между тем, в той же статье написано, что Flannel с инкапсуляцией VXLan работает вполне корректно.
Да. Для этого линк. Знание = сила.
Flannel входит не в Kubernetes, а в CoreOS.
Вообще у них очень тесные взаимоотношения, команда CoreOS использует fleet чтобы стартануть kubernetes и дальше работают в последнем. Существует вероятность что fleet просто заменят в один прекрасный момент,
CoreOS и все прекрасно.

Rancher не взлетит. Они ставят на «админку» но конкуренты их задавят.

Kubernetes/Swarm в очень глубокой бете. Багов словил тонны.
Fleet стабильно, но на порядок «сложней».
Попробовал я, значит, CoreOS… Мне кажется, что я скоро сделаю N+1 OS. Когда я только познакомился с Docker, мне казалось, что мне подойдёт любая OS, которая удовлетворяет вот этому условию:
  • Linux Kernel 3.10+

Как сильно я ошибался…
  • Так получилось, что я использую фичи Docker 1.6.0+ (на момент написания проекта приходилось ночные релизы использовать)
  • Всё шло гладко до нагрузочного тестирования, которое показало, что течёт память, да не просто память, а память ядра. В ходе раскопок узнал много нужного и не очень, но радости моей не было предела, когда я узнал, что в 4.0 уже это исправлено! Итак: Linux Kernel 4.0+
  • Собирать своё ядро на Ubuntu мне не хотелось ну совсем, да и на данный момент все эксперименты ведутся в виртуальных машинах, так что можно пойти по пути экзотических ОС, в частности, «оптимизированных» для Docker (так как меинстрим дистрибутивы нереально пнуть на обновление ядра). Ок, RancherOS не прошёл по версии ядра, поставил CoreOS, а тут у нас overlay+extfs и ладно бы оно не лагало, так нет, упало на первом же запуске pip install… Итог: нужен AUFS, как уже проверенное решение

Продолжаю поиски…
UFO just landed and posted this here
Утечки памяти не связаны с Docker, а с Cgroups, когда пытаешься включить ограничение памяти ядра (использую как временный костыль против fork-бомб). Ирония в том, что ядро течёт при мониторинги потребления памяти ядра (исправлено в 4.0).
UFO just landed and posted this here
На centos7 словили багу с уничтожением netns и паникой по этому поводу (https://bugzilla.kernel.org/show_bug.cgi?id=65191). Благо на патченном руками ядре пришлось жить меньше месяца, потом фикс доехал в ванильном rhel'овском.

Сейчас на centos6 (с 2.6.32-504.16.2.el6) словили багу в cpuacct (в cgroups), пока ковыряю её, чтобы было что отправить в рассылки/багзиллу.

Я с devicemapper'а уехал на btrfs (только для /var/lib/docker), пока живёт и работает. Непривычно, правда, смотреть на состояние fs (df показывает погоду на Марсе). Но у меня все volumes — bind-mount на нормальную fs (xfs/ext4).

В общем, по 8 месяцам в production, namespaces, cgroups и докер сыроваты на centos6 и centos7.
UFO just landed and posted this here
Кстати говоря, вот тут есть playbook для ansible (умеет RHEL, Fedora) для авторазвертывания кластера kubernetes. Уверен, что для chef/puppet и других дистров тоже есть.
Вообще было удобно конечно. При наличии этого плейбука и машин — все развертывание кластера занимает полчаса времени (у меня было 5 тестовых машин).
Да, подобные playbook довольно легко написать для любой системы управления серверами, благо, даже запуск «вручную» у Kubernetes довольно прост. Соответственно и playbook написать не сложно, необходимо описать запуск нескольких исполняемых файлов с определёнными параметрами.

Другой вопрос, что эти параметры стоит изучить и написать свой рецепт, а не брать готовый, можно напороться на неприятные последствия.
Абсолютно верно, главный «профит» в Ansible/Puppet/Chef в разрезе Kubernetes — то, что можно достаточно легко, без лишних телодвижений добавлять миньоны.
К сожалению, пока, добавить миньона «на лету» довольно проблематично. Данный функционал будет реализован чуть позже.
Смотрю на результаты голосования(лидирует рассказ о запуске стандартного LAMP стека) и удивляюсь — о чем там рассказывать?
«In the wild», mysql будет отдельным кластером(percona cluster). Остальное — обычные докер контейнеры и управление конфигами на основе какого-нибудь confd. Бери да запускай.

Или я ошибаюсь?
У меня несколько другой план:
  • nginx — вне Kubernetes, дабы корректно обрабатывать source IP
  • php в контейнерах в нескольких экземплярах, для отказоустойчивости и масштабируемости
  • memcache в виде двух отдельных сервисов внутри кластера, репликация и отказоустойчивость
  • galera — внутри кластера в виде 3-4 отдельных сервисов с подключением внешнего хранилища по iscsi

Как-то так.
Почему именно такой выбор — напишу в статье.
В ноде — нормально, но не в Kubernetes
В статье выше, в разделе «заметки на полях» есть замечательная фраза «Using the kube-proxy obscures the source-IP of a packet accessing a Service» А для меня важно, чтобы приложение знало этот самый source-IP.
MySQL в контейнере, да ещё и через iscsi? ИМХО, лишний и ненужный оверхэд. Если хочется нанотехнологий, в CoreOS можно развернуть кластер в systemd-nspawn/docker через systemd/fleet на машинах с подключенной дисковой полкой.
А можно как-то вкратце, каким образом происходит синхронизация конкретно данных (баз данных, статики ...) между нодами? Нету хорошей статьи чтобы почитать?
Можно прикрутить Flocker github.com/ClusterHQ/flocker, но интеграция с kubernetes там в зародыше.

Ну или шарить папку между нодами, а уже локальную папку монтировать в поды.
Зачем если есть нативные Data volume containers?
Пожалуйста подробнее что вы имеете ввиду. И где это они есть?
Вы пробовали пользоваться поисковыми системами? «Data volume containers».
#1url
Да я знаю про volume в docker, но они не работают. Они годятся только когда у вас 2-3 контейнера на одной машине, а не когда сотни на нескольких физических серверах.
Так же гугл вам бы мог помочь узнать что в kebernetes своя реализация для этого.
Ок. Мы друг друга поняли.
К сожалению, исключительно вручную, Kubernetes это система управления контейнерами и работает она только с ними.
В последних релизах добавили возможность отдавать через kube-proxy статику, но, как я понял, её нужно раскладывать по серверам так же — вручную.
А каким образом, хоть приблизительно, это происходит? Где вся эта парадигма контейнеров предусматривает хранение файлов?
Допустим, я запускаю 3 контейнера mysql сервера, данные хранятся в контейнере, реплика — это моя забота штатными средствами, но, как я понимаю логику работы контейнеров, одновременно работает 1 инстанс, как тогда происходит синхронизация?
С nginx еще непонятнее, если сервера раскиданы по разным физическим серверам, как синхронизировать статику, скрипты, сессии…
Прошу просить за глупые вопросы, но глубоко разбираться нет пока возможности, а понять, как оно работает хочется.
> Где вся эта парадигма контейнеров предусматривает хранение файлов?

В контейнерах.

Если вам одного инстанса мало, то вам нужна распределенная БД. А это уже совсем другой зверь и как правило не mysql.
Парадигма контейнеров предусматривает хранение только статичной информации.
Динамика, пользовательский данные и логи хранить внутри контейнеров вообще не стоит, разве что, при условии монтирования в контейнер внешнего хранилища, например по iscsi.
Спасибо, в общем становится немного яснее. Так понимаю, в том примере что в статье (без каких-то дополнительных телодвижений), будет 3 варианта статики для nginx, 3 разных лога…, каждый в своем контейнере.
Было бы конечно очень интересно почитать про то, как практически это хозяйство организовать хотя бы на примере простого LAMP.
Получается, если выносить данные за пределы контейнера, получаем одну точку отказа, теряется весь смысл затеянного.
Ну так используйте кластерную/распределенную ФС.

Раскрою свою мысль.
Есть несколько вариантов деплоя:

* Плавный перезапуск контейнеров, в которых лежит вся статика;
* В контейнере весит демон, который принимает перехватывает kill сигналы. И по kill -HUP(например), делает git pull -u
* Использовать распределенную ФС. Например, gluster
* Использовать что-нибудь типа mysql для хранения статики
Больше вариантов не успел написать — закончилось время редактиврования. Однако это первое, что пришло на ум. Остальное можете дописать сами.

Лично я использую в своем pet-проекте перезапуск контейнеров с новой статикой.
Для важных данных использую CephRBD.
Сбор логов — это отдельная задача. Надо настроить nginx (и все другие контейнеры) писать логи на stderr, потом их нужно чем-то собирать со всего кластера и уметь по ним поиск делать. Говорят, Fluentd + Elasticsearch хорошо работают.
Есть ещё вариант научить всё ПО в контейнерах писать в rsyslog и собирать это на отдельной логовнице.
Логовница может 1. сдохнуть и потерять часть логов, 2. не справляться с потоком логов от многих машин и, опять же, терять их. Лучше логи писать локально на диск, а потом неторопливо их высасывать в хранилище.
Предполагается делать это так. Вы ставите на все машины кластера GlusterFS, который поддерживает нужный уровень избыточности данных. Затем, когда контейнер запускается, у него создаётся volume, «смонтированный» в один из каталогов GlusterFS. В результате, все инстансы вашего приложения имеют доступ к одной и той же файловой системе без лишних телодвижений.
Оригинальный ответ от команды docker — используйте volumes.
Это такие контейнеры которые не запускают сервисов но хранят данные и могут шарить эти данные с другими контейнерами.

К сожалению идея работает очень убого ибо отключить и подключить volume к контейнеру можно только перезапуском самого контейнера.

Ну а базы данных так либо на Gluster либо не в контейнере.
UFO just landed and posted this here
+1, даже где-то в FAQ'е Ceph был жирным текстом выделен текст в подзаголовке «Ceph как бэкэнд для mysql», что не надо так делать.

volume — это не контейнеры, это docker -v /path/in/host:/path/in/container.
А взаимодействия конейнеров между собой — это уже другой вопрос.

P.S. Расшарить из докера в хост машину volume оказалось очень не тривиальной задачей, когда я баловался.
Бывают volumes между хостом и контейнером, а бывают между ондинм контейнером и другим.
Оригинальное использование volumes именно между контейнерами — команда докера так делает бекапы и логи в вообщем все.
Volumes между хостом и контейнером считаются плохим тоном, хотя зря наверное, я люблю всякие сокеты с хоста прокидывать.
Базы да, а что по поводу статики? Допустим какой-то среднестатистический дефолтный интернет магазин с кучей картинок, превьющек и т.д.
К примеру хотим сделать некое отказоустойчивое решение, имеем 3 сервера. Настройка стандартная nginx + php + mysql.
насколько я понимаю, подход такой, собираем 3 ноды по мануалу из статьи. Внутри каждого контейнера собираем GlusterFS серверную ноду в режиме replicated volume, монтируем на /var/www.
Mysql настраиваем для реплики…
Правда вот сейчас думаю, зачем мне контейнеры )))) если это можно сделать и без них.
Никак не могу понять как правильно в реальной жизни все это можно использовать.
UFO just landed and posted this here
Контейнеры позволяют изолировать окружение. Вы можете упаковать ваши отдельные сервисы в образы и запускать их «вручную» с указанием локальной папки на конкретном сервере. Контейнеры не сделают вам автоматический S3/HDFS/GlusterFS/WeedFS/NFS/… это уровень приложений.

Кстати, я как-то изучал тему распределённых файловых систем и о GlusterFS всегда были отзывы и конкретные бенчмарки, показывающие, что нужно сторониться этой FS. NFS (не распределённая, но может показаться, что она подойдёт) — не вздумайте полагаться на NFS в проектах (личный опыт). Вы можете даже rsync по расписанию делать из контейнеров, кстати. Я в своё время пришёл к SeaweedFS (WeedFS), но нужно учитывать, что она никогда не будет POSIX-совместимой, но для статики она подходит отлично.
Смысл контейнеров заключается в бинарных апдейтах. В вашем случае это удобно для выкатывания обновлений php. В норме у вас app сервер, помимо php, будет содержать всякие утилиты типа imagemagic и прочие зависимости системы которые, могут уходить глубоко в libc.
Каждый раз когда вы выкатываете обновление обновление на конфигурацию app сервера вы рискуете получить отличающееся состояние. Докер гарантирует, что обновления будут идентичными.

Но статья-то про кубернетис, а это следующий шаг после контейнров — scheduled deployments. Тут две радости — во первых удобно следовать infrastructure as code, во вторых масштабировать систему очень приятно — говоришь я хочу еще 10 этих контецнеров и через 5 секунд они работают.
Ага. А ещё удобно тестовую версию системы поднимать. Говоришь — хочу вот точно такую базу данных, в неё, пожалуйста, вчерашний бэкап с продакшна, ещё нужны такие же сервисы, как в продакшне, только с новой версией. И всё само поднимается, связывается друг с другом, и готово к тестированию. Потом прибить всё одной командой, чтобы ресурсы не ело.
Kubernetes, сам по себе, не решает проблему связи с пользователем.
Очень даже решает. Вы можете запустить Pod с опцией hostNetwork: true. В результате порты будут доступны не на виртуальном динамическом IP, а снаружи. Конфиг выглядит примерно так:

spec:
  nodeSelector:
    frontend: "true"
  hostNetwork: true
  containers:
    - name: frontend
      image: your/packaged/nginx:latest
      ports:
        - name: http
          containerPort: 80
          hostPort: 80
          protocol: TCP
        - name: https
          containerPort: 443
          hostPort: 443
          protocol: TCP

Тут важны два момента. Во-первых, мы ограничиваем, на каких нодах запускать nginx (только на тех, которые мы пометили как frontend=true), а во-вторых, порты 80 и 443 будут доступны снаружи (hostNetwork: true).

Потом можно снаружи какой-нибудь Cloudflare прицепить, чтобы внешний трафик проксировал на эти машины, и получится нормальный отказоустойчивый фронтенд.
Да, это возможно, но я, пока, не исследовал как себя поведут pod при попытке запуститься на уже занятом порту.
К тому же, проблему связи с пользователем, в данном решении, решает всё-же Cloudflare, а не Kubernetes.
1. Это решается на этапе scheduling'а. Kubernetes не отправит два пода, которым нужен один и тот же внешний порт, на одну машину. Если на машине порт занят чем-то другим (не подом), то под будет висеть в статусе Pending, пока порт не освободится и он не сможет стартовать.

2. Вы можете запустить одну единственную ноду с nginx, и настроить ваш домен, чтобы он указывал на её IP-адрес. Тогда Cloudflare не нужен. Всё просто работает. Cloudflare — это полезное дополнение, чтобы фронтенд не был единой точкой отказа. Это собственно и не только к Kubernetes относится, а вообще к любой системе, которая претендует на отказоустойчивость.
Интересует вопрос миграции подов. Допустим система управления приняла решение разгрузить одну из нод, и должна выселить с ноды 30% подов. Как это возможно реализовать? Пока расматриваю 2 варианта:

  1. Переводим ноду в статус unschedulable и запускаем rolling-update для репликейшен контроллеров которые имеют поды на необходимой ноде. Таким образом RC заменит поды по очереди, и стартанет их уже в новом месте
  2. Настроить жеский контроль по лейблам, и так же ролинг апдейтом перемещать поды с ноды на ноду

Мне решение #1 кажется наиболее подходящим к философии Kubernetes. Единственное, если вы хотите ограничить нагрузку на машину, чтобы она потребляла на 30% меньше ресурсов, а не отключить её совсем, то вместо unschedulable лучше уменьшить лимит CPU и RAM (поле Capacity).
Мы хотим оверселить ресурсы, и поймать момент когда пора скейлить инфраструктуру и переносить клиентов на новые ноды. Сразу предвидеть нагрузку нет возможности, так как все зависит от частного случая каждого клиента. А держать сервера в простое тоже не хочется.
Я правильно понимаю, что вы хотите делать utilization based scheduling? Т.е. если нагрузка на конкретную ноду стала неприемлемо большой, то вы хотите раскидывать контейнеры на другие ноды?
Именно, так и хотим )
Тогда всё гораздо проще делается. Когда ваша логика решает разгрузить машину, она просто отстреливает «лишние» поды на ней. Replication controller у вас должен быть настроен с политикой LeastRequestedPriority, чтобы новые поды направлялись на наименее загруженные машины.
А где можно прочесть про этот LeastRequestedPriority? Просто отстрелить их не получится, так как нужно без даунтайма это делать. Но если я правильно понял то и ролинг-апдейт тут подойдет.
Если нужен graceful restart, то вместо отстрела, просто снимаете все лейблы с пода. Он ещё запущен, принимает запросы от пользователей, но для kube-proxy и для kube-scheduler он уже не видим. Первый снимет с него трафик, а второй запустит новый под где-нибудь. Через несколько секунд нагрузка на под упадёт до нуля, и его можно уже прибить. Собственно, rolling restart ровно это и делает. Только он делает это со всеми подами, которые у вас есть в кластере, а вы можете сделать это только с теми, которые вам нужно перенести на другие машины.

Про LeastRequestedPriority тут — github.com/GoogleCloudPlatform/kubernetes/blob/master/plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go#L65
Документацию человеческую, насколько я знаю, не написали ещё.
У нас поды без трафика, это демоны которые крутятся все время. Но идея с лейблами годится, тогда контроллер поднимет новые, а уже потом можно из вне прибить старые.

Да исходники я уже тоже нашел и полез изучать ) Похоже все же надо будет ставить себе Го

Спасибо за наводку!
Если я правильно понял по коду, то он отталкивается от статических данных, а не от текущей нагрузке на ноду. Это не спасает когда у нас 10 подов на одной ноде жрет ресурсов больше чем 20 на другой. При равной конфигурации. Но в теории можно дописать туда своих алгоритмов ))
Ага. Должно быть легко. Интерфейсы там очень простые :)
Так же насколько мне известно не решен вопрос изоляции групы контейнеров (неймспейсов).

Все поды живут в одной сети.
Это в планах. Предполагается, что можно будет задать ACL, какой под может с каким связываться по сети. Это решит много проблем с безопасностью прямо на уровне сети.
Да в планах там много чего, но мне нужно уже сейчас ))
В статье указано что:
Pods (pods.md): Pod это группа контейнеров с общими разделами, запускаемых как единое целое.


Меня как человека, который только пытается разобраться в Kubernetes понятие раздела здесь поставило в тупик. Что подразумевается под общим разделом в этом предложении? Ноды внутри контейнера не являются независимыми друг от друга? Они используют одно дисковое пространство? Как это влияет на масштабируемость? Должен ли я использовать два и более отдельных нода чтобы создать масштабируемую систему?
Sign up to leave a comment.

Articles