Антон Маркелов

Автоматизирую, поддерживаю, починяю примус

Navigation
 » Home
 » Обо мне
 » Resume Eng (PDF)
 » Github
 » XML Feed

Краткое сравнение систем оркестрации контейнеров

21 Aug 2016 » devops, docker

Информация актуальна где-то на конец июля.

Вынесу сюда краткое summary по исследованию существующих систем оркестрации в формате “плюсы и минусы”, сделанному мной на стажировке в Экспресс42. В статью не вошла связка Mesos+Marathon, т.к. ее ставил не я, но остальное вроде все охватил. Статейка больше для себя, чтоб иметь краткое описание систем в одном месте.

Fleet

Fleet очень круто сделан идеологически - ты работаешь с целым кластером как с обычной системой, описывая обычные, в общем-то, юнит-файлы для systemd. В части эксплуатации лишних сущностей минимум, все они скрыты под капотом, под который лезть приходится не очень часто. Но с другой стороны, эта скрытость вызывает проблемы с пониманием логики системы, когда тебе надо не просто бездумно шлепать по мануалу, а делать что-то свое. Также, fleet бедноват на средства работы со сложными системами, у него урезанные зависимости, нет иерархий, окружений.

  • Есть constraints (как на уровне “запусти на ноде с такими-то свойствами”, так и на уровне “запусти/не запускай сервис2 на ноде с сервис1”)
  • Нет healthchecks ни в каком виде
  • Есть нормальный DNS Service Discovery, хоть и за счет внешних сервисов
  • Удобный способ описания всего кластера в одном файле cloud-init
  • Зависимости есть, но в очень урезанном виде: они работают только в пределах одной ноды. То есть мы можем запустить Сервис2 после Сервиса1, но только если оба этих сервиса запущены на одной ноде. Более сложные зависимости будут “когда-нибудь”
  • Есть изолированная оверлейная сеть, с которой легко вытащить контейнер наружу, при желании (через --net=host)
  • Поддерживается все множество docker-команд в юнитах
  • По файлу на сервис. Намного удобнее, чем отслеживать изменения в огромном файле на несколько сотен строк.
  • Сложно делать blue-green потому что сложно развернуть две инфраструктуры в пределах одного кластера. Неудобно делать partial deploy
  • Зато rolling довольно безопасен за счет большого количества стадий. Хотя средств отката я не увидел, придется какой-то внешней системой назад катить
  • Простой синтаксис. Ребята не изобретали свой формат, а взяли обычный systemd синтаксис.

Nomad

В Nomad есть то, чего нет в Docker - описание инфраструктуры в едином файле, healthchecks в том же описании, dry-run, но зато не хватает всего остального: нет нормальной работы ни с сетью, ни с персистентными данными. Для эксплуатации в наших условиях как-то совсем не годится.

  • Важно: до сих пор нет поддержки Docker volumes! - https://github.com/hashicorp/nomad/issues/150 https://github.com/hashicorp/nomad/issues/62
  • Важно: Номад не рестартит контейнеры с проваленными healthcheck. Просто помечает их в консуле как failed, но не перезапускает - https://github.com/hashicorp/nomad/issues/876
  • Нельзя рестартануть таску через nomad cli. Надо идти на слейв и прибивать контейнер руками.
  • Файл получается довольно объемный из-за JSON-подобного синтаксиса. Скобки-скобки-скобки. Но вполне читаемый.
  • Номад не умеет в зависимости между сервисами, когда-нибудь обещают сделать - https://github.com/hashicorp/nomad/issues/419
  • Номад не умеет биндить порты на все интерфейсы или на какой-то определенный для контейнера. Только на тот, который указан в параметре network_interface конфига слейва. Обещают пофиксить когда-нибудь - https://github.com/hashicorp/nomad/issues/646
  • Зато healthcheck’и можно описывать прямо тут, что удобно. Поддерживаются http, tcp и script чеки.
  • Некрасивые DNS-имена. Мало того что надо извращаться с dnsmasq/bind для того чтобы пробросить DNS консула на 53 порт, так еще и имена получаются некрасивые, по типу datastore-zookeeper.service.consul, вместо более цивильных zookeeper.datastore.service.consul
  • Можно передавать данные о private registry прямо в самом файле, удобно.
  • Нет способов исключить повторяемость кода. Надо тебе передавать одни и те же переменные в 10 разных контейнеров - дублируй код 10 раз.
  • Nomad умеет обновлять джобу через скармливание ему новой версии hcl-файла, при этом обновляя контейнеры с заданными интервалами и параллелизмом.
  • Поддерживается dry-run режим запуска джобы.

Kubernetes

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

  • Есть constraints, healthchecks, DNS Service Discovery, scaling, autoscaling, single tasks, rolling updates, кофеварка и триммер для волос в носу;
  • Есть cli утилита, которая может работать через TLS;
  • Есть какие-то политики безопасности, но я их не трогал. Вроде как можно авторизовать пользователей по ключу и позволять им разное;
  • Есть богатые возможности по определению своих метаданных для сервисов/подов/и т.д. Очень удобно в больших инфраструктурах;
  • Есть API, документировано тоже не прям супер;
  • Есть красивенький Dashboard
  • Нет cron tasks, но есть четкий milestone, когда их запилят - в следующей версии
  • Удобный способ описания всего кластера в одном файле cloud-init
  • Удобный способ дистрибуции всего кластерного добра в контейнере, все развертывание сводится к указанию этому контейнеру нужных ключей
  • Есть изолированная оверлейная сеть, с которой можно вытащить контейнер наружу, при желании через load balancer
  • Есть поддержка распределенных/сетевых ФС из коробки;
  • По умолчанию все довольно сильно изолировано, как на уровне namespace’ов, так и вообще by design. С другой стороны - зато сложновато взаимодействие сервисов настраивать;
  • Очень много сущностей на всех уровнях. Kubectl имеет довольно длинные команды (хотя есть completions). Искренне не понимаю, зачем нужно было городить 4 сущности: Pod, Service, ReplicaSet, Deployment там, где другие системы обходятся одной;
  • Как следствие из предыдущего - очень многословные yaml-файлы. Описание 4 сервисов у меня заняло 300 строк там, где в Swarm можно было бы обойтись 4 командами;
  • Помимо количества сущностей, они еще и плохо документированы. Ладно бы еще документация местами отсутствовала и приходилось лезть на Github, так она просто неправильная и неактуальная. Ты видишь мануал на официальном сайте, который призван решить твою проблему, а он неточный и устаревший. В итоге ты убиваешь кучу времени на этот мануал, а потом все равно в итоге лезешь на Github.

Swarm

Мне оркестрация от Docker’а очень понравилась. Реально не хватает только описания инфраструктуры как кода где-нибудь в одном файле, с зависимостями и переменными. А так: кластер развертывается быстро, никаких непонятных дополнительных сущностей, есть приватные сети, есть общие сети, есть балансировка, скейлинг, constraints, вот это вот все. Учитывая темпы развития Docker - все скоро будет совсем хорошо.

Aurora

  • Aurora не умеет запускать несколько джобов с зависимостями между ними (например, запусти zk, как только он запустится - запусти kafka и т.д.). Одновременно, впрочем, она тоже не умеет их запускать, только по одному за раз. http://mail-archives.apache.org/mod_mbox/aurora-user/201602.mbox/%3CEE9100CC-04FF-4C64-B479-D3DF68D8C0BE%40lensa.com%3E - тут и далее по треду предлагают городить свои скрипты или использовать что-то вроде Chronos или Airflow.

  • constraints работают на уровне параметра attributes mesos-slave. Т.е. определяем на слейве какие-то атрибуты и потом можем сказать авроре - запускай такой-то джоб только на слейве с таким-то атрибутом.

  • Healthchecks есть, http и shell, но я их не тестил еще.

  • Максимальное количество failures, timeout между попытками перезапуска есть.

  • Внутри aurora-файла полноценный питон, можно определять какие-то структуры, подсовывать их в таски, стрелять себе в ногу из револьвера, ружья, дробовика, пулемета. Мне оказалось удобно определить dict со всеми параметрами в шапке файла и обращаться к нему по ходу дела.

  • Целиком игнорируются ENV, ENTRYPOINT и COMMAND докерфайла. С одной стороны это плюс, можно один и тот же контейнер переиспользовать для разных тасок, плюс в ряде случаев можно обойтись и без пересборки контейнеров. С другой стороны - приходится все эти переменные и команды вытаскивать из докерфайла в аврорафайл, получается что-то вроде:

postgres_proc = env_proc(
   name="postgres_daemon",
   cmdline="""
       export PGDATA='/pgdata'
       export PG_MAJOR='9.3'
       export PG_VERSION='9.3.13-1.pgdg80+1'
       export PATH="/usr/lib/postgresql/$PG_MAJOR/bin:$PATH"
       /docker-entrypoint.sh postgres
   """
  • Есть cronjobs, services (long-running jobs) и обычные “одноразовые” джобы. С учетом предыдущего пункта все три вида можно построить на базе одного контейнера, переопределяя cmdline.

  • Через aurora-cli можно логиниться прямо в контейнер джобы и чего-нибудь херачить там руками.