5 років на Docker Swarm: чому ми досі не на Kubernetes
Привіт, я — Павло, CTO Adheart. Майже 5 років і до сьогодні наш прод крутиться на Docker Swarm, хоч це і звучить як певне «guilty pleasure». Ця стаття — не рекомендація щодо того, «чи варто тобі стартувати новий проєкт на Swarm», і не антагонізм «ви всі дарма в Kubernetes», а мій власний постмортем за цей період.
2026: чи живий Docker Swarm?
Перше враження — що тільки в мемах та документації. Втім існує немало маленьких та середніх продакшнів, які досі на Swarm, серед яких і ми, які просто не кричать про це, бо трохи соромно. Swarm досі залишається робочою конячкою для тих, кому k8s ще кусючий, а хмарна оркестрація — надто золота. Напиши коментар, якщо ваш проєкт також ще досі на свормі :)
Крива входу в цю технологію набагато нижча, ніж в k8s. Якщо ти здатний описати докерфайл і звʼязати пару сервісів між собою в docker compose — можна сказати, що ти вже знаєш Swarm. Купуємо декілька дешевих VPS — і наш проєкт виїжджає в продакшн.

Чому ми обрали Swarm і як виросли в ньому
Власне, такою і була мотивація нашого вибору. Ми прийняли від «попередників» проєкт з шаленим техборгом по всіх напрямах. Не існувало не те, що контейнерізації, навіть git не використовувався — це багато про що говорить. Наша команда на той момент складалась всього з двох людей, тому потрібно було швидко ліквідувати цей розрив. Swarm в такій ситуації став оптимальним вибором.
Нині ми доросли до кластера Swarm з 15 нод (3 менеджера + 12 воркерів), які крутять під собою 2000+ контейнерів, маємо солідні ворклоади у воркерах (нам потрібно збирати більше 100 тисяч реклами з фейсбук за годину), blue/green деплой, повний моніторинг всього кластера, логи — і це все ще у Swarm.
Swarm на стероїдах vs Kubernetes
З коробки Swarm дає лише базовий інструментарій, якого вистачить на пів року чи рік, залежно від росту інженерного рівня твоєї команди. Якщо проєкт вийшов в продакшн або ліквідували базовий техборг, як в нашому випадку — то апетити зростають, і базовий набір функцій їх не задовольнить. Це не проблема, оскільки навколо Docker Swarm також існує розвинена екосистема.

Ingress і роутинг
Swarm має тільки базовий routing mesh. Можна підняти port-forwading, можна прикрутити зверху над цим HAProxy чи інший балансер — і таким чином зшити кластер та отримати high-availability. Навіть для старту це відверто недостатнє рішення, тому ми відразу стартувати з Traefik.
Traefik це реверс-проксі/контролер трафіку, який чудово інтегрується зі Swarm:
- Надає можливість service-discovery через service labels.
- Маршрутизує як HTTP, так і TCP-трафік (в нас чудово живе в кластері redis, rabbit, kafka).
- Проста робота з сертифікатами, https, let’s encrypt, яка знімає весь головний біль.
- blue/green та canary-deployments, не у два кліки, але цілком можливо.
Фактично це повноцінний Ingress з k8s-світу. І до речі, найбезпроблемніший компонент в межах нашого кластера — за 5 років саме з траефіком ми не отримали жодних проблем. Він успішно тримав DDOS-атаки в десятки тисяч RPS, тим більше — стабільний аптайм прода.
CI/CD та deployments
docker stack deploy — це, звісно, непогано для старту, але в реальному проєкті дуже швидко приходиш до потреби побудови CI/CD-процесу. Достатньо поширених рішень тут не так багато. Але коштом простоти Swarm нескладно зібрати свій велосипед, який відкатає 5 років без капремонту.
Ми використовуємо Github actions та Portainer — тому таким велосипедом для нас став власний portainer-deploy-action, який використовує API-портейнер, деплоїть стеки через нього, і дає легкий менеджмент через UI далі.
З реальних проблем тут: розвиток Portainer йде в першу чергу в бік k8s. Для Swarm нових фіч вже навряд чи хтось завезе, а старі баги не факт, що пофіксять. А вони є. Інколи портейнер втрачає звʼязок зі своїми агентами на нодах, через що менеджмент кластера зводиться до старої доброї консолі, а деплої відкладаються на декілька хвилин, а інколи й годин.
Configs / Secrets
Ми ж усі погодились, що сікрети в git — погана ідея, правда? Але у Swarm їх менеджмент непростий і незручний. І сікрети, і конфіги — імутабельні, тобто оновити конфіг можна тільки через створення нового, а видалити старий, поки він використовується, звісно, не можна. Що й призводить до появи my_config_version_100500, оскільки іншого шляху тут і не дають.
Або шукати шляхи спрощення, або городити чудернацькі пайплайни (хоча якщо твоя команда на Swarm, то й інженера, який майстерно це може зробити, ймовірно, немає). Тож ми пішли на компроміс, тримаючи конфіги та сікрети в Github, а в стеки передаючи просто як значення. Не ідеально безпечно, але краще, ніж нічого.
Stateful services / persistent volumes
Коли у вашому кластері починають зʼявлятись сервіси зі стейтом, ти дізнаєшся про те, що Swarm не дає інструментів для розподілених сховищ з коробки. Вихід — або прибивати цвяхами сервіс до якоїсь ноди і забувати про high-availability, або використовувати сторонні розподілені файлові системи, або плагіни.
Ceph — складно, NFS — дуже обмежено. Нам потрібна була з одного боку проста, з іншого — повноцінна файлова система, якою став для нас GlusterFS. Звісно, що не треба реплікувати всі волюми, достатньо виділити якийсь синхронізований простір для сервісів, які потребують розподілених. Ми пропрацювали з GlusterFS близько двох років, без істотних проблем, але з часом все ж прийшли до того, що краще у Swarm тримати тільки stateless-сервіси.
Темна сторона Docker Swarm — реальні проблеми за 5 років
Overlay networks — сім кіл пекла
Коли тільки стартуєш кластер, мало замислюєшся про CIDR, MTU чи розмір мереж. Docker Swarm — це легкий старт, памʼятаємо ж? Який приносить страждання, коли ворклоад кластера перевалює за сотні реплік, які активно комунікують між собою внутрішніми мережами.
І проблема навіть не з самим концептом overlay-мережі як такої, вона використовується і в k8s, і загалом проста, проте робоча технологія. Проблема в менеджменті цих мереж, про що знову ж, не замислюєшся одразу.

Більша мережа — більші проблеми
За замовчуванням Docker видає /24 підмережі для overlay, що дозволяє запускати десь до
В той день, коли один з наших сервісів став потребувати більше реплік, назрів чудовий, здавалось, план: створюємо вручну /16 overlay-мережу, щоб точно вистачило на роки вперед, аттачимо сервіс до неї і маємо щастя... на роки вперед в цій схемі вистачило тільки проблем.
Менеджери Swarm-кластера (а їх для продакшна потрібно мінімум три для консенсусу) постійно тримають таблиці відповідності IP <-> container і синхронізують їх між собою та воркер-нодами. Поки таблиці невеликі, це не складає проблеми, але коли у вас /16 мережа, в якій за весь час вже стартували і відпрацювали тисячі контейнерів, її синхронізація стає накладною. А при відсутності синхронізації починаються мережеві збої: нода1 думає, що контейнер Х в ноді2, хоча фактично він в ноді3, або менеджер взагалі не може заасайнити контейнер на якусь ноду, бо знає, що він не знає стан мережі.
Найпоширеніший приклад: Traefik намагається запроксювати запит на якийсь бекенд, не може отримати від нього відповідь — timeout, 502, і незадовольні клієнти.
Як ми намагались обійти ці проблеми
Повноцінної відповіді на питання «як уникнути проблем з мережами» в мене нема. Всі наші 5 років зі Swarm пройшли в ключі «ура, ми вирішили проблеми з мережами. Через дні, тижні чи місяці знову проблеми». Але якщо їх і можна побороти остаточно — то тільки жорстким, спланованим менеджментом:
- Не підіймати дефолтний розмір мережі без причини (240 вузлів достатньо для більшості сервісів).
- Створювати вручну мережі для великих сервісів з чітким усвідомленням їх розміру. Не набирати вузлів на перспективу років. Перестворити мережу навіть в проді не є величезною проблемою.
- Контролювати, в яких мережах знаходиться кожен сервіс, уникати комбінацій, де сервіси можуть комунікувати у двох і більше мережах одночасно.
- Ретельно моніторити NetworkDB stats і вчасно реагувати на потенційні проблеми. Якщо запустити проблему синхронізації — часто простіше перестворити мережу.
Планувальник задач
Ще одна проблема, яка істотно потріпала нам нерви — це планувальник задач. Для Docker swarm нема нічого простішого, ніж закинути ще пару контейнерів на ноду, яка вже ледве дихає, або навпаки дати відпочинок комусь, поки інші працюють. Типовий сценарій: перевантажується одна з нод, перестає навіть відповідати менеджеру, в якийсь момент він прибирає з неї всі задачі й розкидає так само нерівномірно на інші ноди, викликаючи ефект снігового кому.
Що варто винести з цього:
- Планувальник не ідеальний, і краще вже не стане — потрібно думати за нього.
- Reservations не менш, а може, навіть більш важливі, ніж limits. Дивлячись на reservations, планувальник з меншою ймовірністю поставить задачу на ноду, яка вже й так задихається.
- Оптимізація сервісів по CPU/RAM. На етапі прототипування при роботі з великими обʼємами даних багато проблем вирішується на рівні «дати більше памʼяті», але коли сервіс на всі репліки починає віджирати сотні гігабайт — потрібно взяти час на оптимізацію.
Тулінг та екосистема
Як би ми не намагались зробити зі Swarm k8s — це коштує зусиль, часу на ресерч і розробку. Ми створили десятки кастомних екшенів для github, python/bash скриптів для менеджменту кластера, написали інструкції «як поводитись черговому в разі...» — але кубернетесом від того він так і не став.
До того ж частину проблем ми так і не вирішили:
- Зручний менеджмент конфігів та стеків.
- Шаблонізація стеків.
- Observability самого кластера.
А окремий пласт проблеми — людський.
Ми рухаємось до Kubernetes
Час переходити до логічного фіналу: ми переходимо в k8s. Якщо бути чесним, ми б могли ще довго жити зі Swarm, адже:
- Навчились деплоїти в нього тисячі контейнерів.
- Обросли кастомним просунутим тулінгом для canary deployments, auto-scaling.
- Ефективно покрили ворклоад в кластері логами і метриками.
- Навчились розуміти, де і як ламається кластер, як швидко ремонтувати його, або взагалі обходити збій.
- Достеменно розібрались з overlay-мережами (хоч і не знайшли фінальний рецепт щастя, ймовірно).
Тож причина переїзду не в тому, що «Swarm категорично не підходить». Скоріше ми просто доросли, щоб спробувати інший технологічний рівень: номінально складніший, але більш документований, освітлений чужим досвідом та з більш розвиненою екосистемою. Там, де ми платимо годинами і днями часу на розробку кастомного рішення, в Kubernetes є великий шанс за хвилини встановити і користуватись готовим інструментом. Іноді треба міняти не тільки масло в машині, а й саму машину.
Що я виніс із цих п’яти років на Swarm
- Swarm був доречним для свого часу. Він дозволив нам легко ліквідувати величезний техборг і дозволити зростати далі.
- Простота — кредит. Спочатку ти радієш, що немає зайвої складності, потім починаєш породжувати ще більшу складність.
- Технологія обирається під ресурси. На старті проєкту вдвох з партнером ми і не мріяли про складні технології, але коли команда вже кратно виросла — цілком можемо собі їх дозволити.
- Обирати середній горизонт планування. У Swarm не треба планувати «на роки», але й діяти виключно задля вирішення сьогоднішніх проблем — не можна.
- Треба вчасно зрозуміти, що виріс зі старого одягу. Swarm відпрацював своє, дав нам цінний досвід, але час іти далі.
Я дуже вдячний, читачу, що ти дійшов аж до кінця цієї статті. Сподіваюсь, цей досвід буде корисним для тебе. Я свідомо намагався уникати в ній прямих глобальних порад на кшталт «обирай або не обирай Swarm». Натомість дав ілюстрацію досвіду нашої команди, наших проблем, і кілька практичних порад з їх вирішення. Бажаю тобі не зіштовхнутися з ними, а якщо в тебе залишились запитання — ласкаво прошу в коментарі до обговорення.
Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

18 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів