CoreOS: ОС как платформа для контейнеров, или зачем выбрасывать yum
Пощупали CoreOS после выхода из бета: Docker-контейнеры вместо пакетов, fleet для кластера, etcd как мозг. Интересно, но в клиентскую эксплуатацию пока не берём.
CoreOS вышел из бета в июле 2014 - минималистичная Linux-система без пакетного менеджера, рассчитанная на запуск всего через Docker-контейнеры с автоматическим обновлением ОС
Примерно в июле CoreOS объявил о выходе из бета. Для нас это был хороший повод поднять его на стенде и посмотреть, не просто ли это красивая идея на слайдах.
Если коротко: идея необычная, реализация опрятная, но эксплуатационная зрелость для клиентских проектов нас пока не устраивает. Дальше - подробнее.
Что вообще такое CoreOS
Нормальный Linux-сервер - это операционная система плюс куча пакетов: nginx, postgresql, java-рантайм, ваш любимый набор bash-скриптов в /etc/init.d. CoreOS предлагает другую картину мира: сама ОС - это только ядро и минимум системных компонентов. Никакого yum, никакого apt. Хочешь запустить что-то - упаковывай в Docker-контейнер и запускай.
На уровне идеи это очень чисто. Хост становится однородным: неважно, что там внутри контейнера, хост просто запускает контейнеры и обновляется сам. Обновление реализовано через A/B-разделы: система скачивает новый образ в пассивный раздел, при следующей перезагрузке переключается на него. Если что-то пошло не так - откатывается обратно. Без rpm, без dpkg, без «а у нас в пакете другая версия libssl». Приятно выглядит.
fleet и etcd: мозг кластера
Тут CoreOS-экосистема предлагает свои инструменты, и это самая интересная часть.
etcd - распределённое key-value хранилище на базе Raft. Служит единым источником истины для всего кластера: кто живой, какие сервисы запущены, где. Мы уже видели etcd краем глаза в контексте flannel и overlay-сетей, но здесь он центральный компонент, без него CoreOS просто не работает.
fleet - это systemd для кластера. Пишешь unit-файл, говоришь fleetctl start, и fleet сам решает, на каком хосте его запустить. Умеет ограничения: «запусти на хосте, где нет другой копии этого сервиса» - получаешь примитивную HA. «Запусти рядом с этим сервисом» - получаешь аффинность.
Поиграли с трёхнодовым кластером на стенде. Поднимать несложно: сгенерировал cloud-config, указал токен etcd-кластера, запустил три виртуалки. fleet подхватывает ноды автоматически, fleetctl list-machines сразу показывает всех участников.
Деплой сервиса выглядит примерно так:
[Unit]
Description=myapp
After=docker.service
Requires=docker.service
[Service]
ExecStartPre=-/usr/bin/docker kill myapp
ExecStartPre=-/usr/bin/docker rm myapp
ExecStart=/usr/bin/docker run --name myapp \
-p 8080:8080 \
registry.internal/myapp:latest
ExecStop=/usr/bin/docker stop myapp
[X-Fleet]
Conflicts=myapp@*.service
Два инстанса через fleetctl start myapp@{1,2}.service - и fleet раскидает их по разным хостам, не пересекаясь. Для этого нам раньше нужен был либо Ansible с ручной картой хостов, либо что-то сложнее. Здесь это из коробки.
Что не понравилось
Операционная модель ломает привычные инструменты. У нас Ansible автоматизирует всё подряд: настройку nginx, разворачивание конфигов, управление сервисами. CoreOS этого просто не предполагает - нет пакетного менеджера, нет директории /etc/nginx, потому что nginx должен быть в контейнере. Перенести существующую инфраструктуру клиента на CoreOS - это не «адаптировать плейбуки», это переписать операционную модель с нуля.
Дебаггинг неочевиден. Когда сервис падает на обычном хосте - идёшь в /var/log, смотришь systemctl status, запускаешь процесс руками с отладочными флагами. С fleet всё чуть сложнее: сервис может быть на любой ноде кластера, логи надо вытаскивать через fleetctl journal, который работает не всегда быстро. Плюс все файловые пути внутри контейнера, и если что-то падает при старте - понять причину без нормальной наладки образа непросто.
Всё только через Docker. Пока это звучит как достоинство, но на практике означает: любой инструмент, который не умеет работать из контейнера, требует дополнительной работы. Наш внутренний Docker Registry - не проблема, он сам контейнер. А вот некоторые агенты мониторинга, специфичное ПО для заказчиков из корпоративного сегмента или что-то с лицензионным ключом на железо - уже интереснее.
Нет ничего похожего на зрелую документацию по production-эксплуатации. Как обновлять образы в контейнерах без даунтайма при использовании fleet - вопрос, на который в официальных доках пока даются очень общие ответы. Как справляться с ситуацией, когда etcd-кластер теряет кворум - тоже. Это не значит, что невозможно, но означает, что придётся разбираться самим и фиксировать собственные процедуры.
Где это уместно
CoreOS хорошо смотрится в ситуации, где вы строите новый сервис с нуля, вся команда умеет в Docker, нет наследия в виде конфигурационных RPM и нет требования «чтобы всё работало через месяц без сюрпризов».
Для клиентских проектов, которые мы сопровождаем, пока это не тот случай. Там есть legacy, там есть специфические зависимости, там есть люди, которым надо быстро разобраться в инциденте в три часа ночи - а не вспоминать, как извлечь лог из fleet.
Стенд оставляем жить. Интересно наблюдать за тем, как развивается fleet и особенно etcd - последний уже используется в нескольких местах вне CoreOS как просто надёжное распределённое хранилище конфигурации. Это само по себе ценно вне зависимости от того, приживётся ли CoreOS как ОС.