Dynamische bouw en implementatie van Docker-images met werf, gebruikmakend van het voorbeeld van de versiebeheerde documentatiesite

We hebben het al vaker over onze GitOps-tool gehad werf, en deze keer willen we de ervaring delen van het samenstellen van een website met de documentatie van het project zelf - werf.io (de Russische versie is ru.werf.io). Dit is een gewone statische site, maar de samenstelling ervan is interessant omdat deze is opgebouwd met behulp van een dynamisch aantal artefacten.

Dynamische bouw en implementatie van Docker-images met werf, gebruikmakend van het voorbeeld van de versiebeheerde documentatiesite

We gaan hier niet in op de details van de sitestructuur: het genereren van een gemeenschappelijk menu voor alle versies, een pagina met informatie over releases, etc. In plaats daarvan richten we ons op de problemen en functies van dynamische assemblage en een beetje op de bijbehorende CI/CD-processen.

Inleiding: Hoe de site werkt

Laten we beginnen met het feit dat werf-documentatie samen met de code wordt opgeslagen. Dit stelt bepaalde eisen aan de ontwikkeling, die over het algemeen buiten het bestek van dit artikel vallen, maar we kunnen in ieder geval het volgende zeggen:

  • Nieuwe werf-functies mogen niet worden vrijgegeven zonder de documentatie te updaten. Omgekeerd impliceren alle wijzigingen in de documentatie de vrijgave van een nieuwe versie van werf.
  • Het project kent een behoorlijk intensieve ontwikkeling: er kunnen meerdere keren per dag nieuwe versies verschijnen;
  • Alle handmatige handelingen om een ​​site te implementeren met een nieuwe versie van de documentatie zijn op zijn minst vervelend;
  • Het project hanteert een semantische benadering versiebeheer, met 5 stabiliteitskanalen. Het releaseproces omvat een opeenvolgende doorgang van versies door kanalen in volgorde van toenemende stabiliteit: van alfa tot rotsvast;
  • De site heeft een Russischtalige versie, die ‘leeft en zich ontwikkelt’ (d.w.z. waarvan de inhoud wordt bijgewerkt) parallel aan de hoofdversie (d.w.z. de Engelstalige versie).

Om al deze ‘innerlijke werkingen’ voor de gebruiker te verbergen en hem iets te bieden dat ‘gewoon werkt’, hebben we aparte tool voor het installeren en updaten van werf - Is multiwerfU hoeft alleen het releasenummer en het stabiliteitskanaal op te geven dat u wilt gebruiken. Multiwerf controleert dan of er een nieuwe versie op het kanaal beschikbaar is en downloadt deze indien nodig.

De nieuwste versies van werf zijn beschikbaar in elk kanaal in het versiekeuzemenu op de site. Standaard zijn bij werf.io/documentatie De meest stabiele kanaalversie voor de nieuwste release wordt geopend - deze wordt ook geïndexeerd door zoekmachines. Documentatie voor het kanaal is beschikbaar op aparte adressen (bijvoorbeeld werf.io/v1.0-beta/documentatie voor bètaversie 1.0).

In totaal zijn de volgende versies beschikbaar op de site:

  1. root (opent standaard),
  2. voor elk actief updatekanaal van elke release (bijv. werf.io/v1.0-beta).

Om een ​​specifieke versie van een site te genereren, is het in het algemeen voldoende om deze te compileren met behulp van Jekyll, actief in de directory /docs werf repository corresponderende opdracht (jekyll build), nadat er eerder was overgeschakeld naar de Git-tag van de vereiste versie.

Het enige dat nog rest, is het volgende:

  • het hulpprogramma zelf (werf) wordt gebruikt voor de assemblage;
  • CI/CD-processen worden gebouwd op basis van GitLab CI;
  • en dit alles draait uiteraard in Kubernetes.

taken

Laten we nu de taken formuleren die rekening houden met alle beschreven bijzonderheden:

  1. Na het wijzigen van de werfversie op een updatekanaal de documentatie op de site moet automatisch worden bijgewerkt.
  2. Om je te ontwikkelen moet je soms in staat zijn om Bekijk voorbeelden van de site.

De site moet opnieuw worden gecompileerd nadat de versie op een willekeurig kanaal is gewijzigd via de bijbehorende Git-tags, maar tijdens het proces van het samenstellen van de image krijgen we de volgende functies:

  • Omdat de versielijst op kanalen verandert, hoeft alleen de documentatie voor de kanalen waar de versie is gewijzigd, opnieuw te worden opgebouwd. Alles vanaf nul opnieuw opbouwen is immers niet zo prettig.
  • De set kanalen voor releases kan veranderen. Op een gegeven moment is er bijvoorbeeld mogelijk geen stabielere versie op de kanalen dan de early access 1.1-release, maar die zullen na verloop van tijd verschijnen. Je kunt de build in dat geval toch niet handmatig wijzigen?

Het blijkt dat de assemblage is afhankelijk van het wijzigen van externe gegevens.

uitvoering

Een aanpak kiezen

U kunt er ook voor kiezen om elke vereiste versie als een aparte pod in Kubernetes te draaien. Deze optie impliceert een groter aantal objecten in het cluster, dat zal toenemen naarmate het aantal stabiele werf-releases toeneemt. Dit impliceert op zijn beurt complexer onderhoud: elke versie heeft een eigen HTTP-server met een beperkte belasting. Dit brengt uiteraard ook hogere resourcekosten met zich mee.

Wij gingen dezelfde weg builds van alle vereiste versies in één imageDe gecompileerde statica van alle versies van de site bevinden zich in een container met NGINX, en het verkeer naar de bijbehorende implementatie verloopt via NGINX Ingress. Een eenvoudige structuur – een stateless applicatie – maakt het mogelijk om de implementatie eenvoudig te schalen (afhankelijk van de belasting) met behulp van Kubernetes zelf.

Om preciezer te zijn, we bouwen twee images: één voor het productiecircuit en de tweede is een extra image voor het dev-circuit. De extra image wordt alleen gebruikt (gedraaid) op het dev-circuit, samen met de hoofdimage, en bevat de versie van de site uit de reviewcommit. De routering tussen de images gebeurt met behulp van Ingress-resources.

werf vs git kloon en artefacten

Zoals gezegd, om sitestatistieken voor een specifieke versie van de documentatie te genereren, moet je builden door over te schakelen naar de bijbehorende repositorytag. Je kunt dit ook doen door de repository elke keer dat je buildt te klonen en de bijbehorende tags uit de lijst te selecteren. Dit is echter een vrij resource-intensieve bewerking en vereist bovendien het schrijven van niet-triviale instructies... Een ander ernstig nadeel is dat er met deze aanpak geen mogelijkheid is om iets te cachen tijdens de build.

Hier komt het werf-hulpprogramma zelf te hulp, door slimme caching en stelt u in staat om te gebruiken externe opslagplaatsenDoor werf te gebruiken om code uit een repository toe te voegen, wordt de build aanzienlijk versneld, omdat werf de repository in feite één keer kloont en vervolgens uitvoert alleen fetch indien nodig. Bovendien kunnen we bij het toevoegen van gegevens uit de repository alleen de benodigde mappen selecteren (in ons geval is dit de map docs), waardoor de hoeveelheid toegevoegde gegevens aanzienlijk wordt verminderd.

Omdat Jekyll een hulpmiddel is dat is ontworpen om statische bestanden te compileren en niet nodig is in de uiteindelijke afbeelding, zou het logisch zijn om te compileren in artefact werf, en in de uiteindelijke afbeelding importeer alleen het compilatieresultaat.

Wij schrijven werf.yaml

We besloten dus dat we elke versie in een apart werf-artefact zouden compileren. We we weten niet hoeveel van deze artefacten er tijdens de assemblage zullen zijn, dus we kunnen geen vaste buildconfiguratie schrijven (strikt genomen wel, maar dat is niet erg efficiënt).

werf stelt u in staat om te gebruiken Ga naar sjablonen in uw configuratiebestand (werf.yaml), en dit maakt het mogelijk genereer configuratie "on the fly" Afhankelijk van externe data (wat we nodig hebben!). In ons geval zijn externe data informatie over versies en releases, op basis waarvan we het benodigde aantal artefacten verzamelen en twee afbeeldingen als resultaat krijgen: werf-doc и werf-dev voor het starten op verschillende circuits.

Externe gegevens worden doorgegeven via omgevingsvariabelen. Dit is hun samenstelling:

  • RELEASES — een regel met een lijst met releases en de bijbehorende huidige versie van werf, als een door spaties gescheiden lijst met waarden in de indeling <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>. Voorbeeld: 1.0%v1.0.4-beta.20
  • CHANNELS — een regel met een lijst met kanalen en de bijbehorende huidige versie van werf, in de vorm van een door spaties gescheiden lijst met waarden in de indeling <КАНАЛ>%<НОМЕР_ВЕРСИИ>. Voorbeeld: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION — werf releaseversie die standaard op de site wordt weergegeven (het is niet altijd nodig om documentatie weer te geven met het hoogste releasenummer). Voorbeeld: v1.0.4-beta.20
  • REVIEW_SHA — de hash van de review commit waaruit de versie voor het testcircuit moet worden opgebouwd.

Deze variabelen worden ingevuld in de GitLab CI-pijplijn. Hoe dat precies gebeurt, wordt hieronder beschreven.

Laten we eerst voor het gemak definiëren werf.yaml Ga naar sjabloonvariabelen door ze waarden toe te wijzen vanuit omgevingsvariabelen:

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

De beschrijving van het artefact voor het compileren van de statische versie van de site is over het algemeen hetzelfde voor alle gevallen die we nodig hebben (inclusief het genereren van de rootversie, evenals de versie voor de dev-contour). Daarom zullen we het naar een apart blok verplaatsen met behulp van de functie define — voor later hergebruik met behulp van includeWe geven de volgende argumenten door aan de sjabloon:

  • Version — de gegenereerde versie (tagnaam);
  • Channel — de naam van het updatekanaal waarvoor het artefact wordt gegenereerd;
  • Commit — commit-hash, als het artefact wordt gegenereerd voor een review-commit;
  • context.

Beschrijving van het artefactsjabloon

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

De artefactnaam moet uniek zijn. We kunnen dit bijvoorbeeld bereiken door de kanaalnaam (de variabele waarde) toe te voegen. .Channel) als achtervoegsel bij de artefactnaam: artifact: doc-{{ .Channel }}Maar u moet begrijpen dat u bij het importeren van artefacten dezelfde namen moet gebruiken.

Bij het beschrijven van een artefact wordt de volgende werf-eigenschap gebruikt: montage. Monteren met een opgegeven servicedirectory build_dir Hiermee kunt u de Jekyll-cache behouden tussen pijplijnruns, wat versnelt de hermontage aanzienlijk.

Mogelijk heeft u ook het gebruik van het bestand opgemerkt releases.yml — is een YAML-bestand met opgevraagde releasegegevens github.com (een artefact verkregen bij het uitvoeren van een pijplijn). Het is nodig bij het compileren van een site, maar in de context van het artikel is het voor ons interessant omdat de status ervan afhangt van hermontage van slechts één artefact — artefact van de rootversie van de site (het is niet nodig in andere artefacten).

Dit wordt geïmplementeerd met behulp van de voorwaardelijke operator. if Ga naar sjablonen en constructies {{ $Root.Files.Get "releases.yml" | sha256sum }} in fase stadiaHet werkt als volgt: bij het bouwen van een artefact voor de rootversie (variabele .Channel is gelijk aan root) bestandshash releases.yml beïnvloedt de handtekening van het hele podium, omdat het een onderdeel is van de Ansible-taaknaam (parameter name). Dus bij het veranderen inhoud het dossier releases.yml Het bijbehorende artefact wordt opnieuw in elkaar gezet.

Let ook op bij het werken met een externe repository. In de artefactafbeelding van werf-opslagplaatsen, alleen de directory wordt toegevoegd /docsen afhankelijk van de doorgegeven parameters worden de gegevens van de vereiste tag of review commit direct toegevoegd.

Om de artefactsjabloon te gebruiken om een ​​artefactbeschrijving van de overgedragen kanaalversies en releases te genereren, organiseren we een lus per variabele .WerfVersions в werf.yaml:

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

Omdat de cyclus meerdere artefacten zal genereren (dat hopen we), is het noodzakelijk om rekening te houden met de scheidingslijn ertussen: de sequentie --- (voor meer informatie over de syntaxis van het configuratiebestand, zie documentatieZoals we eerder hebben gedefinieerd, geven we bij het aanroepen van de sjabloon in de lus de versieparameters, URL en rootcontext door.

Op dezelfde manier, maar dan zonder de cyclus, roepen we de artefactsjabloon aan voor ‘speciale gevallen’: voor de rootversie, evenals de versie uit de reviewcommit:

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

Houd er rekening mee dat het artefact voor de reviewcommit alleen wordt gebouwd als de variabele is ingesteld. .WerfReviewCommit.

De artefacten zijn klaar: tijd om te importeren!

De uiteindelijke image die op Kubernetes moet draaien, is een gewone NGINX met een toegevoegd serverconfiguratiebestand. nginx.conf en statica van artefacten. Naast het artefact van de rootversie van de site moeten we de cyclus herhalen per variabele. .WerfVersions Om kanaal- en releaseversie-artefacten te importeren, volgt u de naamgevingsregel voor artefacten die we eerder hebben gebruikt. Omdat elk artefact siteversies voor twee talen opslaat, importeren we ze naar de locaties die door de configuratie zijn opgegeven.

Beschrijving van de uiteindelijke afbeelding 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 -}}

De extra afbeelding, die samen met de hoofdafbeelding op de dev-circuit wordt gelanceerd, bevat slechts twee versies van de site: de versie van de review commit en de rootversie van de site (deze bevat gemeenschappelijke assets en, als je je herinnert, releasegegevens). De extra afbeelding verschilt dus alleen van de hoofdafbeelding in het importgedeelte (en natuurlijk ook in de naam):

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

Zoals hierboven vermeld, wordt het artefact voor de reviewcommit alleen gegenereerd wanneer de ingestelde omgevingsvariabele wordt uitgevoerd REVIEW_SHAHet zou mogelijk zijn om de werf-dev-image helemaal niet te genereren als er geen omgevingsvariabele is REVIEW_SHA, maar om schoonmaak volgens beleid Docker-images in werf werkten voor de werf-dev-image, we laten deze alleen bouwen met het root-versie-artefact (het is toch al gebouwd), om de pijplijnstructuur te vereenvoudigen.

De build is klaar! Laten we verder gaan met CI/CD en belangrijke details.

Pipeline in GitLab CI en functies van dynamische build

Bij het uitvoeren van de build moeten we de omgevingsvariabelen instellen die worden gebruikt in werf.yamlDit is niet van toepassing op de variabele REVIEW_SHA, die we instellen wanneer we de pijplijn aanroepen vanuit de GitHub-hook.

We verplaatsen de vorming van de benodigde externe gegevens naar een Bash-script generate_artifacts, die twee GitLab-pijplijnartefacten genereert:

  • файл releases.yml met vrijgavegegevens,
  • файл common_envs.sh, die omgevingsvariabelen voor export bevat.

Bestand inhoud generate_artifacts vindt u in onze repositories met voorbeeldenDe dataverzameling zelf is niet het onderwerp van het artikel, maar het bestand common_envs.sh is belangrijk voor ons, omdat de werking van Werf ervan afhangt. Een voorbeeld van de inhoud:

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'

De uitvoer van een dergelijk script kan bijvoorbeeld worden gebruikt met behulp van de Bash-functie source.

Nu komt het meest interessante deel. Om zowel de assemblage als de implementatie van de applicatie correct te laten verlopen, is het noodzakelijk om ervoor te zorgen dat: werf.yaml был hetzelfde minst binnen één pijpleidingAls aan deze voorwaarde niet wordt voldaan, zullen de fasehandtekeningen die werf berekent tijdens de assemblage en bijvoorbeeld de implementatie, anders zijn. Dit leidt tot een implementatiefout, omdat de voor de implementatie benodigde afbeelding ontbreekt.

Met andere woorden: als tijdens het samenstellen van de site-image de informatie over releases en versies gelijk is, en op het moment van implementatie een nieuwe versie uitkomt en de omgevingsvariabelen andere waarden hebben, dan eindigt de implementatie met een fout: het artefact van de nieuwe versie is immers nog niet samengesteld.

Als generatie werf.yaml Als een pijplijn afhankelijk is van externe gegevens (bijvoorbeeld een lijst met actuele versies, zoals in ons geval), dan moeten de samenstelling en waarden van die gegevens in de pijplijn worden vastgelegd. Dit is vooral belangrijk als externe parameters vaak veranderen.

Wij zullen externe gegevens ontvangen en registreren in de eerste fase van de pijplijn in GitLab (voorbouw) en ze verder in de vorm doorgeven GitLab CI-artefactenHiermee kunt u pijplijntaken (bouwen, implementeren, opschonen) uitvoeren en opnieuw starten met dezelfde configuratie in werf.yaml.

Inhoud van het podium voorbouw het dossier .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

Met vaste externe gegevens in het artefact kunt u bouwen en implementeren met behulp van de standaardfasen van de GitLab CI-pipeline: Build en Deploy. We starten de pipeline zelf met behulp van hooks uit de werf GitHub-repository (d.w.z. wanneer er wijzigingen zijn in de repository op GitHub). De gegevens hiervoor kunnen worden opgehaald uit de GitLab-projecteigenschappen in de sectie CI/CD-instellingen -> Pijplijntriggersen maak vervolgens de overeenkomstige webhook in GitHub (Instellingen -> Webhooks).

De bouwfase ziet er als volgt uit:

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 zal twee artefacten van de stage toevoegen aan de build stage voorbouw, dus we exporteren variabelen met voorbereide invoergegevens met behulp van de constructie source common_envs.shWe starten de build-fase in alle gevallen, behalve wanneer we de pijplijn volgens schema lanceren. Op schema lanceren we de pijplijn voor het opschonen - in dit geval is het niet nodig om de build uit te voeren.

In de implementatiefase beschrijven we twee taken - afzonderlijk voor implementatie naar productie- en dev-circuits, met behulp van een YAML-sjabloon:

.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

De taken verschillen wezenlijk alleen in de aanduiding van de clustercontext waarin werf de implementatie moet uitvoeren (WERF_KUBE_CONTEXT), en het instellen van de contouromgevingsvariabelen (environment.name и environment.url), die vervolgens worden gebruikt in Helm-kaartsjablonen. We zullen de inhoud van de sjablonen niet verstrekken, aangezien er niets interessants is over het onderwerp, maar u kunt ze vinden in repositories naar het artikel.

Laatste greep

Omdat werf-versies regelmatig worden uitgebracht, worden er regelmatig nieuwe images gemaakt en groeit het Docker-register voortdurend. Daarom is het noodzakelijk om automatische image cleaning op basis van beleid in te stellen. Dit is heel eenvoudig.

Voor de implementatie heeft u het volgende nodig:

  • Voeg een reinigingsstap toe aan .gitlab-ci.yml;
  • Voeg periodieke uitvoering van de schoonmaaktaak toe;
  • Stel een omgevingsvariabele in met een schrijftoegangstoken.

Voeg een reinigingsfase toe aan .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

We hebben dit hierboven bijna allemaal al gezien. Om het op te schonen, moet je eerst inloggen op Docker Registry met een token dat rechten heeft om afbeeldingen in Docker Registry te verwijderen (het automatisch uitgegeven token van de GitLab CI-taak heeft dergelijke rechten niet). Het token moet vooraf in GitLab worden aangemaakt en de waarde ervan moet worden opgegeven in de omgevingsvariabele. WERF_IMAGES_CLEANUP_PASSWORD project (CI/CD-instellingen -> Variabelen).

Het toevoegen van een schoonmaaktaak met het vereiste schema gebeurt in CI/CD ->
Schema's
.

Dat is alles: uw Docker Registry-project groeit niet langer voortdurend met ongebruikte images.

Ter afsluiting van het praktische gedeelte wil ik u eraan herinneren dat de volledige lijsten van het artikel beschikbaar zijn in Git:

Resultaat

  1. We kregen een logische assemblagestructuur: één artefact per versie.
  2. De montage is universeel en vereist geen handmatige wijzigingen bij de release van een nieuwe versie van werf: de documentatie op de site wordt automatisch bijgewerkt.
  3. Er worden twee afbeeldingen verzameld voor verschillende contouren.
  4. Het werkt snel omdat caching maximaal wordt benut: wanneer een nieuwe versie van werf wordt uitgebracht of een GitHub-hook wordt aangeroepen voor een reviewcommit, wordt alleen het overeenkomstige artefact met de gewijzigde versie opnieuw opgebouwd.
  5. U hoeft zich geen zorgen te maken over het verwijderen van ongebruikte afbeeldingen: werf-beleidsgebaseerde opschoning zorgt ervoor dat uw Docker-register opgeruimd blijft.

Bevindingen

  • Door werf te gebruiken, kan de build snel worden uitgevoerd, omdat zowel de build zelf als de cache worden opgeslagen bij het werken met externe opslagplaatsen.
  • Door met externe Git-repositories te werken, vervalt de noodzaak om de repository elke keer volledig te klonen of het wiel opnieuw uit te vinden met lastige optimalisatielogica. Werf gebruikt een cache en kloont slechts één keer, en gebruikt vervolgens fetch en alleen als het nodig is.
  • Mogelijkheid om Go-sjablonen te gebruiken in het buildconfiguratiebestand werf.yaml Hiermee kunt u een assemblage beschrijven waarvan het resultaat afhankelijk is van externe gegevens.
  • Het gebruik van mounting in werf versnelt het verzamelen van artefacten aanzienlijk - dankzij de cache, die gemeenschappelijk is voor alle pipelines.
  • Met werf kunt u opschonen eenvoudig configureren, wat vooral belangrijk is bij dynamische builds.

PS

Lees ook op onze blog:

Bron: www.habr.com

Koop betrouwbare hosting voor sites met DDoS-bescherming, VPS VDS-servers 🔥 Koop betrouwbare websitehosting met DDoS-bescherming, VPS- en VDS-servers | ProHoster