Ndërtimi dinamik dhe shpërndarja e imazheve Docker me werf përmes shembujve të faqes së dokumentacionit të versionuar

Kemi kemi treguar pĂ«r mjetin tonĂ« GitOps mĂ« parĂ«, werf, dhe kĂ«tĂ« herĂ« dĂ«shirojmĂ« tĂ« ndajmĂ« pĂ«rvojĂ«n e ndĂ«rtimit tĂ« faqes me dokumentacionin e projektit vetĂ« — werf.io (versioni i tij nĂ« gjuhĂ«n ruse — ru.werf.io). Ky Ă«shtĂ« njĂ« faqe statike e zakonshme, megjithatĂ« ndĂ«rtimi i saj Ă«shtĂ« interesant sepse Ă«shtĂ« ndĂ«rtuar duke pĂ«rdorur njĂ« numĂ«r dinamik artekfesh.

Ndërtimi dinamik dhe shpërndarja e imazheve Docker me werf përmes shembujve të faqes së dokumentacionit të versionuar

Nuk do tĂ« hyjmĂ« nĂ« detajet e strukturĂ«s sĂ« faqes: gjenerimi i menusĂ« sĂ« pĂ«rbashkĂ«t pĂ«r tĂ« gjitha versionet, faqet me informacion mbi lĂ«shimet dhe tĂ« tjera — nĂ« vend tĂ« kĂ«saj, do tĂ« pĂ«rqendrohemi nĂ« pyetje dhe veçori tĂ« ndĂ«rtimit dinamik dhe pak mbi proceset pĂ«rkatĂ«se CI/CD.

Hyrje: si funksionon faqja

Së pari, dokumentacioni për werf ruhet së bashku me kodin e tij. Kjo parashtron kërkesa të caktuara për zhvillim, të cilat, në përgjithësi, tejkalojnë kornizën e këtij artikulli, por të paktën mund të thuhet se:

  • Funksionet e reja tĂ« werf nuk duhet tĂ« dalin pa pĂ«rditĂ«simin e dokumentacionit dhe, pĂ«rkundrazi, çdo ndryshim nĂ« dokumentacionin nĂ«nkupton njĂ« version tĂ« ri tĂ« werf;
  • Projekti ka njĂ« zhvillim tĂ« intensifikuar: versione tĂ« reja mund tĂ« dalin disa herĂ« nĂ« ditĂ«;
  • Çdo operacion manual pĂ«r deploy-in e faqes me njĂ« version tĂ« ri tĂ« dokumentacionit Ă«shtĂ« tĂ« paktĂ«n lodhĂ«s;
  • NĂ« projekt Ă«shtĂ« pranuar njĂ« qasje semantike versionimi, me 5 kanale stabiliteti. Procesi i lĂ«shimit parashikon kalimin e versioneve pĂ«rmes kanaleve nĂ« rendin e rritjes sĂ« stabilitetit: nga alpha nĂ« rock-solid;
  • Faqja ka njĂ« version nĂ« gjuhĂ«n ruse, i cili "jeton dhe zhvillohet" (dmth, pĂ«rmbajtja e saj pĂ«rditĂ«sohet) paralelisht me versionin kryesor (dmth, versionin nĂ« anglisht).

PĂ«r tĂ« fshehur nga pĂ«rdoruesi tĂ« gjithĂ« kĂ«tĂ« "kuchinĂ« e brendshme", duke i ofruar atij atĂ« qĂ« "thjesht funksionon", ne kemi bĂ«rĂ« njĂ« mjet tĂ« veçantĂ« pĂ«r instalimin dhe pĂ«rditĂ«simin e werf — kjo Ă«shtĂ« multiwerf. Mjafton tĂ« specifikoni numrin e lĂ«shimit dhe kanalin e stabilitetit qĂ« jeni tĂ« gatshĂ«m tĂ« pĂ«rdorni, dhe multiwerf do tĂ« kontrollojĂ« nĂ«se ka njĂ« version tĂ« ri nĂ« kanal dhe do ta shkarkojĂ« nĂ«se Ă«shtĂ« e nevojshme.

NĂ« menunĂ« e zgjedhjes sĂ« versioneve nĂ« faqe janĂ« tĂ« disponueshme versionet mĂ« tĂ« fundit tĂ« werf nĂ« secilin kanal. NĂ« mĂ«nyrĂ« tĂ« parazgjedhur, nĂ« adresĂ«n werf.io/documentation hapet versioni mĂ« stabil i kanalit pĂ«r lĂ«shimin mĂ« tĂ« fundit — ai gjithashtu indeksohet nga motorĂ«t e kĂ«rkimit. Dokumentacioni pĂ«r kanalin Ă«shtĂ« i disponueshĂ«m nĂ« adresa tĂ« veçanta (pĂ«r shembull, werf.io/v1.0-beta/documentation pĂ«r lĂ«shimin beta 1.0).

Kështu, faqja ka versionet e mëposhtme të disponueshme:

  1. rrënjësore (hapesht automatikisht),
  2. për çdo kanal aktiv azhurnimesh të çdo lëshimi (për shembull, werf.io/v1.0-beta).

Për të gjeneruar një version të caktuar të faqes, në përgjithësi mjafton të kryeni përpunimin e saj me ndihmën e Jekyll, duke e ekzekutuar në katalogun /docs të depozitës werf komandën përkatëse (jekyll build), duke u kaluar më parë në etiketën Git të versionit të nevojshëm.

Ngeli vetëm të shtojmë se:

  • pĂ«r ndĂ«rtimin pĂ«rdoret vetĂ« mjeti (werf);
  • proceset CI/CD janĂ« ndĂ«rtuar mbi bazĂ«n e GitLab CI;
  • dhe e gjithĂ« kjo, sigurisht, funksionon nĂ« Kubernetes.

Detyrat

Tani do të formulojmë detyrat që marrin parasysh të gjithë këtë specifikë:

  1. Pas ndryshimit të versionit të werf në çdo kanal azhurnimesh dokumentacioni në faqe duhet të azhurnohet automatikisht.
  2. Për zhvillimin, duhet të kemi mundësinë që ndonjëherë të shikojmë versionet paraprake të faqes.

Rikompilimi i faqes duhet të bëhet pas ndryshimit të versionit në çdo kanal nga etiketat përkatëse Git, por gjatë procesit të ndërtimit të imazhit ne do të marrë këto veçori:

  • Pasi lista e versioneve nĂ« kanale ndryshon, duhet tĂ« rikompilohet vetĂ«m dokumentacioni pĂ«r kanalet ku Ă«shtĂ« ndryshuar versioni. Sepse rikompilimi i tĂ« gjithĂ«ve nga e para nuk Ă«shtĂ« shumĂ« kĂ«ndshĂ«m.
  • I gjithĂ« seti i kanaleve pĂ«r lĂ«shimet mund tĂ« ndryshojĂ«. NĂ« njĂ« moment tĂ« caktuar, pĂ«r shembull, mund tĂ« mos ketĂ« version nĂ« kanale mĂ« tĂ« qĂ«ndrueshme se lĂ«shimi i hershĂ«m 1.1, por me kalimin e kohĂ«s ata do tĂ« shfaqen — a nuk do ta ndryshojmĂ« atĂ« nĂ« kĂ«tĂ« rast me duar?

Kështu, ndërtimi varet nga të dhënat e jashtme që ndryshojnë.

Realizimi

Zgjedhja e qasjes

Si një opsion, mund të ekzekutoni çdo version të nevojshëm si një pod të veçantë në Kubernetes. Ky opsion nënkupton një numër më të madh objektesh në klaster, i cili do të rritet me rritjen e numrit të lëshimeve të qëndrueshme të werf. Dhe kjo nga ana tjetër nënkupton mbështetje më të komplikuar: për çdo version ka një server HTTP specifik, që ndonjëherë është edhe me një ngarkesë të vogël. Sigurisht, kjo sjell dhe shpenzime më të mëdha për burime.

Ne shkuam nĂ« rrugĂ«n e ndĂ«rtimit tĂ« tĂ« gjithĂ« versioneve tĂ« nevojshme nĂ« njĂ« imazh. Statika e pĂ«rpunuar e tĂ« gjithĂ« versioneve tĂ« faqes ndodhet nĂ« njĂ« kontejner me NGINX, ndĂ«rsa trafiku nĂ« pĂ«rkatĂ«sin Deployment vjen pĂ«rmes NGINX Ingress. StrukturĂ« e thjeshtĂ« — aplikacion stateless — lejon lehtĂ«sisht tĂ« shkallĂ«zojĂ« Deployment (nĂ« varĂ«si tĂ« ngarkesĂ«s) me ndihmĂ«n e vetĂ« Kubernetes.

Nëse duam të jemi më të saktë, ne mblidhni dy imazhe: një për linjën production dhe një tjetër si shtesë për linjën dev. Imazhi shtesë përdoret (ekzekutohet) vetëm në linjën dev së bashku me të parin dhe përmban versionin e faqes nga komiti i rishikimit, ndërsa ruterimi mes tyre bëhet nëpërmjet burimeve Ingress.

werf vs git clone dhe artefaktet

Siç u përmend më parë, për të gjeneruar statikën e faqes për një version të caktuar të dokumentacionit, është e nevojshme të kryhet ndërtimi duke kaluar në tagun përkatës në repositor. Mund të bëhej gjithashtu duke klonuar repositorin çdo herë kur kryhej ndërtimi, duke zgjedhur tag-et përkatëse nga lista. Megjithatë, kjo është një operacion mjaft kërkues në burime dhe kërkon gjithashtu shkruajtjen e udhëzimeve jo triviale... Një minus tjetër serioz është se me këtë qasje nuk ka mundësi për të ruajtur diçka në cache gjatë ndërtimit.

Këtu na ndihmon vetë utilitari werf, i cili implementon kërkimin e mençur dhe lejon përdorimin e repositorio të jashtme. Përdorimi i werf për të shtuar kod nga repositor do të përshpejtojë ndërtimin, sepse werf në thelb e klonon repositorin një herë dhe pastaj kryen vetëm fetch kur është e nevojshme. Për më tepër, kur shtojmë të dhëna nga repositor, mund të zgjedhim vetëm direktoret e nevojshme (në rastin tonë kjo është katalogu docs), duke reduktuar ndjeshëm sasinë e të dhënave që po shtohen.

Duke qenë se Jekyll është një mjet i destinuar për kompilimin e statikës dhe nuk është i nevojshëm në imazhin përfundimtar, do të kishte kuptim të kryhej kompilimi në artefaktin werf, dhe në imazhin përfundimtar të importohej vetëm rezultati i kompilimit.

Shkruajmë werf.yaml

Pra, ne kemi vendosur që do të kompilojmë çdo version në një artefakt të veçantë werf. Megjithatë, ne nuk e dimë sa artefaktë do të kemi gjatë ndërtimit, prandaj nuk mund të shkruajmë një konfigurim të fiksuar të ndërtimit (ndoshta mundemi, por kjo nuk do të ishte shumë efikase).

werf lejon përdorimin e shablloneve Go në skedarin e tij të konfigurimit (werf.yaml), dhe kjo ofron mundësinë për të gjeneruar konfigurimin "në flakë" në varësi të të dhënave të jashtme (çfarë na nevojitet!). Të dhënat e jashtme në rastin tonë përfaqësojnë informacionin mbi versionet dhe lëshimet, mbi të cilat ne grumbullojmë sasinë e nevojshme të artefaktëve dhe arrijmë përfundimisht në dy imazhe: werf-doc dhe werf-dev përdorim në kontura të ndryshme.

Të dhënat e jashtme kalohen përmes variablave të mjedisit. Këtu janë komponentët e tyre:

  • RILASJET — njĂ« varg me listĂ«n e rilaseve dhe versionin aktual tĂ« werf, nĂ« formĂ«n e njĂ« liste me vlera qĂ« ndahen me hapĂ«sira nĂ« formatin %. Shembull: 1.0%v1.0.4-beta.20
  • KANALIT — njĂ« varg me listĂ«n e kanaleve dhe versionin pĂ«rkatĂ«s tĂ« werf, nĂ« formĂ«n e njĂ« liste me vlera qĂ« ndahen me hapĂ«sira nĂ« formatin %. Shembull: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • VERSIONI_RRIZ — versioni i rilasit werf qĂ« shfaqet si parazgjedhje nĂ« faqe (nuk Ă«shtĂ« gjithmonĂ« e nevojshme tĂ« shfaqet dokumentacioni pĂ«r numrin mĂ« tĂ« lartĂ« tĂ« rilasit). Shembull: v1.0.4-beta.20
  • REVIEW_SHA — heshja e commit-it review, nga e cila duhet tĂ« ndĂ«rtohet versioni pĂ«r konturin testues.

KĂ«ta variabla do tĂ« plotĂ«sohen nĂ« pipeline GitLab CI, dhe si pikĂ«risht — Ă«shtĂ« shkruar mĂ« poshtĂ«.

Së pari, për lehtësinë, do të përcaktojmë në werf.yaml variablat e shabllonit Go, duke u caktuar atyre vlerat nga variablat e mjedisit:

{{ $_ := set . "WerfVersions" (cat (env "CHANNELS") (env "RELEASES") | splitList " ") }}
{{ $Root := . }}
{{ $_ := set . "WerfRootVersion" (env "ROOT_VERSION") }}
{{ $_ := set . "WerfReviewCommit" (env "REVIEW_SHA") }}

PĂ«rshkrimi i artefaktit pĂ«r kompaktimin e statikĂ«s sĂ« versionit tĂ« faqes Ă«shtĂ« gjithmonĂ« i njĂ«jtĂ« pĂ«r tĂ« gjitha rastet qĂ« na nevojiten (pĂ«rfshirĂ«, gjenerimin e versionit rrĂ«njor, si dhe versionin pĂ«r konturin dev). Prandaj, do ta nxjerrim atĂ« nĂ« njĂ« bllok tĂ« veçantĂ« pĂ«rmes funksionit pĂ«rcakto — pĂ«r ripĂ«rtĂ«ritjen e mĂ«vonshme pĂ«rmes include. Shabllonit do t'i kalojmĂ« argumentet e mĂ«poshtme:

  • Version — versionin e gjeneruar (emri i etiketĂ«s);
  • Kanal — emrin e kanalit tĂ« azhurnimeve, pĂ«r tĂ« cilin gjenerohet artefakti;
  • Commit — heshja e commit-it, nĂ«se artefakti gjenerohet pĂ«r commit-in review;
  • konkret.

Përshkrimi i shabllonit të artefaktit

{{- define "doc_artifact" -}}
{{- $Root := index . "Root" -}}
artefakti: doc-{{ .Channel }}
nga: jekyll/builder:3
montim:
- nga: build_dir
  te: /usr/local/bundle
ansible:
  instalo:
  - shell: |
      export PATH=/usr/jekyll/bin/:$PATH
  - emër: "Instalo Varësitë"
    shell: bundle install
    args:
      executable: /bin/bash
      chdir: /app/docs
  paraSetup:
{{- if .Commit }}
  - shell: echo "Rishiko SHA - {{ .Commit }}."
{{- end }}
{{- if eq .Channel "root" }}
  - emër: "releases.yml HASH: {{ $Root.Files.Get "releases.yml" | sha256sum }}"
    kopjo:
      përmbajtja: |
{{ $Root.Files.Get "releases.yml" | indent 8 }}
      destinacion:  /app/docs/_data/releases.yml
{{- else }}
  - skedar:
      rruga: /app/docs/_data/releases.yml
      gjendje: touch
{{- end }}
  - skedar:
      rruga: "{{`{{ item }}`}}"
      gjendje: directory
      moda: 0777
    me_items:
    - /app/main_site/
    - /app/ru_site/
  - skedar:
      destinacion: /app/docs/pages_ru/cli
      gjendje: link
      src: /app/docs/pages/cli
  - shell: |
      echo -e "werfVersion: {{ .Version }}nwerfChannel: {{ .Channel }}" > /tmp/_config_additional.yml
      export PATH=/usr/jekyll/bin/:$PATH
{{- if and (ne .Version "review") (ne .Channel "root") }}
{{- $_ := set . "BaseURL" ( printf "v%s" .Channel ) }}
{{- else if ne .Channel "root" }}
{{- $_ := set . "BaseURL" .Channel }}
{{- end }}
      jekyll build -s /app/docs  -d /app/_main_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/tmp/_config_additional.yml
      jekyll build -s /app/docs  -d /app/_ru_site/{{ if .BaseURL }} --baseurl /{{ .BaseURL }}{{ end }} --config /app/docs/_config.yml,/app/docs/_config_ru.yml,/tmp/_config_additional.yml
    args:
      executable: /bin/bash
      chdir: /app/docs
git:
- url: https://github.com/flant/werf.git
  te: /app/
  pronar: jekyll
  grup: jekyll
{{- if .Commit }}
  commit: {{ .Commit }}
{{- else }}
  etiket: {{ .Version }}
{{- end }}
  varësitëEstadës:
    instalo: ['docs/Gemfile','docs/Gemfile.lock']
    paraSetup: '**/*'
  përfshijRrugët: 'docs'
  përjashtimRrugët: '**/*.sh'
{{- end }}

Emri i artefaktit duhet të jetë unik. Ne mund ta arrijmë këtë, për shembull, duke shtuar emrin e kanalit (vlera e variables .Channel) si sufix të emrit të artefaktit: artefakti: doc-{{ .Channel }}. Por është e rëndësishme të kuptojmë se gjatë importit nga artefaktet do të nevojitet të referohemi me emra të tillë.

Gjatë përshkrimit të artefaktit përdoret mundësia e werf, si montim. Montimi me specifikimin e drejtorisë shërbimet build_dir lejon ruajtjen e nërllogarive Jekyll midis ekzekutimeve të pipeline-it, çka shpejton ndjeshëm rindërimin.

Gjithashtu, mund tĂ« keni vĂ«nĂ« re pĂ«rdorimin e skedarit releases.yml — ky Ă«shtĂ« njĂ« skedar YAML me tĂ« dhĂ«na rreth lĂ«shimeve, i kĂ«rkuar nga github.com (artefakti qĂ« merret gjatĂ« ekzekutimit tĂ« pipeline-it). Ai Ă«shtĂ« i nevojshĂ«m gjatĂ« kompilimit tĂ« sitit, por nĂ« kontekstin e kĂ«tij artikulli Ă«shtĂ« i rĂ«ndĂ«sishĂ«m sepse gjendja e tij pĂ«rcakton rinndĂ«rimin vetĂ«m tĂ« njĂ« artefakti — artefakti i versionit themelor (nĂ« artefaktet e tjera ai nuk Ă«shtĂ« i nevojshĂ«m).

Kjo realizohet falë operatorëve të kushtit nëse shabllonet Go dhe strukturës {{ $Root.Files.Get "releases.yml" | sha256sum }} në fazën stadës. Kjo funksionon në këtë mënyrë: gjatë ndërtimit të artefaktit për versionin rrënjësor (variabli .Channel e barabartë me root) hash-i i skedarit releases.yml ndikon në nënshkrimin e të gjithë fazës, pasi ai është një komponent i emrit të detyrës Ansible (parametri emri). Prandaj, kur ndryshohet përmbajtja, e skedarit releases.yml artefakti përkatës do të rbuild.

Merrni parasysh gjithashtu punën me depo të jashtme. Në imazhin e artefaktit nga depoja werf, shtohet vetëm katalogu /docs, dhe varësisht nga parametrat e dhënë, shtohen të dhëna të etiketës së nevojshme ose komitit për shqyrtim.

Për të përdorur shabllonin e artefaktit për të gjeneruar përshkrimin e artefaktit të versioneve të kanaleve dhe lëshimeve të dhëna, organizojmë një cikël mbi variablën .WerfVersions në werf.yaml:

{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ dict "Version" $VersionsDict._1 "Channel" $VersionsDict._0 "Root" $Root | include "doc_artifact" }}
---
{{ end -}}

Pasi cikli do tĂ« gjenerojĂ« disa artefakte (shpresojmĂ« pĂ«r kĂ«tĂ«), Ă«shtĂ« e nevojshme tĂ« merret parasysh ndarĂ«si midis tyre — sekuenca --- (mĂ« shumĂ« rreth sintaksĂ«s sĂ« skedarit tĂ« konfigurimit shih nĂ« dokumentacion). Siç u pĂ«rcaktua mĂ« parĂ«, kur thĂ«rrasim shabllonin nĂ« cikĂ«l, ne kalojmĂ« parametrat e versionit, URL-nĂ« dhe kontekstin rrĂ«njor.

Në mënyrë të ngjashme, por tashmë pa cikël, thërrasim shabllonin e artefaktit për "rastet speciale": për versionin rrënjësor, si dhe versionin nga komiti për shqyrtim:

{{ dict "Version" .WerfRootVersion "Channel" "root" "Root" $Root  | include "doc_artifact" }}
---
{{- if .WerfReviewCommit }}
{{ dict "Version" "review" "Channel" "review" "Commit" .WerfReviewCommit "Root" $Root  | include "doc_artifact" }}
{{- end }}

Vini re se artefakti për komitin e shqyrtimit do të ndërtohet vetëm nëse variabli .WerfReviewCommit.

Artefaktet janĂ« gati — Ă«shtĂ« koha pĂ«r import!

Imazhi përfundimtar, i destinuar për të funksionuar në Kubernetes, është një NGINX i zakonshëm, në të cilin është shtuar një skedar konfigurimi serveri nginx.conf dhe statikat nga artefaktet. Përveç artefaktit të versionit rrënjor të faqes, na nevojitet të përsërisim ciklin mbi variantin .WerfVersions për të importuar artefaktet e versioneve të kanaleve dhe lëshimeve + mbajti në konsideratë rregullin e emërtimeve të artefakteve që pranuam më parë. Pasi çdo artefakt mban versionet e faqes për dy gjuhë, i importojmë ato në vendet e parashikuara nga konfigurimi.

Përshkrimi i imazhit përfundimtar werf-doc

image: werf-doc
from: nginx:stable-alpine
ansible:
  setup:
  - name: "Setup /etc/nginx/nginx.conf"
    copy:
      content: |
{{ .Files.Get ".werf/nginx.conf" | indent 8 }}
      dest: /etc/nginx/nginx.conf
  - file:
      path: "{{`{{ item }}`}}"
      state: directory
      mode: 0777
    with_items:
    - /app/main_site/assets
    - /app/ru_site/assets
import:
- artifact: doc-root
  add: /app/_main_site
  to: /app/main_site
  before: setup
- artifact: doc-root
  add: /app/_ru_site
  to: /app/ru_site
  before: setup
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ $Channel := $VersionsDict._0 -}}
{{ $Version := $VersionsDict._1 -}}
- artifact: doc-{{ $Channel }}
  add: /app/_main_site
  to: /app/main_site/v{{ $Channel }}
  before: setup
{{ end -}}
{{ range .WerfVersions -}}
{{ $VersionsDict := splitn "%" 2 . -}}
{{ $Channel := $VersionsDict._0 -}}
{{ $Version := $VersionsDict._1 -}}
- artifact: doc-{{ $Channel }}
  add: /app/_ru_site
  to: /app/ru_site/v{{ $Channel }}
  before: setup
{{ end -}}

Imazhi shtesë, e cila përfshihet me atë kryesoren në dev-environment, përmban vetëm dy versione të faqes: versionin nga review-commit dhe versionin bazë të faqes (aty janë asetet e përbashkëta dhe, nëse e mbani mend, të dhënat e lëshimeve). Kështu, imazhi shtesë do të dallojë nga ai kryesor vetëm për seksionin e importit (sigurisht, edhe për emrin):

image: werf-dev
...
import:
- artifact: doc-root
  add: /app/_main_site
  to: /app/main_site
  before: setup
- artifact: doc-root
  add: /app/_ru_site
  to: /app/ru_site
  before: setup
{{- if .WerfReviewCommit  }}
- artifact: doc-review
  add: /app/_main_site
  to: /app/main_site/review
  before: setup
- artifact: doc-review
  add: /app/_ru_site
  to: /app/ru_site/review
  before: setup
{{- end }}

Siç u përmend më parë, artefakti për review-commit do të gjenerohet vetëm kur aktivizohet variabla i ambientit REVIEW_SHA. Do të ishte e mundur të mos gjeneronit fare imazhin werf-dev, nëse nuk ka variabla ambienti REVIEW_SHA, por që për pastrimin sipas politikave Imazheve Docker në werf do të funksiononte për imazhin werf-dev, ne do ta lejojmë atë të ndihmojë vetëm me artefaktin e versionit bazë (sidoqoftë, ai tashmë është ndërtuar), për të thjeshtuar strukturën e pipeline.

Ndërtimi është gati! Tani kalojmë në CI/CD dhe nuancat e rëndësishme.

Pipeline në GitLab CI dhe veçoritë e ndërtimit dinamik

Gjatë ndërtimit, na nevojitet të vendosim variablat e ambientit të përdorura në werf.yaml. Kjo nuk i ndikon variablës REVIEW_SHA, e cila do të vendoset gjatë thirrjes së pipeline nga hook-u i GitHub.

Krijimi i të dhënave të nevojshme jashtë do të zhvillohet në një skript Bash generate_artifacts, e cila do të krijojë dy artefakte për pipeline GitLab:

  • skedari releases.yml me tĂ« dhĂ«nat pĂ«r lĂ«shimet,
  • skedari common_envs.sh, qĂ« pĂ«rmban variablat e ambientit pĂ«r eksport.

Përmbajtja e skedarit generate_artifacts do ta gjeni në repo me shembuj. Marrja e të dhënave nuk është temë e këtij artikulli, por skedari common_envs.sh është i rëndësishëm për ne, pasi varësia nga ai përcakton funksionimin e werf. Një shembull i përmbajtjes së tij:

export RELEASES='1.0%v1.0.6-4'
export CHANNELS='1.0-alpha%v1.0.7-1 1.0-beta%v1.0.7-1 1.0-ea%v1.0.6-4 1.0-stable%v1.0.6-4 1.0-rock-solid%v1.0.6-4'
export ROOT_VERSION='v1.0.6-4'

Përdorimi i një skenari të tillë mund të realizohet, për shembull, me një funksion Bash source.

Dhe tani vjen pjesa më interesante. Që ndërtimi dhe deployment-i i aplikacionit të funksionojnë siç duhet, është e nevojshme të sigurohet që werf.yaml u të njëjtë minimumi në kuadër të një pipeline. Nëse ky kusht nuk përmbushet, atëherë nënshkrimet e fazave që llogarit werf gjatë ndërtimit dhe, për shembull, në momentin e deployment-it, do të jenë të ndryshme. Kjo do të çojë në një gabim në deployment, pasi imazhi i nevojshëm për deployment do të mungojë.

Me fjalë të tjera, nëse gjatë ndërtimit të imazhit të faqes informacioni mbi publikimet dhe versionet është një, ndërsa në momentin e deployment-it del një version i ri dhe variablat e mjedisit kanë vlera të tjera, atëherë deployment-i do të përfundojë me gabim: sepse artefakti i versionit të ri ende nuk është ndërtuar.

Nëse gjenerimi werf.yaml varet nga të dhëna të jashtme (p.sh., lista e versioneve aktuale, si në rastin tonë), atëherë përbërja dhe vlerat e këtyre të dhënave duhet të fiksohen brenda pipeline-it. Kjo është veçanërisht e rëndësishme nëse parametrat e jashtëm ndryshojnë mjaft shpesh.

Ne do të sigurojmë dhe fiksojmë të dhënat e jashtme në fazën e parë të pipeline-it në GitLab (Prebuild) dhe do t'i kalojmë ato më tej si artefakt GitLab CI. Kjo do të lejojë që të nisni dhe ribëni detyrat e pipeline-it (ndërtimi, deployment-i, pastrimi) me konfigurim të njëjtë në werf.yaml.

Përmbajtja e fazës Prebuild e skedarit .gitlab-ci.yml:

Prebuild:
  stage: prebuild
  script:
    - bash ./generate_artifacts 1> common_envs.sh
    - cat ./common_envs.sh
  artifacts:
    paths:
      - releases.yml
      - common_envs.sh
    expire_in: 2 week

Pas fiksohjes së të dhënave të jashtme në artefakt, mund të realizoni ndërtimin dhe deployment-in duke përdorur faza standarde të pipeline-it GitLab CI: Build dhe Deploy. Ne e nisim pipeline-in nëpërmjet hooks nga repository GitHub i werf (dmth. në rast të ndryshimeve në repository-n në GitHub). Të dhënat për to mund të merren nga pronësitë e projektit GitLab në seksionin CI / CD Settings -> Pipeline triggers, dhe më pas do të krijojmë në GitHub webhook-un përkatës (Settings -> Webhooks).

Faza e ndërtimit do të duket si më poshtë:

Build:
  stage: build
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - werf build-and-publish --stages-storage :local
  except:
    refs:
      - schedules
  dependencies:
    - Prebuild

GitLab do tĂ« shtojĂ« nĂ« fazĂ«n e ndĂ«rtimit dy artefakte nga faza Prebuild, kĂ«shtu qĂ« ne eksportojmĂ« variablat me tĂ« dhĂ«nat e pĂ«rgatitura hyrĂ«se nĂ«pĂ«rmjet strukturĂ«s source common_envs.sh. Nisemi fazĂ«n e ndĂ«rtimit nĂ« tĂ« gjitha rastet, pĂ«rveç nisjes sĂ« pipeline-sĂ« sipas orarit. Sipas orarit, ne do tĂ« nisnim njĂ« pipeline pĂ«r pastrimin — nĂ« kĂ«tĂ« rast nuk Ă«shtĂ« e nevojshme tĂ« kryhet ndĂ«rtimi.

NĂ« fazĂ«n e shpĂ«rndarjes do tĂ« pĂ«rshkruajmĂ« dy detyra — veçmas pĂ«r shpĂ«rndarjen nĂ« konturet production dhe dev, duke pĂ«rdorur njĂ« template YAML:

.base_deploy: &base_deploy
  stage: deploy
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - werf deploy --stages-storage :local
  dependencies:
    - Prebuild
  except:
    refs:
      - schedules

Deploy to Production:
  <<: *base_deploy
  variables:
    WERF_KUBE_CONTEXT: prod
  environment:
    name: production
    url: werf.io
  only:
    refs:
      - master
  except:
    variables:
      - $REVIEW_SHA
    refs:
      - schedules

Deploy to Test:
  <<: *base_deploy
  variables:
    WERF_KUBE_CONTEXT: dev
  environment:
    name: test
    url: werf.test.flant.com
  except:
    refs:
      - schedules
  only:
    variables:
      - $REVIEW_SHA

Detyrat në thelb ndryshojnë vetëm me përcaktimin e kontekstit të klasterit, në të cilin werf duhet të kryejë shpërndarjen (WERF_KUBE_CONTEXT), dhe vendosjen e variablave mjedisorë të konturit (environment.name dhe environment.url), të cilat përdoren më pas në shabllonet e Helm-chart. Nuk do të paraqesim përmbajtjen e shablloneve, sepse aty nuk ka asgjë interesante për temën që po diskutojmë, por ju mund t'i gjeni në repozitorin e artikullit.

Detaji përfundimtar

Duke qenĂ« se versionet e werf dalin mjaft shpesh, do tĂ« ndodhin shpesh edhe ndĂ«rtimin e imazheve tĂ« reja, dhe Docker Registry — do tĂ« rritet vazhdimisht. Prandaj, Ă«shtĂ« e nevojshme tĂ« konfigurohet pastrimi automatik i imazheve sipas politikave. TĂ« bĂ«sh kĂ«tĂ« Ă«shtĂ« shumĂ« e thjeshtĂ«.

Për implementimin, do të nevojitet:

  • Shtoni njĂ« fazĂ« pastrimi nĂ« .gitlab-ci.yml;
  • Shtoni ekzekutimin periodik tĂ« detyrĂ«s sĂ« pastrimit;
  • Konfiguroni njĂ« variabĂ«l mjedisor me token e aksesit pĂ«r shkrim.

Shtojmë fazën e pastrimit në .gitlab-ci.yml:

Cleanup:
  stage: cleanup
  script:
    - type multiwerf && . $(multiwerf use 1.0 alpha --as-file)
    - type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
    - source common_envs.sh
    - docker login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${WERF_IMAGES_REPO}
    - werf cleanup --stages-storage :local
  only:
    refs:
      - schedules

K almost gjithçka qĂ« e kemi parĂ« mĂ« sipĂ«r — vetĂ«m pĂ«r pastrimin duhet tĂ« identifikohesh mĂ« parĂ« nĂ« Docker Registry me njĂ« token qĂ« ka tĂ« drejta pĂ«r tĂ« fshirĂ« imazhet nĂ« Docker Registry (tokeni qĂ« merret automatikisht nga detyrat e GitLab CI nuk ka kĂ«to tĂ« drejta). Duhet tĂ« krijoni tokenin paraprakisht nĂ« GitLab dhe tĂ« pĂ«rcaktoni vlerĂ«n e tij nĂ« variablin e mjedisit WERF_IMAGES_CLEANUP_PASSWORD projekti (CI/CD Settings -> Variables).

Shtimi i detyrës së pastrimit me orarin e nevojshëm bëhet në CI/CD ->
Schedules
.

Të gjitha: projekti në Docker Registry nuk do të rritet më për shkak të imazheve të papërdorura.

Në përfundim të pjesës praktike, po ju rikujtoj se listat e plota nga artikulli janë në dispozicion në Git:

Rezultati

  1. Kemi marrë një strukturë logjike ndërtimi: një artefakt për një version.
  2. Ndërtimi është universale dhe nuk kërkon ndryshime manuale me daljen e versioneve të reja të werf: dokumentacioni në faqe përditësohet automatikisht.
  3. Mblidhen dy imazhe për konture të ndryshme.
  4. Puna Ă«shtĂ« e shpejtĂ«, pasi shfrytĂ«zohet sa mĂ« shumĂ« mundĂ«sitĂ« e memorizimit — kur del njĂ« version i ri i werf ose kur aktivizohet njĂ« GitHub hook pĂ«r review-commit, ndodh pĂ«rsĂ«ri ndĂ«rtimi vetĂ«m i artefaktit pĂ«rkatĂ«s me versionin e ndryshuar.
  5. Nuk është e nevojshme të mendohet për fshirjen e imazheve të papërdorura: pastrimi sipas politikave të werf do të mbajë rendin në Docker Registry.

Përfundimet

  • PĂ«rdorimi i werf lejon ndĂ«rtimin tĂ« funksionojĂ« shpejt falĂ« memorizimit si tĂ« ndĂ«rtimit, ashtu edhe tĂ« punĂ«s me depo extern.
  • Puna me depo Git tĂ« jashtme shmang nevojĂ«n pĂ«r tĂ« klonuar depozitĂ«n çdo herĂ« plotĂ«sisht ose pĂ«r tĂ« shpikur njĂ« logjikĂ« tĂ« komplikuar optimizimi. werf pĂ«rdor memorizimin dhe bĂ«n klonimin vetĂ«m njĂ« herĂ«, dhe mĂ« pas pĂ«rdor fetch dhe vetĂ«m sipas nevojĂ«s.
  • MundĂ«sia e pĂ«rdorimit tĂ« shablloneve Go nĂ« skedarin e konfigurimit tĂ« ndĂ«rtimit werf.yaml lejon pĂ«rshkrimin e ndĂ«rtimit, rezultat i tĂ« cilit varet nga tĂ« dhĂ«nat e jashtme.
  • PĂ«rdorimi i montimit nĂ« werf e shpejton ndĂ«rtimin e artefakteve — pĂ«rmes keshit, i cili Ă«shtĂ« i pĂ«rbashkĂ«t pĂ«r tĂ« gjitha pipeline.
  • werf lejon lehtĂ«sisht tĂ« konfigurohet pastrimi, qĂ« Ă«shtĂ« veçanĂ«risht e rĂ«ndĂ«sishme nĂ« ndĂ«rtimin dinamik.

P.S.

Lexoni gjithashtu në blogun tonë:

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster