Dynamic na pagpupulong at pag-deploy ng mga larawan ng Docker na may werf gamit ang halimbawa ng isang site ng dokumentasyong may bersyon

Napag-usapan na namin ang tungkol sa aming tool sa GitOps nang higit sa isang beses. werf, at sa pagkakataong ito nais naming ibahagi ang aming karanasan sa pag-assemble ng site kasama ang dokumentasyon ng proyekto mismo - werf.io (ang bersyon nitong Ruso ay en.werf.io). Ito ay isang ordinaryong static na site, ngunit ang pagpupulong nito ay kawili-wili dahil ito ay binuo gamit ang isang dynamic na bilang ng mga artifact.

Dynamic na pagpupulong at pag-deploy ng mga larawan ng Docker na may werf gamit ang halimbawa ng isang site ng dokumentasyong may bersyon

Pumunta sa mga nuances ng istraktura ng site: pagbuo ng isang karaniwang menu para sa lahat ng mga bersyon, mga pahina na may impormasyon tungkol sa mga release, atbp. - hindi namin gagawin. Sa halip, tumuon tayo sa mga isyu at tampok ng dynamic na pagpupulong at kaunti sa mga kasamang proseso ng CI/CD.

Panimula: kung paano gumagana ang site

Upang magsimula, ang dokumentasyon ng werf ay naka-imbak kasama ang code nito. Nagpapataw ito ng ilang mga kinakailangan sa pag-unlad na sa pangkalahatan ay lampas sa saklaw ng artikulong ito, ngunit sa pinakamababa ay masasabing:

  • Ang mga bagong function ng werf ay hindi dapat ilabas nang hindi ina-update ang dokumentasyon at, sa kabaligtaran, ang anumang mga pagbabago sa dokumentasyon ay nagpapahiwatig ng pagpapalabas ng isang bagong bersyon ng werf;
  • Ang proyekto ay may medyo masinsinang pag-unlad: ang mga bagong bersyon ay maaaring ilabas ng ilang beses sa isang araw;
  • Ang anumang mga manu-manong operasyon upang mag-deploy ng isang site na may bagong bersyon ng dokumentasyon ay hindi bababa sa nakakapagod;
  • Ang proyekto ay gumagamit ng isang semantikong diskarte versioning, na may 5 stability channel. Ang proseso ng paglabas ay nagsasangkot ng sunud-sunod na pagpasa ng mga bersyon sa pamamagitan ng mga channel sa pagkakasunud-sunod ng pagtaas ng katatagan: mula alpha hanggang rock-solid;
  • Ang site ay may bersyon sa wikang Ruso, na "nabubuhay at umuunlad" (i.e., ang nilalaman nito ay ina-update) kaayon ng pangunahing (ibig sabihin, Ingles-wika) na bersyon.

Upang itago ang lahat ng "inner kitchen" na ito mula sa user, nag-aalok sa kanya ng isang bagay na "gumagana lang", ginawa namin hiwalay na tool sa pag-install at pag-update ng werf - Ay multiwerf. Kailangan mo lang tukuyin ang release number at ang stability channel na handa mong gamitin, at titingnan ng multiwerf kung may bagong bersyon sa channel at i-download ito kung kinakailangan.

Sa menu ng pagpili ng bersyon sa website, available ang pinakabagong mga bersyon ng werf sa bawat channel. Bilang default, ayon sa address werf.io/documentation bubukas ang bersyon ng pinaka-stable na channel para sa pinakabagong release - na-index din ito ng mga search engine. Ang dokumentasyon para sa channel ay makukuha sa magkahiwalay na mga address (halimbawa, werf.io/v1.0-beta/documentation para sa beta release 1.0).

Sa kabuuan, ang site ay may mga sumusunod na bersyon na magagamit:

  1. ugat (bubukas bilang default),
  2. para sa bawat aktibong channel sa pag-update ng bawat release (halimbawa, werf.io/v1.0-beta).

Upang makabuo ng isang partikular na bersyon ng isang site, sa pangkalahatan, ito ay sapat na upang i-compile ito gamit Jekyllsa pamamagitan ng pagtakbo sa direktoryo /docs werf repository na kaukulang utos (jekyll build), pagkatapos lumipat sa Git tag ng kinakailangang bersyon.

Ito ay nananatili lamang upang idagdag na:

  • ang utility mismo (werf) ay ginagamit para sa pagpupulong;
  • Ang mga proseso ng CI/CD ay binuo batay sa GitLab CI;
  • at lahat ng ito, siyempre, ay tumatakbo sa Kubernetes.

gawain

Ngayon, bumalangkas tayo ng mga gawain na isinasaalang-alang ang lahat ng inilarawan na mga detalye:

  1. Matapos baguhin ang bersyon ng werf sa anumang channel ng pag-update ang dokumentasyon sa site ay dapat na awtomatikong na-update.
  2. Para sa pag-unlad kailangan mong magagawang minsan tingnan ang mga preview na bersyon ng site.

Dapat na muling i-compile ang site pagkatapos baguhin ang bersyon sa anumang channel mula sa kaukulang mga tag ng Git, ngunit sa proseso ng pagbuo ng imahe ay makukuha natin ang mga sumusunod na feature:

  • Dahil nagbabago ang listahan ng mga bersyon sa mga channel, kailangan lang na muling buuin ang dokumentasyon para sa mga channel kung saan nagbago ang bersyon. Pagkatapos ng lahat, ang muling pagtatayo ng lahat ay hindi masyadong maganda.
  • Maaaring magbago ang hanay ng mga channel para sa mga release. Sa ilang sandali, halimbawa, maaaring walang bersyon sa mga channel na mas matatag kaysa sa early-access na 1.1 na release, ngunit sa paglipas ng panahon ay lilitaw ang mga ito - sa kasong ito, hindi ba dapat mong manual na baguhin ang assembly?

Ito ay lumiliko ang na ang pagpupulong ay nakasalalay sa pagbabago ng panlabas na data.

Pagpapatupad

Pagpili ng Diskarte

Bilang kahalili, maaari mong patakbuhin ang bawat kinakailangang bersyon bilang isang hiwalay na pod sa Kubernetes. Ang opsyong ito ay nagpapahiwatig ng mas malaking bilang ng mga bagay sa cluster, na lalago sa pagtaas ng bilang ng mga stable na paglabas ng werf. At ito naman, ay nagpapahiwatig ng mas kumplikadong pagpapanatili: ang bawat bersyon ay may sariling HTTP server, at may maliit na pagkarga. Siyempre, nangangailangan din ito ng mas malaking gastos sa mapagkukunan.

Pareho kami ng landas pagsasama-sama ng lahat ng kinakailangang bersyon sa isang larawan. Ang pinagsama-samang statics ng lahat ng bersyon ng site ay matatagpuan sa isang lalagyan na may NGINX, at ang trapiko sa kaukulang Deployment ay dumarating sa NGINX Ingress. Ang isang simpleng istraktura - isang stateless na application - ay nagbibigay-daan sa iyong madaling sukatin ang Deployment (depende sa load) gamit ang Kubernetes mismo.

Upang maging mas tumpak, kumukolekta kami ng dalawang larawan: isa para sa production circuit, ang pangalawa ay karagdagang isa para sa dev circuit. Ang karagdagang larawan ay ginagamit (inilunsad) lamang sa dev circuit kasama ang pangunahing isa at naglalaman ng bersyon ng site mula sa review commit, at ang pagruruta sa pagitan ng mga ito ay isinasagawa gamit ang mga mapagkukunan ng Ingress.

werf vs git clone at artifacts

Tulad ng nabanggit na, upang makabuo ng mga static ng site para sa isang partikular na bersyon ng dokumentasyon, kailangan mong bumuo sa pamamagitan ng paglipat sa naaangkop na tag ng repositoryo. Magagawa mo rin ito sa pamamagitan ng pag-clone ng repositoryo sa tuwing bubuo ka, pagpili ng naaangkop na mga tag mula sa isang listahan. Gayunpaman, ito ay isang medyo resource-intensive na operasyon at, bukod dito, nangangailangan ng pagsusulat ng mga di-maliit na tagubilin... Ang isa pang malubhang kawalan ay na sa diskarteng ito ay walang paraan upang i-cache ang isang bagay sa panahon ng pagpupulong.

Dito ang werf utility mismo ay tumulong sa amin, nagpapatupad matalinong pag-cache at nagpapahintulot sa iyo na gamitin mga panlabas na imbakan. Ang paggamit ng werf upang magdagdag ng code mula sa repositoryo ay makabuluhang mapabilis ang pagbuo, dahil Werf mahalagang clone ang repositoryo ng isang beses at pagkatapos ay executes lamang fetch kung kinakailangan. Bilang karagdagan, kapag nagdaragdag ng data mula sa imbakan, maaari lamang naming piliin ang mga kinakailangang direktoryo (sa aming kaso ito ang direktoryo docs), na makabuluhang bawasan ang dami ng idinagdag na data.

Dahil ang Jekyll ay isang tool na idinisenyo para sa pag-compile ng static na data at hindi kailangan sa huling larawan, magiging lohikal na mag-compile sa artifact ng werf, at sa huling larawan i-import lamang ang resulta ng compilation.

Nagsusulat kami ng werf.yaml

Kaya, nagpasya kaming i-compile namin ang bawat bersyon sa isang hiwalay na artifact ng werf. Gayunpaman kami hindi namin alam kung gaano karami ang mga artifact na ito sa panahon ng pagpupulong, kaya hindi kami makakasulat ng nakapirming configuration ng build (mahigpit na pagsasalita, magagawa pa rin namin, ngunit hindi ito magiging ganap na epektibo).

pinapayagan ka ng werf na gamitin Pumunta sa mga template sa iyong configuration file (werf.yaml), at ginagawa nitong posible bumuo ng config sa mabilisang depende sa panlabas na data (kung ano ang kailangan mo!). Ang panlabas na data sa aming kaso ay ang impormasyon tungkol sa mga bersyon at paglabas, batay sa kung saan kinokolekta namin ang kinakailangang bilang ng mga artifact at bilang resulta nakakuha kami ng dalawang larawan: werf-doc и werf-dev upang tumakbo sa iba't ibang mga circuit.

Ang panlabas na data ay ipinapasa sa mga variable ng kapaligiran. Narito ang kanilang komposisyon:

  • RELEASES — isang linya na may listahan ng mga release at ang kaukulang kasalukuyang bersyon ng werf, sa anyo ng isang listahan ng mga halaga na pinaghihiwalay ng espasyo sa format <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>... Halimbawa: 1.0%v1.0.4-beta.20
  • CHANNELS — isang linya na may listahan ng mga channel at ang kaukulang kasalukuyang bersyon ng werf, sa anyo ng isang listahan ng mga halaga na pinaghihiwalay ng espasyo sa format <КАНАЛ>%<НОМЕР_ВЕРСИИ>... Halimbawa: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION — bersyon ng paglabas ng werf na ipapakita bilang default sa site (hindi palaging kinakailangan na ipakita ang dokumentasyon ayon sa pinakamataas na numero ng paglabas). Halimbawa: v1.0.4-beta.20
  • REVIEW_SHA — hash ng review commit kung saan kailangan mong buuin ang bersyon para sa test loop.

Ang mga variable na ito ay pupunan sa GitLab CI pipeline, at kung paano eksaktong nakasulat sa ibaba.

Una sa lahat, para sa kaginhawahan, tinutukoy namin ang werf.yaml Pumunta sa mga variable ng template, na nagtalaga sa kanila ng mga halaga mula sa mga variable ng kapaligiran:

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

Ang paglalarawan ng artifact para sa pag-compile ng static na bersyon ng site ay karaniwang pareho para sa lahat ng kaso na kailangan namin (kabilang ang pagbuo ng root na bersyon, pati na rin ang bersyon para sa dev circuit). Samakatuwid, ililipat namin ito sa isang hiwalay na bloke gamit ang function define - para sa kasunod na muling paggamit include. Ipapasa namin ang mga sumusunod na argumento sa template:

  • Version — nabuong bersyon (pangalan ng tag);
  • Channel — ang pangalan ng channel ng pag-update kung saan nabuo ang artifact;
  • Commit — commit hash, kung ang artifact ay nabuo para sa isang review commit;
  • konteksto.

Paglalarawan ng Template ng Artifact

{{- define "doc_artifact" -}}
{{- $Root := index . "Root" -}}
artifact: doc-{{ .Channel }}
from: jekyll/builder:3
mount:
- from: build_dir
  to: /usr/local/bundle
ansible:
  install:
  - shell: |
      export PATH=/usr/jekyll/bin/:$PATH
  - name: "Install Dependencies"
    shell: bundle install
    args:
      executable: /bin/bash
      chdir: /app/docs
  beforeSetup:
{{- if .Commit }}
  - shell: echo "Review SHA - {{ .Commit }}."
{{- end }}
{{- if eq .Channel "root" }}
  - name: "releases.yml HASH: {{ $Root.Files.Get "releases.yml" | sha256sum }}"
    copy:
      content: |
{{ $Root.Files.Get "releases.yml" | indent 8 }}
      dest:  /app/docs/_data/releases.yml
{{- else }}
  - file:
      path: /app/docs/_data/releases.yml
      state: touch
{{- end }}
  - file:
      path: "{{`{{ item }}`}}"
      state: directory
      mode: 0777
    with_items:
    - /app/main_site/
    - /app/ru_site/
  - file:
      dest: /app/docs/pages_ru/cli
      state: 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
  to: /app/
  owner: jekyll
  group: jekyll
{{- if .Commit }}
  commit: {{ .Commit }}
{{- else }}
  tag: {{ .Version }}
{{- end }}
  stageDependencies:
    install: ['docs/Gemfile','docs/Gemfile.lock']
    beforeSetup: '**/*'
  includePaths: 'docs'
  excludePaths: '**/*.sh'
{{- end }}

Ang pangalan ng artifact ay dapat na natatangi. Maaari nating makamit ito, halimbawa, sa pamamagitan ng pagdaragdag ng pangalan ng channel (ang halaga ng variable .Channel) bilang isang suffix sa pangalan ng artifact: artifact: doc-{{ .Channel }}. Ngunit kailangan mong maunawaan na kapag nag-import mula sa mga artifact, kakailanganin mong sumangguni sa parehong mga pangalan.

Kapag naglalarawan ng isang artifact, ginagamit ang sumusunod na tampok na werf: pag-mount. Pag-mount na nagpapahiwatig ng direktoryo ng serbisyo build_dir ay nagbibigay-daan sa iyo na i-save ang Jekyll cache sa pagitan ng pipeline run, na makabuluhang nagpapabilis ng muling pagsasama.

Maaaring napansin mo rin ang paggamit ng file releases.yml ay isang YAML file na may hiniling na data ng release github.com (isang artifact na nakuha kapag nagsasagawa ng pipeline). Ito ay kinakailangan kapag kino-compile ang site, ngunit sa konteksto ng artikulo ito ay kawili-wili sa amin dahil ito ay nakasalalay sa estado nito muling pagsasama-sama ng isang artifact lamang — isang artifact ng root version ng site (hindi ito kailangan sa ibang artifact).

Ito ay ipinatupad gamit ang conditional statement if Pumunta sa mga template at disenyo {{ $Root.Files.Get "releases.yml" | sha256sum }} sa entablado mga yugto. Gumagana ito bilang mga sumusunod: kapag bumubuo ng isang artifact para sa root na bersyon (variable .Channel ay pantay sa root) file hash releases.yml nakakaapekto sa lagda ng buong yugto, dahil bahagi ito ng pangalan ng Ansible na gawain (parameter name). Kaya, kapag nagbabago nilalaman file releases.yml ang kaukulang artifact ay muling bubuuin.

Mangyaring bigyang-pansin din ang pagtatrabaho sa isang panlabas na imbakan. Sa larawan ng isang artifact mula sa imbakan ng werf, tanging ang direktoryo ang idinaragdag /docs, at depende sa mga naipasa na parameter, idinaragdag kaagad ang data ng kinakailangang tag o review commit.

Para magamit ang template ng artifact para makabuo ng paglalarawan ng artifact ng mga inilipat na bersyon ng mga channel at release, nag-aayos kami ng loop sa variable .WerfVersions в werf.yaml:

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

kasi ang loop ay bubuo ng ilang mga artifact (umaasa kami), kinakailangang isaalang-alang ang separator sa pagitan nila - ang pagkakasunud-sunod --- (Para sa higit pang impormasyon sa configuration file syntax, tingnan ang dokumentasyon). Gaya ng naunang tinukoy, kapag tumatawag sa isang template sa isang loop, ipinapasa namin ang mga parameter ng bersyon, URL at konteksto ng ugat.

Katulad nito, ngunit walang loop, tinatawag namin ang template ng artifact para sa "mga espesyal na kaso": para sa root na bersyon, pati na rin ang bersyon mula sa review commit:

{{ 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 }}

Pakitandaan na ang artifact para sa review commit ay gagawin lamang kung ang variable ay nakatakda .WerfReviewCommit.

Handa na ang mga artifact - oras na para magsimulang mag-import!

Ang huling larawan, na idinisenyo upang tumakbo sa Kubernetes, ay isang regular na NGINX na may naidagdag na file ng configuration ng server nginx.conf at static mula sa mga artifact. Bilang karagdagan sa artifact ng root na bersyon ng site, kailangan nating ulitin ang loop sa variable .WerfVersions para mag-import ng mga artifact ng channel at maglabas ng mga bersyon + sundin ang panuntunan sa pagpapangalan ng artifact na pinagtibay namin kanina. Dahil ang bawat artifact ay nag-iimbak ng mga bersyon ng site para sa dalawang wika, ini-import namin ang mga ito sa mga lugar na ibinigay ng configuration.

Paglalarawan ng huling larawan 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 -}}

Ang karagdagang imahe, na, kasama ang pangunahing isa, ay inilunsad sa dev circuit, ay naglalaman lamang ng dalawang bersyon ng site: ang bersyon mula sa review commit at ang root na bersyon ng site (may mga pangkalahatang asset at, kung naaalala mo , release ng data). Kaya, ang karagdagang imahe ay mag-iiba mula sa pangunahing isa lamang sa seksyon ng pag-import (at, siyempre, sa pangalan):

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 }}

Gaya ng nabanggit sa itaas, ang artifact para sa review commit ay bubuo lamang kapag ang set na variable ng environment ay pinatakbo REVIEW_SHA. Posibleng hindi makabuo ng werf-dev na imahe kung walang environment variable REVIEW_SHA, ngunit upang paglilinis ng mga patakaran Ang mga imahe ng Docker sa werf ay nagtrabaho para sa werf-dev na imahe, iiwan namin ito na mabuo lamang gamit ang root version artifact (ito ay binuo pa rin), upang gawing simple ang istraktura ng pipeline.

Ang pagpupulong ay handa na! Lumipat tayo sa CI/CD at mahahalagang nuances.

Pipeline sa GitLab CI at mga feature ng dynamic na build

Kapag nagpapatakbo ng build kailangan nating itakda ang mga variable ng kapaligiran na ginamit sa werf.yaml. Hindi ito nalalapat sa REVIEW_SHA variable, na itatakda namin kapag tumatawag sa pipeline mula sa GitHub hook.

Bubuo kami ng kinakailangang panlabas na data sa isang Bash script generate_artifacts, na bubuo ng dalawang artifact ng pipeline ng GitLab:

  • file releases.yml na may data ng paglabas,
  • file common_envs.sh, na naglalaman ng mga variable ng kapaligiran na ie-export.

Mga nilalaman ng file generate_artifacts makikita mo sa aming mga repositoryo na may mga halimbawa. Ang pagtanggap ng data mismo ay hindi ang paksa ng artikulo, ngunit ang file common_envs.sh ay mahalaga sa amin, dahil ang gawain ng werf ay nakasalalay dito. Isang halimbawa ng nilalaman nito:

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'

Maaari mong gamitin ang output ng naturang script, halimbawa, gamit ang Bash function source.

Ngayon ay dumating ang masayang bahagi. Upang ang parehong pagbuo at pag-deploy ng application ay gumana nang tama, kinakailangan upang matiyak iyon werf.yaml noon ay pareho kahit papaano sa loob ng isang pipeline. Kung hindi matugunan ang kundisyong ito, ang mga lagda ng mga yugto na kinakalkula ng werf sa panahon ng pagpupulong at, halimbawa, pag-deploy, ay magkakaiba. Ito ay hahantong sa isang error sa pag-deploy, dahil... mawawala ang larawang kinakailangan para sa pag-deploy.

Sa madaling salita, kung sa panahon ng pagpupulong ng imahe ng site ang impormasyon tungkol sa mga release at mga bersyon ay pareho, at sa oras ng pag-deploy ay inilabas ang isang bagong bersyon at ang mga variable ng kapaligiran ay may iba't ibang mga halaga, kung gayon ang pag-deploy ay mabibigo nang may error: pagkatapos ng lahat, ang artifact ng bagong bersyon ay hindi pa nabubuo.

Kung henerasyon werf.yaml depende sa panlabas na data (halimbawa, isang listahan ng mga kasalukuyang bersyon, tulad ng sa aming kaso), kung gayon ang komposisyon at mga halaga ng naturang data ay dapat na maitala sa loob ng pipeline. Ito ay lalong mahalaga kung ang mga panlabas na parameter ay madalas na nagbabago.

Kami ay tumanggap at magtala ng panlabas na data sa unang yugto ng pipeline sa GitLab (Prebuild) at ipadala pa ang mga ito sa anyo Artifact ng GitLab CI. Papayagan ka nitong patakbuhin at i-restart ang mga trabaho sa pipeline (bumuo, mag-deploy, maglinis) na may parehong configuration werf.yaml.

Mga nilalaman ng entablado Prebuild file .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

Sa pagkakaroon ng pagkuha ng panlabas na data sa artifact, maaari kang bumuo at mag-deploy gamit ang karaniwang mga yugto ng pipeline ng GitLab CI: Bumuo at Mag-deploy. Inilunsad namin ang mismong pipeline gamit ang mga hook mula sa GitHub werf repository (ibig sabihin, kapag may mga pagbabago sa repository sa GitHub). Ang data para sa kanila ay matatagpuan sa mga katangian ng proyekto ng GitLab sa seksyon Mga Setting ng CI/CD -> Pipeline trigger, at pagkatapos ay lumikha ng kaukulang Webhook sa GitHub (Mga Setting -> Webhook).

Ang yugto ng pagbuo ay magiging ganito:

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

Ang GitLab ay magdaragdag ng dalawang artifact mula sa stage hanggang sa build stage Prebuild, kaya nag-e-export kami ng mga variable na may inihandang data ng input gamit ang construct source common_envs.sh. Sinisimulan namin ang yugto ng pagbuo sa lahat ng kaso, maliban sa paglulunsad ng pipeline ayon sa isang iskedyul. Ayon sa iskedyul, magpapatakbo kami ng pipeline para sa paglilinis - sa kasong ito ay hindi na kailangang magsagawa ng pagpupulong.

Sa yugto ng pag-deploy, ilalarawan namin ang dalawang gawain - hiwalay para sa pag-deploy sa mga production at dev circuit, gamit ang isang template ng 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

Ang mga gawain ay mahalagang naiiba lamang sa pagpahiwatig ng konteksto ng kumpol kung saan dapat gawin ng werf ang pag-deploy (WERF_KUBE_CONTEXT), at pagtatakda ng mga variable ng kapaligiran ng loop (environment.name и environment.url), na pagkatapos ay ginagamit sa mga template ng Helm chart. Hindi namin ibibigay ang mga nilalaman ng mga template, dahil... walang kawili-wili doon para sa paksang pinag-uusapan, ngunit mahahanap mo sila sa mga repositoryo para sa artikulo.

Huling ugnay

Dahil ang mga bersyon ng werf ay madalas na inilabas, ang mga bagong imahe ay madalas na itatayo, at ang Docker Registry ay patuloy na lalago. Samakatuwid, kinakailangang i-configure ang awtomatikong paglilinis ng imahe batay sa mga patakaran. Napakadaling gawin.

Upang ipatupad kakailanganin mo:

  • Magdagdag ng hakbang sa paglilinis sa .gitlab-ci.yml;
  • Magdagdag ng pana-panahong pagpapatupad ng isang gawain sa paglilinis;
  • Mag-set up ng environment variable na may write access token.

Pagdaragdag ng yugto ng paglilinis sa .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

Nakita na namin ang halos lahat ng ito na mas mataas ng kaunti - para lamang linisin ito kailangan mo munang mag-log in sa Docker Registry gamit ang isang token na may karapatang magtanggal ng mga larawan sa Docker Registry (ang awtomatikong inilabas na token ng gawain ng GitLab CI ay hindi may ganitong mga karapatan). Dapat na malikha ang token sa GitLab nang maaga at dapat na tukuyin ang halaga nito sa variable ng kapaligiran WERF_IMAGES_CLEANUP_PASSWORD proyekto (Mga Setting ng CI/CD -> Mga Variable).

Ang pagdaragdag ng gawain sa paglilinis na may kinakailangang iskedyul ay tapos na sa CI/CD ->
Iskedyul
.

Iyon lang: ang isang proyekto sa Docker Registry ay hindi na patuloy na lalago mula sa hindi nagamit na mga imahe.

Sa pagtatapos ng praktikal na bahagi, hayaan mong ipaalala ko sa iyo na ang buong listahan mula sa artikulo ay magagamit sa pumunta:

Resulta

  1. Nakatanggap kami ng lohikal na istraktura ng pagpupulong: isang artifact bawat bersyon.
  2. Ang pagpupulong ay pangkalahatan at hindi nangangailangan ng mga manu-manong pagbabago kapag ang mga bagong bersyon ng werf ay inilabas: ang dokumentasyon sa website ay awtomatikong ina-update.
  3. Dalawang larawan ang binuo para sa magkakaibang mga contour.
  4. Mabilis itong gumana, dahil Ang pag-cache ay ginagamit hangga't maaari - kapag ang isang bagong bersyon ng werf ay inilabas o ang isang GitHub hook ay tinawag para sa isang review commit, tanging ang kaukulang artifact na may binagong bersyon ay itinayong muli.
  5. Hindi na kailangang mag-isip tungkol sa pagtanggal ng mga hindi nagamit na larawan: ang paglilinis ayon sa mga patakaran ng werf ay magpapanatiling maayos ang Docker Registry.

Natuklasan

  • Ang paggamit ng werf ay nagbibigay-daan sa pagpupulong na gumana nang mabilis dahil sa pag-cache ng mismong pagpupulong at pag-cache kapag nagtatrabaho sa mga panlabas na repositoryo.
  • Ang pagtatrabaho sa mga panlabas na Git repository ay nag-aalis ng pangangailangan na i-clone ang buong repository sa bawat oras o muling likhain ang gulong na may nakakalito na lohika sa pag-optimize. Werf ay gumagamit ng isang cache at ginagawa ang pag-clone nang isang beses lamang, at pagkatapos ay gumagamit fetch at kung kinakailangan lamang.
  • Kakayahang gumamit ng mga template ng Go sa build configuration file werf.yaml nagbibigay-daan sa iyo na ilarawan ang isang pagpupulong na ang resulta ay nakasalalay sa panlabas na data.
  • Ang paggamit ng mount in werf ay makabuluhang nagpapabilis sa koleksyon ng mga artifact - dahil sa cache, na karaniwan sa lahat ng pipelines.
  • Pinapadali ng werf ang pag-configure ng paglilinis, na lalong mahalaga kapag dynamic na pagbuo.

PS

Basahin din sa aming blog:

Pinagmulan: www.habr.com

Bumili ng maaasahang pagho-host para sa mga site na may proteksyon ng DDoS, mga server ng VPS VDS 🔥 Bumili ng maaasahang website hosting na may proteksyon ng DDoS, VPS VDS servers | ProHoster