← Усі статті

Transparent Gateway · Proxmox · cloud-init · DevOps

Чому робочий Transparent Gateway ще не готовий до production

8 вересня 2026 р. · 5 хв читання

Відтворюваний deployment Transparent Gateway від Proxmox template до healthy gateway з двома відкинутими ручними шляхами

У попередніх трьох частинах я послідовно закрив DNS-витоки, прозоро завернув TCP-трафік у проксі та додав автоматичний конвеєр збору, перевірки й ранжування upstream. На схемі все вже виглядає як система. Але на практиці вона тримається на одному Debian-хості, який я кілька днів налаштовував руками.

Поки цей хост працює, проблема майже непомітна. Справжнє запитання з’являється пізніше: чи зможу я відтворити той самий gateway на чистій VM без пам’яті про випадкові команди, старі файли та порядок ручних виправлень?

Тож я розібрав поточний стан: що вже створюють Proxmox і cloud-init, що лишається на диску VM та де має проходити межа між підготовкою хоста й розгортанням gateway. Просте рішення знайшлося швидко. Навіть два.

Проблема: робочий gateway ще не означає відтворюваний gateway

Поточна VM не є повністю ручною. Proxmox створив її з cloud image, а cloud-init задав hostname, користувача, SSH-ключі та мережу. На самій машині це видно без здогадок:

Показати код
root@transparent-gateway-vm:~# systemd-detect-virt
kvm

root@transparent-gateway-vm:~# cloud-init status
status: done

root@transparent-gateway-vm:~# . /etc/os-release; echo "$PRETTY_NAME"
Debian GNU/Linux 13 (trixie)

Але далі автоматизація закінчується. Репозиторій лежить у /opt/transparent-gateway, поруч є локальні .env, inventory та файл credentials. Docker увімкнений у systemd, а контейнери мають restart policy. Окремого deployment-скрипта або systemd unit для всього gateway у репозиторії поки немає.

Тобто cloud-init створює сервер, але не створює сервіс. Між цими двома станами залишається набір ручних дій, які ніяк не зафіксовані.

Термінал Transparent Gateway: KVM, завершений cloud-init і шість запущених сервісів
Поточна VM вже створена через cloud-init і запускає шість сервісів. Але перевірку стану мають лише ASN updater, gateway і Redis — це один із сигналів, що готовність усього конвеєра ще ніхто не перевіряє.

Аудит перед автоматизацією: що насправді треба відтворити

Моя перша помилка була б почати одразу писати cloud-init. Перед автоматизацією треба зрозуміти, який фактичний стан намагаюся отримати.

У gateway зараз три різні мережеві ролі:

  • eth0 — management-мережа 192.168.88.0/24;
  • eth1 — клієнтська мережа 192.168.90.0/24, де gateway має адресу 192.168.90.1;
  • eth2 — лабораторна proxy/echo-мережа 10.10.10.0/24.

Поверх них працюють шість сервісів: Redis, ASN updater, fetcher, validator, ranker і сам gateway. Redis зберігає знімки стану, validator отримує credentials лише для з’єднання з проксі, а gateway працює в режимі host network, бо йому потрібні реальні інтерфейси, правила маршрутизації та перехоплення трафіку.

Відтворити лише контейнери недостатньо. Якщо нова VM отримає інші інтерфейси, не матиме потрібного маршруту або запустить gateway до готовності мережі, Docker формально працюватиме, але клієнтський трафік піде не туди. Звісно, усе це можна виправити руками, але ж це не наш метод.

Просто зробити копію готової VM. Так?

Найшвидший варіант очевидний: вимкнути поточну машину, зробити з неї копію й використовувати цю копію для нових gateway. Я майже пішов цим шляхом, бо в ній уже є всі пакети, образи Docker та конфігурація.

Проблема в тому, що разом із потрібним станом така копія збереже й усе випадкове, що накопичилося на диску. До неї можуть потрапити:

  • старі credentials і токени провайдерів;
  • SSH host keys та стан попереднього запуску cloud-init;
  • знімок Redis із попереднього середовища;
  • застарілі образи Docker;
  • тимчасові резервні файли, про які вже ніхто не пам’ятає.

Через місяць буде незрозуміло, чим одна VM відрізняється від іншої і як оновити базову копію без нового ручного ритуалу. Тому за основу краще взяти мінімальну операційну систему з cloud-init, а застосунок розгортати окремо.

Тоді запхну весь deployment у cloud-init

Після відмови від «золотого» образу виникає протилежна ідея: нехай cloud-init встановить Docker, клонує Git, створить усі файли, запише secrets і виконає docker compose up.

Для короткого демо це працює. Для gateway — швидко перетворюється на величезний блок runcmd, який важко повторно запустити та майже неможливо нормально тестувати. Ще гірше — cloud-init зберігає отриманий user-data на диску VM. Якщо передати там пароль проксі або API token, секрет залишиться у /var/lib/cloud/instances/... та може потрапити в логи.

У підсумку cloud-init знає забагато про застосунок, а застосунок залежить від одноразового механізму першого boot. Я знову отримую ручний сервер, тільки тепер ручні команди сховані у YAML.

Розділяю підготовку VM і розгортання gateway

Після двох невдалих крайнощів межа стала зрозумілою:

Показати код
Proxmox template
    ↓
cloud-init: identity, SSH, network, базові пакети
    ↓
deployment: checkout перевіреної версії, config, systemd
    ↓
Docker Compose: сервіси та залежності
    ↓
readiness check: чи можна вже віддавати трафік клієнтам

Cloud-init відповідає лише за те, щоб VM стала керованим Debian-хостом. Логіка розгортання має бути звичайним кодом у репозиторії: його можна запустити повторно, перевірити перед злиттям змін і прив’язати до конкретної версії Git або релізу.

Також з’являється зрозуміла межа відкату. Якщо нова версія gateway не проходить перевірку готовності, не потрібно відкочувати всю VM. Достатньо повернути попередню перевірену версію застосунку, не чіпаючи дані Redis.

Архітектура відтворюваного Transparent Gateway: Proxmox template, cloud-init, deployment із Git, Docker Compose runtime і readiness
Робоче розділення відповідальності. Секрети надходять лише під час розгортання та роботи сервісів; клонування готової VM й увесь deployment у cloud-init залишаються відкинутими крайнощами.

Що має гарантувати нове розгортання

Після відкидання крайнощів вимоги стали конкретними. Нова VM створюється з мінімального шаблону; cloud-init задає ім’я хоста, SSH-доступ, мережу й базові пакети; код розгортання зберігається в репозиторії та запускає перевірену версію Git або реліз.

Із цього випливають чотири принципові вимоги:

  • Секрети передаю окремо. Вони не потрапляють у шаблон VM, Git або user-data cloud-init. На сервер доставляю їх контрольованим каналом і не виводжу значення в журнали.
  • Запущений контейнер — ще не готовий сервіс. Перевіряю не тільки процеси, а й свіжість знімків стану, наявність робочого проксі та весь маршрут запиту.
  • Відкат не повинен зачіпати всю VM. Версію застосунку зберігаю окремо від постійних даних, щоб повернути попередній реліз, не чіпаючи Redis.
  • Відтворюваність перевіряю на новій VM. Перезавантаження старого диска не доводить, що процедура розгортання повна.

На поточному хості частина конфігурації зберігається лише локально. Окремого systemd-сервісу для запуску всього gateway немає, а перевірка готовності охоплює тільки частину конвеєра. Нове розгортання має закрити саме ці три прогалини.

Що буде у практичній частині

У наступній статті я зберу це в робочу процедуру: підготую мінімальний шаблон Proxmox, залишу cloud-init тільки початкове налаштування, додам повторюваний сценарій розгортання, systemd-сервіс, окрему доставку секретів і повну перевірку готовності. Потім двічі перевірю результат: перезавантажу готову VM і повністю створю її заново з чистого шаблону. Окремий публічний HTTPS-сервіс покаже, чи працює не лише лабораторний маршрут, а й реальний вихід в інтернет.

Висновок

Головний результат цього аудиту — не cloud-init YAML і не ще одна схема. Я нарешті провів межу між створенням VM та розгортанням сервісу. Поточний cloud-init уже вміє створити Debian-хост, але Transparent Gateway поки залишається ручним застосунком на цьому хості.

Тепер зрозуміло, що саме треба довести практикою: secrets не витікають у службові файли, сервіси стартують у правильному порядку, readiness перевіряє весь маршрут, а чиста VM доходить до робочого стану за однією задокументованою процедурою. Саме це і буде предметом наступної частини.

Код проєкту: TransparentGateway на GitHub