Мы ў True Engineering наладзілі працэс бесперапыннай дастаўкі абнаўленняў на серверы замоўца і жадаем падзяліцца гэтым досведам.
Для пачатку мы распрацавалі анлайн сістэму для заказчыка і разгарнулі яе ва ўласным кластары Kubernetes. Цяпер наша высоканагружанае рашэнне пераехала на платформу замоўца, для чаго мы наладзілі цалкам аўтаматычны працэс Continuous Deployment. Дзякуючы гэтаму, мы паскорылі time-to-market - дастаўку змен у прадуктовае асяроддзе.
У гэтым артыкуле мы раскажам пра ўсе этапы працэсу Continuous Deployment (CD) або дастаўкі абнаўленняў на платформу заказчыка:
- як стартуе гэты працэс,
- сінхранізацыя з Git-рэпазітаром заказчыка,
- зборка бэкенда і фронтэнда,
- аўтаматычнае разгортванне прыкладання ў тэставым асяроддзі,
- аўтаматычнае разгортванне на Prod.
У працэсе падзелімся дэталямі наладкі.
1. Старт CD
Continuous Deployment пачынаецца з таго, што распрацоўшчык выкладвае змены ў рэлізную галінку нашага Git-рэпазітара.
Наша прыкладанне працуе на базе мікрасэрвіснай архітэктуры і ўсе яго кампаненты захоўваюцца ў адным рэпазітары. Дзякуючы гэтаму збіраюцца і ўсталёўваюцца ўсе мікрасэрвісы, нават калі змяніўся адзін з іх.
Мы арганізавалі працу праз адзін рэпазітар па некалькіх прычынах:
- Выгода распрацоўкі - дадатак актыўна развіваецца, таму можна працаваць адразу з усім кодам.
- Адзіны пайплайн CI/CD, які гарантуе, што дадатак як адзіная сістэма праходзіць усе тэсты і дастаўляецца ў prod-асяроддзе замоўца.
- Выключаем блытаніну ў версіях - нам не даводзіцца захоўваць карту версій мікрасэрвісаў і апісваць для кожнага мікрасэрвісу сваю канфігурацыю ў скрыптах Helm.
2. Сінхранізацыя з Git-рэпазітаром зыходнага кода заказчыка
Зробленыя змены аўтаматычна сінхранізуюцца з Git-рэпазітаром заказчыка. Там настроена зборка прыкладання, якая запускаецца пасля абнаўлення галінкі, і дэплаймент у прад. Абодва працэсу адбываюцца ў іх асяроддзі з Git-рэпазітара.
Мы не можам працаваць з рэпазітаром заказчыка напрамую, паколькі нам патрэбны ўласныя асяроддзі для распрацоўкі і тэсціравання. Мы выкарыстоўваем для гэтых мэт свой Git-рэпазітар — ён сінхранізаваны з іх Git-рэпазітаром. Як толькі распрацоўшчык выкладвае змены ў адпаведную галінку нашага рэпазітара, GitLab адразу ж адпраўляе гэтыя змены заказчыку.
Пасля гэтага трэба зрабіць зборку. Яна складаецца з некалькіх этапаў: зборкі бэкенда і фронтэнда, тэсціравання і дастаўкі ў прад.
3. Зборка бэкенда і франтэнда
Зборка бэкенда і фронтэнда - гэта дзве паралельныя задачы, якія выконваюцца ў сістэме GitLab Runner. Яе канфігурацыя зыходнай зборкі ляжыць у гэтым жа рэпазітары.
GitLab Runner забірае код з патрэбнага рэпазітара, камандай зборкі Java-прыкладанні сабрае і адпраўляе яго ў Docker registry. Тут мы збіраем бэкенд і фронтэнд, атрымліваем Docker-вобразы, якія складаем у рэпазітар на баку заказчыка. Для кіравання Doker-вобразамі выкарыстоўваем
Мы сінхранізуем версіі нашых вобразаў з версіяй рэлізу, які будзе выкладзены ў Docker. Для гладкай працы мы ўнеслі некалькі налад:
1. Паміж тэставым асяроддзем і прадуктовым кантэйнеры не перазбіраюцца. Мы зрабілі параметрызацыі, каб адзін і той жа кантэйнер мог без перазборкі працаваць са ўсімі наладамі, зменнымі асяроддзямі і сэрвісамі як у тэставым асяроддзі, так і на продзе.
2. Для абнаўлення прыкладання праз Helm неабходна пазначыць яго версію. У нас зборка бэкенда, франтэнда і абнаўленне прыкладання – гэта тры розныя задачы, таму важна выкарыстоўваць усюды адну і тую ж версію прыкладання. Для гэтай задачы мы выкарыстоўваем дадзеныя з гісторыі Git, паколькі ў нас канфігурацыя K8S кластара і прыкладанні знаходзяцца ў адным Git-рэпазітары.
Версію прыкладання мы атрымліваем з вынікаў выканання каманды
git describe --tags --abbrev=7
.
4. Аўтаматычнае разгортванне ўсіх змен у тэставым асяроддзі (UAT)
Наступным этапам у гэтым скрыпце зборкі выконваецца аўтаматычнае абнаўленне кластара K8S. Гэта адбываецца пры ўмове, што ўсё прыкладанне сабралася і ўсе артэфакты апублікаваны ў Docker Registry. Пасля гэтага запускаецца абнаўленне тэставага асяроддзя.
Абнаўленне кластара запускаецца з дапамогай
Мы пастаўляем разам са зборкай канфігурацыю кластара 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:
Разам
Такім чынам, Continuous Deployment наладжаны і працуе. Усе абнаўленні адбываюцца па адным націску клавішы. Дастаўка змен у прадуктовае асяроддзе - аўтаматычная. І, што важна, абнаўленні не спыняюць працы сістэмы.
Планы на будучыню: аўтаматычная міграцыя базы
Мы задумаліся аб аб апгрэйдзе базы і магчымасці гэтыя змены адкаціць. Бо адначасова працуюць дзве розныя версіі прыкладання: старая працуе, а новая паднімаецца. І старую мы выключым толькі калі пераканаемся, што новая версія - працуе. Міграцыя базы павінна дазваляць працаваць з абедзвюма версіямі прыкладання.
Таму мы не можам проста так змяніць назву калонкі ці іншыя дадзеныя. Але мы можам стварыць новую калонку, скапіяваць у яе дадзеныя са старой калонкі і напісаць трыгеры, якія будуць пры абнаўленні дадзеных будуць адначасова капіяваць і абнаўляць іх у іншай калонцы. І пасля паспяховага дэплою новай версіі прыкладання, па сканчэнні перыяду post launch support, мы зможам выдаліць старую калонку і які стаў непатрэбным трыгер.
Калі новая версія прыкладання працуе некарэктна, мы можам адкаціцца да ранейшай версіі, у тым ліку і ранейшай версіі базы. Словам, нашы змены дазволяць працаваць адначасова з некалькімі версіямі дадатку.
Мы плануем зрабіць аўтаматызацыю міграцыі базы праз K8S job, убудаваўшы яе ў працэс CD. І абавязкова падзелімся гэтым досведам на Хабры.
Крыніца: habr.com