Наша реалізація Continuous Deployment на платформу замовника

Ми в True Engineering налаштували безперервну доставку оновлень на сервери замовника і хочемо поділитися цим досвідом.

Для початку ми розробили онлайн систему для замовника та розгорнули її у власному кластері Kubernetes. Тепер наше навантажене рішення переїхало на платформу замовника, для чого ми налаштували повністю автоматичний процес Continuous Deployment. Завдяки цьому ми прискорили time-to-market – доставку змін до продуктового середовища.

У цій статті ми розповімо про всі етапи процесу Continuous Deployment (CD) або доставку оновлень на платформу замовника:

  1. як стартує цей процес,
  2. синхронізація з Git-репозиторієм замовника,
  3. збірка бекенда та фронтенду,
  4. автоматичне розгортання програми у тестовому середовищі,
  5. автоматичне розгортання на Prod.

У процесі поділімося деталями налаштування.

Наша реалізація Continuous Deployment на платформу замовника

1. Старт CD

Continuous Deployment починається з того, що розробник викладає зміни до релізної гілки нашого Git-репозиторію.

Наш додаток працює на базі мікросервісної архітектури та всі його компоненти зберігаються в одному репозиторії. Завдяки цьому збираються та встановлюються всі мікросервіси, навіть якщо змінився один із них.

Ми організували роботу через один репозиторій з кількох причин:

  • Зручність розробки - програма активно розвивається, тому можна працювати відразу з усім кодом.
  • Єдиний пайплайн CI/CD, який гарантує, що програма як єдина система проходить усі тести та доставляється в prod-оточення замовника.
  • Виключаємо плутанину у версіях – нам не доводиться зберігати карту версій мікросервісів та описувати для кожного мікросервісу свою конфігурацію у скриптах Helm.

2. Синхронізація з Git-репозиторієм вихідного коду замовника

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

Ми не можемо працювати з репозиторієм замовника безпосередньо, оскільки нам потрібні власні середовища для розробки та тестування. Ми використовуємо для цього свій Git-репозиторій — він синхронізований з їх Git-репозиторієм. Як тільки розробник викладає зміни у відповідну гілку нашого репозиторію, GitLab відразу ж надсилає ці зміни замовнику.

Наша реалізація Continuous Deployment на платформу замовника

Після цього потрібно зробити складання. Вона складається з декількох етапів: складання бекенду та фронтенду, тестування та доставки в прод.

3. Складання бекенду та фронтенду

Складання бекенду та фронтенду – це два паралельні завдання, які виконуються в системі GitLab Runner. Її конфігурація вихідного складання лежить у тому ж репозиторії.

Туторіал для написання YAML-скрипту для складання в GitLab.

GitLab Runner забирає код із потрібного репозиторію, командою зборки Java-додатки зібрає та відправляє його в Docker registry. Тут ми збираємо бекенд та фронтенд, отримуємо Docker-образи, які складаємо у репозиторій на стороні замовника. Для керування Doker-образами використовуємо плагін Gradle.

Ми синхронізуємо версії наших образів із версією релізу, який буде викладено у Docker. Для гладкої роботи ми внесли кілька налаштувань:

1. Між тестовим оточенням та продуктовим контейнерами не перезбираються. Ми зробили параметризації, щоб один і той же контейнер міг без перескладання працювати з усіма налаштуваннями, змінними оточеннями та сервісами як у тестовому середовищі, так і на проді.

2. Для оновлення програми через Helm необхідно вказати її версію. У нас збірка бекенда, фронтенда та оновлення програми – це три різні завдання, тому важливо використовувати скрізь одну й ту саму версію програми. Для цього завдання ми використовуємо дані з історії Git, оскільки у нас конфігурація K8S кластера та програми знаходяться в одному Git-репозиторії.

Версію програми ми отримуємо з результатів виконання команди
git describe --tags --abbrev=7.

4. Автоматичне розгортання всіх змін у тестовому середовищі (UAT)

Наступним етапом у цьому скрипті збирання виконується автоматичне оновлення кластера K8S. Це відбувається за умови, що вся програма зібралася і всі артефакти опубліковані в Docker Registry. Після цього запускається оновлення тестового оточення.

Оновлення кластера запускається за допомогою Helm Update. Якщо в результаті щось пішло не за планом, Helm автоматично і самостійно відкотить всі свої зміни. Його роботу не слід контролювати.

Ми постачаємо разом зі збиранням конфігурацію кластера K8S. Тому наступним кроком оновлюється вона: configMaps, deployments, services, secrets та будь-які інші конфігурації K8S, які ми змінили.

Після цього Helm запускає RollOut оновлення самої програми у тестовому середовищі. Перш ніж додаток буде розгорнуто на продажі. Це зроблено для того, щоб користувачі перевірили вручну бізнес-фічі, які ми виклали в тестове оточення.

5. Автоматичне розгортання всіх змін на Prod

Щоб розгорнути оновлення у продуктове оточення, залишається лише натиснути одну кнопку в GitLab — і контейнери одразу доставляються у продуктове середовище.

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

Гнучка настройка параметрів програми залежить від того оточення, в якому ця програма буде виконуватися. Ми винесли всі налаштування оточення зовні: все параметризується через конфігурацію K8S та параметри Helm. Коли Helm розгортає збірку в тестове оточення, до неї застосовуються тестові параметри, а продуктовому оточенні продуктові параметри.

Найскладнішим було параметризувати всі сервіси та змінні, які залежать від оточення, і перевести їх у змінні оточення та опис-конфігурації параметрів оточення для Helm.

У параметрах програми використовуються змінні оточення. Їхні значення задаються в контейнерах за допомогою K8S configmap, який шаблонізується за допомогою Go-шаблонів. Наприклад, завдання змінної оточення на звання домену можна зробити так:

APP_EXTERNAL_DOMAIN: {{ (pluck .Values.global.env .Values.app.properties.app_external_domain | first) }}

.Values.global.env – у цій змінній зберігається назва оточення (prod, stage, UAT).
.Values.app.properties.app_external_domain – у цій змінній ми у файлі .Values.yaml задаємо потрібний домен

При оновленні програми Helm виконує створення шаблонів файлу configmap.yaml і заповнює значення APP_EXTERNAL_DOMAIN потрібним значенням залежно від оточення, в якому стартує оновлення програми. Ця змінна проставляється вже у контейнері. Доступ до неї є із програми, відповідно, у кожному оточенні програми буде різне значення цієї змінної.

Відносно нещодавно у Spring Cloud з'явилася підтримка K8S, у тому числі робота з configMaps: Весняна хмара Kubernetes. Поки проект активно розвивається та змінюється кардинально, ми не можемо використовувати його у проді. Але активно моніторимо його стан і використовуємо його в конфігураціях DEV. Як тільки він стабілізується — перемикатимемося з використання змінних оточення на нього.

Разом

Отже, Continuous Deployment налаштований та працює. Усі оновлення відбуваються за одним натисканням клавіші. Доставка змін у продуктове середовище – автоматична. І, що важливо, поновлення не зупиняють роботи системи.

Наша реалізація Continuous Deployment на платформу замовника

Плани на майбутнє: автоматична міграція бази

Ми задумалися про апгрейд бази та можливість ці зміни відкотити. Адже одночасно працюють дві різні версії програми: стара працює, а нова піднімається. І стару ми виключимо лише коли переконаємося, що нова версія працює. Міграція бази повинна дозволяти працювати з обома версіями програми.

Тому ми не можемо просто так змінити назву колонки чи інші дані. Але ми можемо створити нову колонку, скопіювати в неї дані зі старої колонки і написати тригери, які при оновленні даних одночасно копіюватимуть і оновлюватимуть їх в іншій колонці. І після успішного деплою нової версії програми, після періоду post launch support, ми зможемо видалити стару колонку і тригер, що став непотрібним.

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

Ми плануємо зробити автоматизацію міграції бази через K8S job, вбудувавши їх у процес CD. І обов'язково поділимося цим досвідом на Хабрі.

Джерело: habr.com

Додати коментар або відгук