Практыкі Continuous Delivery з Docker (агляд і відэа)
Свой блог мы пачнем з публікацый, створаных паводле апошніх выступаў нашага тэхнічнага дырэктара distol (Дзмітрыя Сталярова). Усе яны адбыліся ў 2016 годзе на розных прафесійных мерапрыемствах і былі прысвечаны тэме DevOps і Docker. Адно відэа, з сустрэчы Docker Moscow у офісе Badoo, мы ўжо публікавалі на сайце. Новыя будуць суправаджацца артыкуламі, якія перадаюць сутнасць дакладаў. Такім чынам…
31 траўня на канферэнцыі RootConf 2016, якая праходзіла ў рамках фестывалю "Расійскія інтэрнэт-тэхналогіі" (РІТ++ 2016), секцыя "Бесперапыннае разгортванне і дэплой" адкрылася дакладам "Лепшыя практыкі Continuous Delivery з Docker". У ім былі абагульнены і сістэматызаваны лепшыя практыкі пабудовы працэсу Continuous Delivery (CD) з выкарыстаннем Docker і іншых Open Source-прадуктаў. З гэтымі рашэннямі мы працуем у production, што дазваляе абапірацца на практычны досвед.
Калі ў вас ёсць магчымасць выдаткаваць гадзіну на відэа з дакладам, рэкамендуемы паглядзець яго цалкам. У іншым выпадку - ніжэй прадстаўлена асноўная выцісканне ў тэкставым выглядзе.
Continuous Delivery з Docker
Пад бесперапынная пастаўка мы разумеем ланцужок мерапрыемстваў, у выніку якіх код прыкладання з Git-рэпазітара спачатку прыходзіць на production, а потым пападае ў архіў. Выглядае яна так: Git → Build (зборка) → Test (тэставанне) → Release (рэліз) → Operate (наступнае абслугоўванне).
Большая частка даклада прысвечана стадыі build (зборка дадатку), а тэмы release і operate закрануты аглядна. Размова пойдзе аб праблемах і патэрнах, якія дазваляюць іх вырашыць, а канкрэтныя рэалізацыі гэтых патэрнаў могуць быць рознымі.
Чаму тут увогуле патрэбен Docker? Не проста так мы вырашылі распавесці пра практыкі Continuous Delivery у кантэксце гэтага Open Source-інструмента. Хоць яго прымяненню прысвечаны ўвесь даклад, многія прычыны раскрываюцца ўжо пры разглядзе галоўнага патэрна выкату кода прыкладання.
Галоўны патэрн выкату
Такім чынам, пры выкаце новых версій прыкладання мы абавязкова сутыкаемся з праблемай прастою, які ўтвараецца падчас пераключэння production-сервера. Трафік са старой версіі дадатку на новую не можа пераключацца імгненна: папярэдне мы павінны пераканацца, што новая версія не толькі паспяхова выпампавана, але і «прагрэтая» (г.зн. цалкам гатовая да абслугоўвання запытаў).
Такім чынам, некаторы час абедзве версіі прыкладання (старая і новая) будуць працаваць адначасова. Што аўтаматычна прыводзіць да канфлікту агульных рэсурсаў: сеткі, файлавай сістэмы, IPC і да т.п. З Docker гэтая праблема лёгка вырашаецца запускам розных версій прыкладання ў асобных кантэйнерах, для якіх гарантуецца ізаляцыя рэсурсаў у рамках аднаго хаста (сервера/віртуальнай машыны). Вядома, можна абыйсціся некаторымі хітрыкамі і без ізаляцыі зусім, але калі існуе гатовая і зручная прылада, гэта значыць і зваротная рацыя - не грэбаваць ім.
Кантэйнерызацыя дае шмат іншых плюсаў пры дэплоі. Любы дадатак залежыць ад пэўнай версіі (або дыяпазону версій) інтэрпрэтатара, наяўнасці модуляў/пашырэнняў і да т.п., а таксама і іх версій. І ставіцца гэта не толькі да непасрэднага выкананага асяроддзя, але і да ўсяго асяроддзя ўключна сістэмны софт і яго версіі (аж да выкарыстоўванага Linux-дыстрыбутыва). Дзякуючы таму, што кантэйнеры ўтрымоўваюць не толькі код прыкладанняў, але і папярэдне ўсталяваны сістэмны і прыкладны софт патрэбных версій, аб праблемах з залежнасцямі можна забыцца.
Абагульнім галоўны патэрн выкату новых версій з улікам пералічаных фактараў:
Спачатку старая версія прыкладання працуе ў першым кантэйнеры.
Затым новая версія выкочваецца і выграваецца ў другім кантэйнеры. Характэрна, што сама гэтая новая версія можа несці не толькі абноўлены код прыкладання, але і любых яго залежнасцяў, а таксама сістэмных кампанентаў (напрыклад, новую версію OpenSSL ці ўсяго дыстрыбутыва).
Калі новая версія цалкам гатова да абслугоўвання запытаў, трафік перамыкаецца з першага кантэйнера на другі.
Цяпер старая версія можа быць спынена.
Такі падыход з разгортваннем розных версій прыкладання ў асобных кантэйнерах дае яшчэ адна зручнасць. хуткі адкат на старую версію (бо дастаткова пераключыць трафік на патрэбны кантэйнер).
Выніковая першая рэкамендацыя гучыць так, што нават Капітану не прычапіцца: «[пры арганізацыі Continuous Delivery з Docker]Выкарыстоўвайце Docker[і разумейце, што гэта дае]». Памятайце, што гэта не "сярэбраная куля", якая вырашае любыя праблемы, але інструмент, які дае выдатны падмурак.
Прайграванасць
Пад «узнаўляльнасць» мы разумеем абагульнены набор праблем, з якімі сустракаюцца пры эксплуатацыі прыкладанняў. Гаворка ідзе аб такіх выпадках:
Сцэнары, правераныя аддзелам якасці на staging, павінны сапраўды прайгравацца ў production.
Прыкладанні публікуюцца на серверах, якія могуць атрымаць пакеты з розных люстэркаў рэпазітароў (з часам яны абнаўляюцца, а разам з імі - і версіі усталёўваных прыкладанняў).
«У мяне лакальна ўсё працуе!» (… і распрацоўшчыкаў на production не пускаюць.)
Трэба праверыць нешта ў старой (архіўнай) версіі.
...
Агульная іх сутнасць зводзіцца да таго, што неабходна поўная адпаведнасць выкарыстоўваных акружэнняў (а таксама адсутнасць чалавечага фактару). Як жа гарантаваць узнаўляльнасць? Рабіць Docker-вобразы на базе кода з Git, а затым выкарыстоўваць іх для любых задач: на тэставых пляцоўках, у production, на лакальных машынах праграмістаў… Пры гэтым важна мінімізаваць дзеянні, якія выконваюцца пасля зборкі выявы: чым прасцей - тым менш верагоднасць памылак.
Інфраструктура - гэта код
Калі патрабаванні да інфраструктуры (наяўнасць сервернага ПЗ, яго версіі і да т.п.) не фармалізаваць і не "праграмаваць", то выкат любога абнаўлення прыкладання можа скончыцца сумнымі наступствамі. Напрыклад, на staging вы ўжо перайшлі на PHP 7.0 і перапісалі код якая адпавядае выявай – тады яго з'яўленне на production з якім-небудзь старым PHP (5.5) абавязкова кагосьці здзівіць. Хай пра буйную змену версіі інтэрпрэтатара вы не забудзецеся, але «д'ябал крыецца ў дэталях»: неспадзеўка можа апынуцца ў мінорным абнаўленні любой залежнасці.
Вырашальны гэтую праблему падыход вядомы як IaC (Infrastructure as Code, "інфраструктура як код") і мае на ўвазе захоўванне патрабаванняў да інфраструктуры разам з кодам прыкладання. Пры яго выкарыстанні распрацоўшчыкі і DevOps-спецыялісты могуць працаваць з адным Git-рэпазітаром прыкладання, але над рознымі яго часткамі. З гэтага кода ў Git ствараецца выява Docker, у якім прыкладанне разгорнута з улікам усёй спецыфікі інфраструктуры. Прасцей кажучы, скрыпты (правілы) зборкі выяў павінны ляжаць у адным рэпазітары з зыходнікамі і разам мроіцца.
У выпадку шматслаёвай архітэктуры прыкладання - напрыклад, ёсць nginx, які стаіць перад прыкладаннем, ужо запушчаным усярэдзіне Docker-кантэйнера, - выявы Docker павінны стварацца з кода ў Git для кожнага пласта. Тады ў першым вобразе будзе дадатак з інтэрпрэтатарам і іншымі "бліжэйшымі" залежнасцямі, а ў другім - вышэйстаячы nginx.
Docker-вобразы, сувязь з Git
Усе Docker-вобразы, якія збіраюцца з Git, мы падзяляем на дзве катэгорыі: часовыя і рэлізныя. Часовыя вобразы тэгуюцца па назове галінкі ў Git, могуць перазапісвацца чарговым коммітам і выкочваюцца толькі для папярэдняга прагляду (не для production). У гэтым іх ключавое адрозненне ад рэлізных: вы ніколі не ведаеце, які канкрэтна коміт у іх знаходзіцца.
Мае сэнс збіраць у часавыя выявы: галінку master (можна аўтаматычна выкочваць на асобную пляцоўку, каб стала бачыць бягучую версію master), галінкі з рэлізамі, галінкі пэўных новаўвядзенняў.
Пасля таго, як папярэдні прагляд часавых вобразаў прыходзіць да неабходнасці пераводу ў production, распрацоўшчыкі ставяць пэўны тэг. Па тэгу аўтаматычна збіраецца рэлізны вобраз (яго тэгу адпавядае тэг з Git) і выкочваецца на staging. У выпадку яго паспяховай праверкі аддзелам якасці ён пападае на production.
Дапп
Усё апісанае (выкат, зборку выяў, наступнае абслугоўванне) можна рэалізаваць самастойна з дапамогай Bash-скрыптоў і іншых «падручных» сродкаў. Але калі так рабіць, то ў нейкі момант рэалізацыя прывядзе да вялікай складанасці і дрэннай кіравальнасці. Разумеючы гэта, мы дашлі да стварэння сваёй спецыялізаванай Workflow-утыліты для пабудовы CI/CD. Дапп.
Яе зыходны код напісаны на Ruby, адкрыты і апублікаваны на GitHub. На жаль, дакументацыя на дадзены момант - самае слабое месца інструмента, але мы працуем над гэтым. І яшчэ не раз напішам і раскажам пра dapp, т.я. нам шчыра не церпіцца падзяліцца яго магчымасцямі з усёй зацікаўленай супольнасцю, а пакуль дасылайце свае issues і pull requests і/ці сочыце за развіццём праекту на GitHub.
Абноўлена 13 жніўня 2019 г.: у цяперашні час праект Дапп перайменаваны ў werf, яго код цалкам перапісаны на Go, а дакументацыя значна палепшана.
Kubernetes
Іншы гатовы Open Source-інструмент, ужо атрымаў значнае прызнанне ў прафесійным асяроддзі, - гэта Kubernetes, кластар для кіравання Docker. Тэма яго выкарыстання ў эксплуатацыі праектаў, пабудаваных на Docker, выходзіць за рамкі даклада, таму выступленне абмежавана аглядам некаторых цікавых магчымасцяў.
Для выкату Kubernetes прапануе:
readiness probe - праверку гатоўнасці новай версіі прыкладання (для пераключэння трафіку на яе);
rolling update - паслядоўнае абнаўленне выявы ў кластары з кантэйнераў (адключэнне, абнаўленне, падрыхтоўка да запуску, пераключэнне трафіку);
synchronous update - абнаўленне выявы ў кластары з іншым падыходам: спачатку на палове кантэйнераў, затым на астатніх;
canary releases - запуск новай выявы на абмежаванай (невялікай) колькасці кантэйнераў для маніторынгу анамалій.
Паколькі Continuous Delivery – гэта не толькі рэліз новай версіі, у Kubernetes ёсць шэраг магчымасцяў для наступнага абслугоўвання інфраструктуры: убудаваны маніторынг і лагіраванне па ўсіх кантэйнерах, аўтаматычнае маштабаванне і інш. Усё гэта ўжо працуе і толькі чакае пісьменнага ўкаранення ў вашыя працэсы.
Выніковыя рэкамендацыі
Выкарыстоўвайце Docker.
Рабіце Docker-вобразы прыкладання для ўсіх патрэб.
Выконвайце прынцыпу «Інфраструктура - гэта код».
Звяжыце Git з Docker.
Рэгламентуйце парадак выкату.
Выкарыстоўвайце гатовую платформу (Kubernetes ці іншую).
Відэа і слайды
Відэа з выступу (каля гадзіны) апублікавана ў YouTube(непасрэдна даклад пачынаецца з 5-й хвіліны – па спасылцы прайграванне з гэтага моманту).