Content-based tagging у зборшчыку werf: навошта і як гэта працуе?

Content-based tagging у зборшчыку werf: навошта і як гэта працуе?

werf - Наша GitOps CLI-ўтыліта з адкрытым кодам для зборкі і дастаўкі прыкладанняў у Kubernetes. У рэлізе v1.1 была прадстаўлена новая магчымасць у зборшчыку вобразаў: тэгіраванне вобразаў па змесціва або content-based tagging. Да гэтага часу тыповая схема тэгавання ў werf меркавала тэгіраванне Docker-вобразаў па Git-тэгу, Git-галінцы або Git-каміту. Але ва ўсіх гэтых схемах ёсць недахопы, якія цалкам вырашаюцца новай стратэгіяй тэгавання. Падрабязнасці пра яе і чым яна такая добрая - пад катом.

Выкат набору мікрасэрвісаў з аднаго Git-рэпазітара

Часта сустракаецца сітуацыя, калі дадатак разбіты на мноства больш-менш незалежных сэрвісаў. Рэлізы гэтых сэрвісаў могуць адбывацца незалежна: за адзін раз можа рэлізавацца адзін ці некалькі сэрвісаў, астатнія пры гэтым павінны працягваць працаваць без якіх-небудзь змен. Але з пункту гледжання захоўвання кода і кіравання праектам зручней трымаць такія сэрвісы прыкладання ў адзіным рэпазітары.

Бываюць сітуацыі, калі сэрвісы сапраўды незалежныя і не злучаны з адным дадаткам. У такім разе яны будуць размешчаны ў асобных праектах і іх рэліз будзе ажыццяўляцца праз асобныя працэсы CI/CD у кожным з праектаў.

Аднак у рэальнасці распрацоўнікі часцяком разбіваюць адзінае прыкладанне на некалькі мікрасэрвісаў, але заводзіць для кожнага асобны рэпазітар і праект… – відавочны overkill. Менавіта пра гэтую сітуацыю і пойдзе далей гаворка: некалькі такіх мікрасэрвісаў ляжаць у адзіным рэпазітары праекту і рэлізы адбываюцца праз адзіны працэс у CI/CD.

Тэгіраванне па Git-галінцы і Git-тэгу

Дапушчальны, выкарыстоўваецца самая распаўсюджаная стратэгія тэгавання. tag-or-branch. Для Git-галінак выявы тэгуюцца назовам галінкі, для адной галіны ў адзін момант часу існуе толькі адна апублікаваная выява па імі гэтай галінкі. Для Git-тэгаў вобразы тэгуюцца адпаведна імем тэга.

Пры стварэнні новага Git-тэга - напрыклад, пры выхадзе новай версіі - для ўсіх вобразаў праекта ў Docker Registry будзе створаны новы Docker-тэг:

  • myregistry.org/myproject/frontend:v1.1.10
  • myregistry.org/myproject/myservice1:v1.1.10
  • myregistry.org/myproject/myservice2:v1.1.10
  • myregistry.org/myproject/myservice3:v1.1.10
  • myregistry.org/myproject/myservice4:v1.1.10
  • myregistry.org/myproject/myservice5:v1.1.10
  • myregistry.org/myproject/database:v1.1.10

Гэтыя новыя імёны выяў трапляюць праз Helm-шаблоны ў канфігурацыю Kubernetes. Пры запуску дэплоя камандай werf deploy адбываецца абнаўленне поля image у маніфестах рэсурсаў Kubernetes і перазапуск адпаведных рэсурсаў з-за які змяніўся імя выявы.

праблема: у выпадку, калі рэальна з папярэдняга выкату (Git-тэга) не змянілася змесціва выявы, а толькі яго Docker-тэг, адбываецца лішні перазапуск гэтага прыкладання і, адпаведна, магчымы некаторы просты. Хаця не было ніякіх рэальных прычын вырабляць гэты перазапуск.

Як следства, пры бягучай схеме тэгавання даводзіцца гарадзіць некалькі асобных Git-рэпазітароў і ўстае праблема арганізацыі выкату гэтых некалькіх рэпазітароў. Увогуле такая схема атрымліваецца перагружанай і складанай. Лепш аб'ядноўваць шмат сэрвісаў у адзіны рэпазітар і ствараць такія Docker-тэгі, каб лішніх перазапускаў не было.

Тэгіраванне па Git-каміту

У werf таксама прысутнічае стратэгія тэгавання, звязаная з Git-камітамі.

Git-commit з'яўляецца ідэнтыфікатарам змесціва Git-рэпазітара і залежыць ад гісторыі правак файлаў у Git-рэпазітары, таму здаецца лагічным выкарыстоўваць яго для тэгавання выяў у Docker Registry.

Аднак тэгаванне па Git-каміту мае тыя ж недахопы, што і па Git-галінках або Git-тэгам:

  • Мог быць створаны пусты коміт, які не мяняе файлаў, а Docker-тэг выявы будзе зменены.
  • Мог быць створаны merge-комміт, які не мяняе файлаў, а Docker-тэг выявы будзе зменены.
  • Мог быць створаны коміт, які змяняе тыя файлы ў Git, якія не імпартуюцца ў выяву, а Docker-тэг выявы зноў будзе зменены.

Тэгаванне па імі Git-галінкі не адлюстроўвае версію выявы

Ёсць і яшчэ адна праблема, звязаная са стратэгіяй тэгавання па Git-галінках.

Тэгіраванне па імені галінкі працуе да таго часу, пакуль коміты гэтай галінкі збіраюць паслядоўна ў храналагічным парадку.

Калі ў бягучай схеме карыстач запусціць пересборку старога коммита, злучанага з некаторай галінкай, то werf ператрэ вобраз па які адпавядае Docker-тэгу ізноў сабранай версіяй выявы для старога коммита. Якія выкарыстоўваюць гэты тэг Deployment'ы з гэтага моманту рызыкуюць падчас перазапуску pod'ов зрабіць pull іншай версіі выявы, у выніку чаго наша дадатак страціць сувязь з CI-сістэмай, рассінхранізуецца.

Акрамя таго, пры паслядоўных push'ах у адну галінку з малым прамежкам часу паміж імі стары коміт можа сабрацца пазней, чым навейшы: старая версія выявы ператрэ новую па тэгу Git-галінкі. Такія праблемы можа вырашаць CI/CD-сістэма (напрыклад, у GitLab CI для серыі комітаў запускаецца pipeline апошняга). Аднак гэта падтрымліваюць не ўсе сістэмы і павінен быць больш надзейны спосаб прадухілення гэтак фундаментальнай праблемы.

Што такое content-based tagging?

Такім чынам, што ж такое content-based tagging - тэгіраванне вобразаў па змесціва.

Для стварэння Docker-тэгаў выкарыстоўваюцца не прымітывы Git'а (Git-галінка, Git-тэг…), а кантрольная сума, звязаная з:

  • змесцівам вобраза. Ідэнтыфікатар-тэг выявы адлюстроўвае яго змесціва. Пры зборцы новай версіі гэты ідэнтыфікатар не памяняецца, калі ў выяве не змяніліся файлы;
  • гісторыяй стварэння гэтай выявы ў Git. Выявы, звязаныя з рознымі Git-галінкамі і рознай гісторыяй зборкі праз werf, будуць мець розныя тэгі-ідэнтыфікатары.

У якасці такога тэга-ідэнтыфікатара выступае так званая сігнатура стадый выявы.

Кожная выява складаецца з набору стадый: from, before-install, git-archive, install, imports-after-install, before-setup, ... git-latest-patch і г.д. У кожнай стадыі ёсць ідэнтыфікатар, які адлюстроўвае яе змесціва, - сігнатура стадыі (stage signature).

Фінальны ж вобраз, які складаецца з гэтых стадый, тэгуецца так званай сігнатурай набору гэтых стадый. stages signature, - Якая з'яўляецца абагульняючай для ўсіх стадый выявы.

У кожнай выявы з канфігурацыі werf.yaml у агульным выпадку будзе свая такая сігнатура і, адпаведна, Docker-тэг.

Сігнатура стадый вырашае ўсе названыя праблемы:

  • Устойлівая да пустых Git-камітаў.
  • Устойлівая да Git-каммітаў, якія змяняюць файлы, якія не з'яўляюцца рэлевантнымі для выявы.
  • Не прыводзіць да праблемы з пераціраннем актуальнай версіі выявы пры перазапуску зборак для старых Git-камітаў галінкі.

Цяпер гэта рэкамендуемая стратэгія тэгавання і выкарыстоўваецца па змаўчанні ў werf для ўсіх CI-сістэм.

Як уключыць і выкарыстоўваць у werf

Адпаведная опцыя з'явілася ў каманды werf publish: --tag-by-stages-signature=true|false

У CI-сістэме стратэгія тэгавання задаецца камандай werf ci-env. Раней для яе вызначаўся параметр werf ci-env --tagging-strategy=tag-or-branch. Цяпер, калі паказаць werf ci-env --tagging-strategy=stages-signature ці не паказваць гэтую опцыю, werf па змаўчанні будзе выкарыстоўваць стратэгію тэгавання stages-signature. Каманда werf ci-env аўтаматычна выставіць патрэбныя сцягі для каманды werf build-and-publish (Або werf publish), таму ніякіх дадатковых опцый для гэтых каманд паказваць не трэба.

Напрыклад, каманда:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-by-stages-signature

… можа стварыць наступныя выявы:

  • registry.hello.com/web/core/system/backend:4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d
  • registry.hello.com/web/core/system/frontend:f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6

Тут 4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d - гэта сігнатура стадый выявы backend, А f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6 - Сігнатура стадый выявы frontend.

Пры выкарыстанні спецыяльных функцый werf_container_image и werf_container_env у шаблонах Helm нічога змяняць не патрабуецца: гэтыя функцыі будуць аўтаматычна генераваць дакладныя імёны выяў.

Прыклад канфігурацыі ў CI-сістэме:

type multiwerf && source <(multiwerf use 1.1 beta)
type werf && source <(werf ci-env gitlab)
werf build-and-publish|deploy

Больш інфармацыі па наладзе даступна ў дакументацыі:

Разам

  • Новая опцыя werf publish --tag-by-stages-signature=true|false.
  • Новае значэнне опцыі werf ci-env --tagging-strategy=stages-signature|tag-or-branch (калі не паказаць, то па змаўчанні будзе stages-signature).
  • Калі да гэтага выкарыстоўваліся опцыі тэгавання па Git-камітах (WERF_TAG_GIT_COMMIT або опцыя werf publish --tag-git-commit COMMIT), то абавязкова пераключаць на стратэгію тэгавання stages-signature.
  • Новыя праекты лепш адразу пераключаць на новую схему тэгавання.
  • Старыя праекты пры перакладзе на werf 1.1 пажадана пераключаць на новую схему тэгавання, аднак старая tag-or-branch па-ранейшаму падтрымліваецца.

Content-based tagging вырашае ўсе асветленыя ў артыкуле праблемы:

  • Устойлівасць імя Docker-тэга да пустых Git-камітаў.
  • Устойлівасць імя Docker-тэга да Git-каммітаў, якія змяняюць нерэлевантныя для выявы файлы.
  • Не прыводзіць да праблемы з пераціраннем актуальнай версіі выявы пры перазапуску зборак для старых Git-камітаў для Git-галінак.

Карыстайцеся! І не забывайце зазіраць да нас на GitHub, Каб стварыць issue або знайсці ўжо існуючы, паставіць плюс, стварыць PR ці проста паназіраць за развіццём праекта.

PS

Чытайце таксама ў нашым блогу:

Крыніца: habr.com

Дадаць каментар