Мяне клічуць Зміцер Сугробаў, я распрацоўшчык у «Леруа Мерлен». У артыкуле распавяду, навошта патрэбен Helm, як ён спрашчае працу з Kubernetes, што памянялася ў трэцяй версіі і як з яго дапамогай абнаўляць прыкладанні ў прадакшэне без прастою.
"Леруа Мерлен" – лідэр на рынку DIY-рытэйла ў Расіі і Еўропе. У нашай кампаніі больш за сто распрацоўшчыкаў, 33 унутраных супрацоўнікаў і велізарная колькасць людзей, якія наведваюць гіпермаркеты і сайт. Для таго, каб зрабіць усіх іх шчаслівымі, мы вырашылі прытрымлівацца стандартных падыходаў у індустрыі. Распрацоўваць новыя прыкладанні, выкарыстоўваючы мікрасэрвісную архітэктуру; для ізаляцыі акружэнняў і правільнай дастаўкі выкарыстоўваць кантэйнеры; а для аркестрацыі выкарыстоўваць Kubernetes. Кошт выкарыстання аркестратараў імкліва таннее: на рынку расце колькасць інжынераў, якія валодаюць тэхналогіяй, з'яўляюцца правайдэры, якія прапануюць Kubernetes як сэрвіс.
Усё, што робіць Kubernetes, вядома, можна зрабіць іншымі спосабамі, напрыклад, абшмараваўшы скрыптамі які-небудзь Джэнкінс і docker-compose, але навошта ўскладняць жыццё, калі ёсць гатовае і надзейнае рашэнне? Таму мы прыйшлі да Kubernetes і ўжо год яго выкарыстоўваем у прадакшэне. Цяпер у нас дваццаць чатыры кластары Kubernetes, самаму старому з іх больш за год, у ім каля двухсот падоў.
Праклён вялікай колькасці YAML-файлаў у Kubernetes
Для запуску мікрасэрвісу ў Kubernetes створым па меншай меры пяць YAML-файлаў: для Deployment, Service, Ingress, ConfigMap, Secrets – і адправім у кластар. Для наступнага прыкладання напішам той жа пакет ямлікаў, з трэцім - яшчэ адзін і гэтак далей. Памножым колькасць дакументаў на колькасць асяродкаў, ужо атрымаем сотні файлаў, і гэта яшчэ не ўлічваючы дынамічныя асяроддзі.
Варыянт працоўны, але даводзіцца шмат разоў капіяваць YAML-файлы. Каб гэты цыкл змяніць, і прыдумалі Helm.
Што такое Helm
Па-першае, Helm - пакетны менеджэр, які дапамагае знаходзіць і ўсталёўваць патрэбныя праграмы. Для ўстаноўкі, напрыклад, MongoDB не трэба заходзіць на афіцыйны сайт і спампоўваць бінарнікі, дастаткова выканаць каманду helm install stable/mongodb.
Па-другое, Helm - шаблонізатар, дапамагае параметрызаваць файлы. Вернемся да сітуацыі з YAML-файламі ў Kubernetes. Прасцей напісаць той жа файл YAML, дадаць у яго некаторыя placeholder-ы, у якія Helm падставіць значэнні. Гэта значыць, замест вялікага набору ямлікаў будзе набор темплейтов (шаблонаў), у якія ў патрэбны момант падставяцца патрэбныя значэння.
Па-трэцяе, Helm майстар па разгортванні. З яго дапамогай можна ўсталёўваць, адкочваць і абнаўляць прыкладанні. Давайце разбяромся, як гэта рабіць.
Як карыстацца Helm для дэплою ўласных прыкладанняў
Усталюем Helm кліент на кампутар, прытрымліваючыся афіцыйнай інструкцыі. Затым створым набор YAML-файлаў. Замест указання канкрэтных значэнняў пакінем плэйсхолдэры, якія ў будучыні Helm запоўніць інфармацыяй. Набор такіх файлаў называецца Helm чарт. У кансольны кліент Helm яго можна адправіць трыма спосабамі:
пазначыць татачку з шаблонамі;
спакаваць у .tar архіў і паказаць на яго;
пакласці шаблон у выдалены рэпазітар і дадаць спасылку на рэпазітар у Helm кліент.
Яшчэ патрэбен файл са значэннямі - values.yaml. Дадзеныя адтуль будуць падстаўляцца ў шаблон. Створым і яго.
У другой версіі Helm ёсць дадатковы серверны дадатак – Tiller. Яно вісіць звонку Kubernetes і чакае запыты ад Helm-кліента, а пры выкліку падстаўляе патрэбныя значэнні ў шаблон і адпраўляе ў Kubernetes.
Helm 3 уладкованы прасцей: замест апрацоўкі шаблонаў на серверы, інфармацыя зараз апрацоўваецца цалкам на боку Helm-кліента і адпраўляецца напроста ў Kubernetes API. Гэта спрашчэнне павялічвае бяспеку кластара і палягчае схему выкату.
Як усё гэта працуе
Запускаем каманду helm install. Укажам назву рэлізу прыкладання, дадзім шлях да values.yaml. У канцы пакажам рэпазітар, у якім ляжыць чарт і назва чарта. У прыкладзе гэта "lmru" і "bestchart" адпаведна.
Выкананне каманды магчыма толькі аднойчы, пры паўторным выкананні замест install трэба выкарыстоўваць upgrade. Для прастаты замест дзвюх каманд можна выконваць каманду upgrade з дадатковым ключом --install. Пры першым выкананні Helm адправіць каманду на ўстаноўку рэлізу, а ў далейшым будзе яго абнаўляць.
Падводныя камяні дэплою новых версій прыкладання з Helm
У гэтым месцы апавядання я гуляю з залай у «Хто хоча стаць мільянерам», і мы высвятляем, як прымусіць Helm абнавіць версію прыкладання. глядзець відэа.
Калі я вывучаў працу Helm, мяне здзівілі дзіўныя паводзіны пры спробе абнаўлення версій запушчаных прыкладанняў. Код прыкладання абнавіў, у докер-рэджыстры загрузіў новую выяву, адправіў каманду на дэплой - і нічога не адбылося. Ніжэй некалькі не зусім удалых спосабаў абнаўлення дадаткаў. Вывучаючы кожны з іх больш падрабязна, пачынаеш разумець унутраную прыладу прылады і чыннікі такіх не відавочных паводзін.
Спосаб 1. Не мяняць інфармацыю з моманту апошняга запуску
Як абвяшчае афіцыйны сайт Helm, "Kubernetes чарты бываюць вялікімі і складанымі, таму Helm імкнецца лішні раз нічога не чапаць". Таму, калі абнавіць latest-версію выявы прыкладання ў docker registry і выканаць каманду helm upgrade, то нічога не адбудзецца. Helm будзе думаць, што нічога не памянялася і пасылаць у Kubernetes каманду на абнаўленне прыкладання не трэба.
Тут і далей тэг latest паказаны выключна ў якасці прыкладу. Пры ўказанні гэтага тэга Kubernetes будзе кожны раз спампоўваць выяву з docker registry, па-за залежнасцю ад параметра imagePullPolicy. Выкарыстанне latest ў прадакшэне непажадана і выклікае пабочныя эфекты.
Спосаб 2. Абнаўляць LABEL у image
Як напісана ў той жа дакументацыі, «Helm будзе абнаўляць прыкладанне, толькі калі яно памянялася з моманту апошняга рэлізу». Лагічным варыянтам для гэтага здасца абнаўленне пазнакі LABEL у самім докер-выяве. Аднак Helm не зазірае ў выявы прыкладанняў і не мае паняцці аб якія-небудзь зменах у іх. Адпаведна, пры абнаўленні метак у выяве Helm пра іх не пазнае, і каманда абнаўлення прыкладання ў Kubernetes не паступіць.
Спосаб 3. Выкарыстоўваць ключ --force
Звернемся да мануалаў і пашукаем патрэбны ключык. Больш за ўсё па сэнсе падыходзіць ключ --force. Нягледзячы на размаўлялую назву, паводзіны адрозніваюцца ад чаканага. Замест фарсіраванага абнаўлення прыкладання, яго рэальнае прызначэнне - аднаўленне які знаходзіцца ў статусе FAILED рэлізу. Калі не выкарыстоўваць гэты ключ, тое трэба паслядоўна выконваць каманды helm delete && helm install --replace. Замест гэтага прапануецца выкарыстоўваць ключ --force, які аўтаматызуе паслядоўнае выкананне гэтых каманд. Больш інфармацыі ў гэтым пул-рэквест. Для таго каб сказаць Helm усёткі абнавіць версію прыкладання, нажаль, гэты ключ не падыдзе.
Спосаб 4. Змяняць labels напрамую ў Kubernetes
Абнаўленне label напрамую ў кластары з дапамогай каманды kubectl edit - дрэнная ідэя. Гэта дзеянне прывядзе да некансістэнтнасці інфармацыі паміж працуючым дадаткам і тым, што першапачаткова адправілася на дэплой. Паводзіны Helm пры дэплоі ў гэтым выпадку адрозніваецца ад яго версіі: Helm 2 нічога рабіць не будзе, а Helm 3 задэплоіць новую версію прыкладання. Для разумення прычыны трэба зразумець, як працуе Helm.
Як уладкованы Helm
Для вызначэння, ці змянілася прыкладанне з моманту апошняга рэлізу, Helm можа скарыстацца:
запушчаным дадаткам у Kubernetes;
новым values.yaml і актуальным чартам;
унутранай інфармацыяй Helm аб рэлізах.
Для самых дапытлівых: дзе Helm захоўвае ўнутраную інфармацыю аб рэлізах?Выканаўшы каманду helm history, мы атрымаем усю інфармацыю аб версіях, устаноўленых з дапамогай Helm.
Яшчэ ёсць падрабязная інфармацыя аб адпраўленых шаблонах і значэннях. Мы можам яе запытаць:
У другой версіі Helm гэтая інфармацыя ляжыць у тым жа неймспейсе, дзе запушчаны Tiller (па змаўчанні - kube-system), у ConfigMap, пазначаным пазнакай «OWNER=TILLER»:
У момант з'яўлення трэцяй версіі Helm інфармацыя пераехала ў сакрэты, прычым у той жа неймспейс, дзе запушчана дадатак. Дзякуючы гэтаму стала магчыма запускаць адначасова некалькі прыкладанняў у розных неймспейсах з аднолькавай назвай рэлізу. У другой версіі гэта быў моцны галаўны боль, калі неймспейсы ізаляваныя, але могуць сябар на сябра ўплываць.
Другі Helm, калі спрабуе зразумець, ці трэба абнаўленне, выкарыстоўвае толькі дзве крыніцы інфармацыі: тое, што яму падалі цяпер, і ўнутраную інфармацыю аб рэлізах, якая ляжыць у ConfigMap.
Трэці Helm выкарыстоўвае стратэгію three-way merge: у дадатак да той інфармацыі ўлічвае яшчэ і дадатак, якое працуе прама зараз у Kubernetes.
Па гэтым чынніку старая версія Helm не будзе нічога рабіць, бо не ўлічвае інфармацыю прыкладання ў кластары, а вось Helm 3 атрымае змены і адправіць новае прыкладанне на дэплой.
Спосаб 5. Выкарыстоўваць ключ -recreate-pods
З дапамогай ключа --recreate-pods можна дасягнуць таго, што першапачаткова планавалася атрымаць з дапамогай ключа --force. Кантэйнеры перазапусцяць і, паводле палітыкі imagePullPolicy: Always для тэга latest (пра гэта ў зносцы вышэй), Kubernetes запампуе і запусціць новую версію выявы. Рабіць будзе гэта не самай лепшай выявай: не ўлічваючы StrategyType дэплойменту, рэзка выключыць усе старыя інстансы прыкладання і пайдзе запускаць новыя. Падчас перазапуску сістэма не будзе працаваць, карыстачы будуць пакутаваць.
У самым Kubernetes падобная праблема таксама існавала працяглы час. І вось, праз 4 гады пасля адкрыцця Пытанне, праблему выправілі, і пачынальна з 1.15 версіі Kubernetes з'яўляецца магчымасць rolling-restart подаў.
Helm жа проста выключае ўсе прыкладанні і запускае побач новыя кантэйнеры. У прадакшэне так рабіць нельга, каб не выклікаць просты прыкладанні. Такое трэба толькі для патрэб распрацоўкі, можна выконваць толькі ў stage-акружэннях.
Як абнавіць версію прыкладання з дапамогай Helm?
Будзем мяняць значэння, якія адпраўляюцца ў Helm. Як правіла, гэта значэння, якія падстаўляюцца на месца тэга выявы. У выпадку latest, часта выкарыстоўванага для непрадуктыўных асяродкаў, у ролі змянянай інфармацыі выступае анатацыя, якая для самога Kubernetes бескарысная, а для Helm будзе выступаць сігналам да неабходнасці абнаўлення прыкладання. Варыянты запаўнення значэння анатацыі:
Рандомнае значэнне з дапамогай стандартнай функцыі - {{ randAlphaNum 6 }}.
Ёсць нюанс: пасля кожнага дэплою з выкарыстаннем чарта з такой зменнай значэнне анатацыі будзе ўнікальным, і Helm будзе меркаваць, што ёсць змены. Атрымліваецца, заўсёды будзем перазапускаць дадатак, нават калі не памянялі яго версію. Гэта не крытычна, бо прастою не будзе, але ўсё ж непрыемна.
Устаўляць бягучую дату і час - {{ .Release.Date }}.
Варыянт падобны на рандомнае значэнне з стала ўнікальнай зменнай.
Больш правільны спосаб - выкарыстоўваць кантрольныя сумы. Гэта SHA выявы або SHA апошняга комміта ў гіце {{ .Values.sha }}.
Іх трэба будзе падлічваць і адпраўляць у Helm кліент на задзірлівым боку, напрыклад у Джэнкінсе. Калі дадатак памянялася, то і кантрольная сума памяняецца. Такім чынам, Helm будзе абнаўляць дадатак толькі тады, калі трэба.
Падагульнім нашы спробы
Helm робіць змены найменш інвазіўным спосабам, таму любая змена на ўзроўні выявы прыкладання ў Docker Registry не прывядзе да абнаўлення: пасля выканання каманды нічога не адбудзецца.
ключ --force выкарыстоўваецца для аднаўлення праблемных рэлізаў і не злучаны з прымусовым абнаўленнем.
ключ --recreate-pods прымусова абновіць прыкладанні, але зробіць гэта вандальным спосабам: рэзка выключыць усе кантэйнеры. Ад гэтага пацерпяць карыстачы, на продзе так рабіць не варта.
Напрамую ўносіць змены ў кластар Kubernetes з дапамогай каманды kubectl edit не трэба: парушым кансістэнтнасць, а паводзіны будуць адрознівацца ў залежнасці ад версіі Helm.
З выхадам новай версіі Helm з'явілася шмат нюансаў. Issues у рэпазітары Helm апісаны зразумелай мовай, яны дапамогуць разабрацца ў дэталях.
Даданне змененай анатацыі ў чарт зробіць яго больш гнуткім. Гэта дазволіць выкочваць прыкладанне правільна, без прастою.
Думка з разраду "мір ва ўсім свеце", якая працуе ва ўсіх сферах жыцця: чытайце інструкцыю перад ужываннем, а не пасля. Толькі валодаючы поўнай інфармацыяй, атрымаецца будаваць надзейныя сістэмы і рабіць карыстачоў шчаслівымі.