Динамічна збірка та деплой Docker-образів з werf на прикладі сайту версійної документації

Ми вже неодноразово розповідали про свій GitOps-інструмент werf, а цього разу хотіли б поділитися досвідом складання сайту з документацією самого проекту. werf.io (його російськомовна версія ru.werf.io). Це звичайний статичний сайт, проте його складання цікаве тим, що побудовано з використанням динамічної кількості артефактів.

Динамічна збірка та деплой Docker-образів з werf на прикладі сайту версійної документації

Вдаватися у нюанси структури сайту: генерацію загального меню для всіх версій, сторінки з інформацією про релізи тощо. - Не будемо. Натомість, сфокусуємось на питаннях та особливостях динамічного складання та трохи на супутніх процесах CI/CD.

Вступ: як влаштований сайт

Почнемо з того, що документація werf зберігається разом з його кодом. Це висуває певні вимоги до розробки, які загалом виходять за межі цієї статті, але як мінімум можна сказати, що:

  • Нові функції werf не повинні виходити без оновлення документації і, навпаки, будь-які зміни в документації мають на увазі вихід нової версії werf;
  • Проект має досить інтенсивну розробку: нові версії можуть виходити кілька разів на день;
  • Будь-які ручні операції з деплою сайту з новою версією документації як мінімум стомлюючі;
  • У проекті прийнято підхід семантичного версіонування, з 5 каналами стабільності. Релізний процес має на увазі послідовне проходження версій каналами в порядку підвищення стабільності: від alpha до rock-solid;
  • У сайту є російськомовна версія, яка «живе та розвивається» (тобто контент якої оновлюється) паралельно з основною (тобто англомовною) версією.

Щоб приховати від користувача всю цю "внутрішню кухню", запропонувавши йому те, що "просто працює", ми зробили окремий інструмент встановлення та оновлення werf - це multiwerf. Достатньо вказати номер релізу та канал стабільності, який ви готові використовувати, а multiwerf перевірить, чи є нова версія на каналі, та завантажить її за потреби.

У меню вибору версій на сайті доступні останні версії werf у кожному каналі. За замовчуванням за адресою werf.io/documentation відкривається версія найбільш стабільного каналу для останнього релізу - вона індексується пошуковими системами. Документація для каналу доступна за окремими адресами (наприклад, werf.io/v1.0-beta/documentation для beta-релізу 1.0).

Всього сайт має такі версії:

  1. коренева (відкривається за замовчуванням),
  2. для кожного активного каналу оновлень кожного релізу (наприклад, werf.io/v1.0-beta).

Для створення конкретної версії сайту в загальному випадку достатньо виконати його компіляцію засобами Джекіл, запустивши в каталозі /docs репозиторія werf відповідну команду (jekyll build), попередньо переключившись на Git-тег необхідної версії.

Залишається тільки додати, що:

  • для складання використовується сама утиліта (werf);
  • CI/CD-процеси побудовані з урахуванням GitLab CI;
  • і все це, звичайно, працює в Kubernetes.

Завдання

Тепер сформулюємо завдання, що враховують усю описану специфіку:

  1. Після зміни версії werf на будь-якому каналі оновлень документація на сайті повинна автоматично оновлюватись.
  2. Для розробки потрібно мати можливість інколи переглядати попередні версії сайту.

Перекомпіляцію сайту необхідно виконувати після зміни версії на будь-якому каналі з відповідних Git-тегів, але в процесі складання образу ми отримаємо такі особливості:

  • Оскільки список версій на каналах змінюється, перезбирати необхідно лише документацію для каналів, де змінилася версія. Адже перезбирати все наново не дуже гарно.
  • Набір каналів для релізів може змінюватися. У якийсь момент часу, наприклад, може не бути версії на каналах стабільнішими за реліз early-access 1.1, але згодом вони з'являться — не міняти ж у цьому випадку збірку руками?

Виходить, що складання залежить від змінних зовнішніх даних.

Реалізація

Вибір підходу

Як варіант, можна запускати кожну необхідну версію окремим pod'ом у Kubernetes. Такий варіант має на увазі більшу кількість об'єктів у кластері, яке зростатиме зі збільшенням кількості стабільних релізів werf. А це в свою чергу має на увазі складніше обслуговування: на кожну версію з'являється свій HTTP-сервер, причому з невеликим навантаженням. Звичайно, це спричиняє і великі витрати на ресурси.

Ми ж пішли шляхом складання всіх необхідних версій в одному образі. Скомпільована статика всіх версій сайту знаходиться у контейнері з NGINX, а трафік на відповідний Deployment надходить через NGINX Ingress. Проста структура – ​​stateless-додаток – дозволяє легко масштабувати Deployment (залежно від навантаження) засобами самого Kubernetes.

Якщо бути точніше, то ми збираємо два образи: один – для production-контуру, другий – додатковий, для dev-контуру. Додатковий образ використовується (запускається) лише на dev-контурі спільно з основним і містить версію сайту з review-комміту, а маршрутизація між ними виконується за допомогою Ingress-ресурсів.

werf vs git clone та артефакти

Як уже згадувалося, щоб згенерувати статику сайту для конкретної версії документації, потрібно виконати складання, переключившись у відповідний тег репозиторію. Можна було б робити це шляхом клонування репозиторію щоразу при складанні, вибираючи відповідні теги за списком. Однак це досить ресурсомістка операція і, до того ж, вимагає написання нетривіальних інструкцій… Інший серйозний мінус — за такого підходу немає можливості щось кешувати під час збирання.

Тут нам на допомогу приходить сама утиліта werf, що реалізує розумне кешування і дозволяє використовувати зовнішні репозиторії. Використання werf додавання коду з репозиторію значно прискорить складання, т.к. werf по суті один раз робить клонування репозиторію, а потім виконує лише fetch за потреби. Крім того, при додаванні даних з репозиторію ми можемо вибрати лише необхідні директорії (у нашому випадку це каталог docs), що значно знизить обсяг даних, що додаються.

Оскільки Jekyll - інструмент, призначений для компіляції статики і він не потрібен у кінцевому образі, логічно було б виконати компіляцію в артефакті werf, а в кінцевий образ імпортувати лише результат компіляції.

Пишемо werf.yaml

Отже, ми визначилися, що компілюватимемо кожну версію в окремому артефакті werf. Однак ми не знаємо, скільки цих артефактів буде при складанніТому не можемо написати фіксовану конфігурацію збірки (строго кажучи, все-таки можемо, але це буде не зовсім ефективно).

werf дозволяє використовувати Go-шаблони у своєму файлі конфігурації (werf.yaml), а це дає можливість генерувати конфіг «на льоту» залежно від зовнішніх даних (те що потрібно!). Зовнішніми даними у нашому випадку виступає інформація про версії та релізи, на підставі якої ми збираємо необхідну кількість артефактів і отримуємо в результаті два образи: werf-doc и werf-dev для запуску різних контурів.

Зовнішні дані передаються через змінні оточення. Ось їх склад:

  • RELEASES — рядок зі списком релізів та відповідної ним актуальної версії werf, у вигляді списку через пробіл значень у форматі <НОМЕР_РЕЛИЗА>%<НОМЕР_ВЕРСИИ>. приклад: 1.0%v1.0.4-beta.20
  • CHANNELS — рядок зі списком каналів та відповідної ним актуальної версії werf, у вигляді списку через пробіл значень у форматі <КАНАЛ>%<НОМЕР_ВЕРСИИ>. приклад: 1.0-beta%v1.0.4-beta.20 1.0-alpha%v1.0.5-alpha.22
  • ROOT_VERSION - Версія релізу werf для відображення за замовчуванням на сайті (не завжди потрібно виводити документацію за найвищим номером релізу). Приклад: v1.0.4-beta.20
  • REVIEW_SHA - хеш review-комміту, з якого потрібно зібрати версію для тестового контуру.

Ці змінні будуть наповнюватися в pipeline GitLab CI, а як саме написано нижче.

Насамперед, для зручності, визначимо в werf.yaml змінні Go-шаблонів, надавши їм значення зі змінних оточення:

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

Опис артефакту для компіляції статики версії сайту в цілому однаково для всіх необхідних нам випадків (у тому числі генерація кореневої версії, а також версії для dev-контуру). Тому винесемо його в окремий блок за допомогою функції define - для подальшого перевикористання за допомогою include. Шаблону передаватимемо такі аргументи:

  • Version - Версія, що генерується (назва тега);
  • Channel - Назва каналу оновлень, для якого генерується артефакт;
  • Commit - хеш комміту, якщо артефакт генерується для review-комміту;
  • контекст.

Опис шаблону артефакту

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

Назва артефакту має бути унікальною. Ми можемо цього досягти, наприклад, додавши назву каналу (значення змінної .Channel) як суфікс назви артефакту: artifact: doc-{{ .Channel }}. Але слід розуміти, що при імпорті з артефактів необхідно буде посилатися на такі ж імена.

При описі артефакту використовується така можливість werf, як монтування. Монтування із зазначенням службової директорії build_dir дозволяє зберігати кеш Jekyll між запусками pipeline, що істотно прискорює перескладання.

Також ви могли помітити використання файлу releases.yml - це YAML-файл з даними про релізи, що запитується з Github.com (Артефакт, одержуваний при виконанні pipeline). Він потрібний при компіляції сайту, але в контексті статті нам він цікавий тим, що від його стану залежить перескладання лише одного артефакту - артефакту сайту кореневої версії (в інших артефактах він не потрібний).

Це реалізовано за допомогою умовного оператора if Go-шаблонів та конструкції {{ $Root.Files.Get "releases.yml" | sha256sum }} у етапі стадії. Працює це так: при складанні артефакту для кореневої версії (змінна .Channel дорівнює root) хеш файлу releases.yml впливає на сигнатуру всієї стадії, оскільки він є складовою імені Ansible-завдання (параметр name). Таким чином, при зміні вмісту файлу releases.yml відповідний артефакт буде перезібрано.

Зверніть увагу також на роботу із зовнішнім репозиторієм. В образ артефакту з репозиторія werf, додається тільки каталог /docs, причому залежно від переданих параметрів додаються дані одразу необхідного тега або review-комміту.

Щоб використовувати шаблон артефакту для генерації опису артефакту переданих версій каналів і релізів, організуємо цикл змінної .WerfVersions в werf.yaml:

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

Т.к. цикл згенерує кілька артефактів (ми сподіваємося на це), необхідно врахувати роздільник між ними – послідовність --- (Докладніше про синтаксис конфігураційного файлу див. документації). Як визначилися раніше, під час виклику шаблону в циклі ми передаємо параметри версії, URL та кореневий контекст.

Аналогічно, але вже без циклу викликаємо шаблон артефакту для «особливих випадків»: для кореневої версії, а також версії з review-комміту:

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

Зверніть увагу, що артефакт для review-комміту збиратиметься лише в тому випадку, якщо встановлена ​​змінна .WerfReviewCommit.

Артефакти готові — настав час зайнятися імпортом!

Кінцевий образ, призначений для запуску в Kubernetes, є звичайним NGINX, до якого додано файл конфігурації сервера nginx.conf та статика з артефактів. Крім артефакту кореневої версії сайту нам потрібно повторити цикл за змінною .WerfVersions для імпорту артефактів версій каналів і релізів + дотриматися правила іменування артефактів, яке ми прийняли раніше. Оскільки кожен артефакт зберігає версії сайту для двох мов, імпортуємо їх до місць, передбачених конфігурацією.

Опис кінцевого образу 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 -}}

Додатковий образ, який разом із основним запускається на dev-контурі, містить лише дві версії сайту: версію з review-комміту та кореневу версію сайту (там загальні ассети та, якщо пам'ятаєте, дані з релізів). Таким чином, додатковий образ від основного відрізнятиметься лише секцією імпорту (ну і, звичайно, ім'ям):

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

Як уже зауважували вище, артефакт для review-комміту генеруватиметься лише при запуску встановленої змінної оточення REVIEW_SHA. Можна було б взагалі не генерувати образ werf-dev, якщо немає змінного оточення REVIEW_SHA, але для того, щоб очищення за політиками Docker-образів у werf працювала для образу werf-dev, ми залишимо його збиратися тільки з артефактом кореневої версії (все одно він вже зібраний), для спрощення структури pipeline.

Збірка готова! Переходимо до CI/CD та важливих нюансів.

Пайплайн в GitLab CI та особливості динамічного складання

При запуску складання нам необхідно встановити змінні оточення, які використовуються в werf.yaml. Це не стосується змінної REVIEW_SHA, яку встановлюватимемо під час виклику pipeline від хука GitHub.

Формування необхідних зовнішніх даних винесемо до Bash-скрипту generate_artifacts, який генеруватиме два артефакти pipeline GitLab:

  • файл releases.yml з даними про релізи,
  • файл common_envs.sh, що містить змінні оточення для експорту.

Вміст файлу generate_artifacts ви знайдете в нашому репозиторії з прикладами. Отримання даних не є предметом статті, а ось файл common_envs.sh нам важливий, т.к. від нього залежить робота werf. Приклад його вмісту:

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'

Використовувати висновок такого скрипту можна, наприклад, за допомогою Bash-функції source.

А тепер найцікавіше. Щоб і складання, і деплой програми працювали правильно, необхідно зробити так, щоб werf.yaml був однаковим як мінімум в рамках одного pipeline. Якщо цю умову не виконати, то сигнатури стадій, які розраховує werf при складанні і, наприклад, депло, будуть різними. Це спричинить помилку деплою, т.к. необхідний для деплою образ не буде.

Іншими словами, якщо під час складання образу сайту інформація про релізи та версії буде одна, а в момент деплою вийде нова версія та змінні оточення матимуть інші значення, то деплой завершиться з помилкою: адже артефакт нової версії ще не зібраний.

Якщо генерація werf.yaml залежить від зовнішніх даних (наприклад, списку актуальних версій, як у нашому випадку), склад і значення таких даних повинні фіксуватися в рамках pipeline. Це особливо важливо, якщо зовнішні параметри змінюються досить часто.

Ми будемо отримувати та фіксувати зовнішні дані на першій стадії пайплайну в GitLab (Попередня збірка) і передавати їх далі у вигляді артефакту GitLab CI. Це дозволить запускати і перезапускати завдання pipelinе'а (складання, деплой, очищення) з однаковою конфігурацією в werf.yaml.

Зміст стадії Попередня збірка файлу .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

Зафіксувавши зовнішні дані в артефакті, можна виконувати складання та деплою, використовуючи стандартні стадії пайплайну GitLab CI: Build та Deploy. Сам пайплайн ми запускаємо по хуках з GitHub-репозиторію werf (тобто при змінах репозиторії на GitHub). Дані для них можна взяти у властивостях проекту GitLab у розділі CI / CD Settings -> Pipeline triggers, а потім створимо в GitHub відповідний Webhook (Settings -> Webhooks).

Стадія складання буде виглядати так:

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 додасть до стадії складання два артефакти зі стадії Попередня збіркатак що ми експортуємо змінні з підготовленими вхідними даними за допомогою конструкції source common_envs.sh. Запускаємо стадію складання у всіх випадках, крім запуску пайплайну за розкладом. За розкладом у нас запускатиметься пайплайн для очищення - виконувати збірку в цьому випадку не потрібно.

На стадії деплою опишемо два завдання - окремо для деплою на production-і dev-контури, з використанням 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

Завдання по суті відрізняються лише зазначенням контексту кластера, в який werf повинен виконувати деплой (WERF_KUBE_CONTEXT), та встановленням змінних оточення контуру (environment.name и environment.url), які використовуються потім у шаблонах Helm-чарта. Зміст шаблонів наводити будемо, т.к. там немає нічого цікавого для розглянутої теми, але ви можете їх знайти в репозиторії до статті.

фінальний штрих

Оскільки версії werf виходять досить часто, часто збиратимуться нові образи, а Docker Registry — постійно зростати. Тому обов'язково потрібно налаштувати автоматичне очищення образів із політиків. Зробити це дуже просто.

Для реалізації потрібно:

  • Додати стадію очищення до .gitlab-ci.yml;
  • Додати періодичне виконання завдання очищення;
  • Налаштувати змінну оточення з токеном доступу до запису.

Додаємо стадію очищення до .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

Майже всі ми це вже бачили трохи вище - тільки для очищення потрібно попередньо авторизуватися в Docker Registry з токеном, що має права на видалення образів в Docker Registry (у токена завдання GitLab CI, що видається автоматично, немає таких прав). Токен потрібно завести в GitLab заздалегідь і вказати його значення в змінному оточенні WERF_IMAGES_CLEANUP_PASSWORD проекту (CI/CD Settings -> Variables).

Додавання завдання очищення з необхідним розкладом здійснюється в CI/CD ->
Розклади
.

Все: проект у Docker Registry більше не буде постійно зростати від образів, що не використовуються.

На завершення практичної частини нагадаю, що повні лістинги зі статті доступні в Git:

Результат

  1. Ми отримали логічну структуру збирання: один артефакт на одну версію.
  2. Складання універсальне і не вимагає ручних змін при виході нових версій werf: документація на сайті автоматично оновлюється.
  3. Збирається два образи для різних контурів.
  4. Працює швидко, т.к. максимально використовується кешування - при виході нової версії werf або виклик GitHub-хуку для review-комміту - здійснюється перескладання тільки відповідного артефакту зі зміненою версією.
  5. Не потрібно думати про видалення образів, що не використовуються: очищення за політиками werf буде підтримувати порядок у Docker Registry.

Висновки

  • Використання werf дозволяє складання працювати швидко завдяки кешування як самої складання, так і кешування при роботі із зовнішніми репозиторіями.
  • Робота із зовнішніми Git-репозиторіями позбавляє необхідності клонувати репозиторій щоразу повністю або винаходити велосипед із хитрою логікою оптимізації. werf використовує кеш і робить клонування лише один раз, а далі використовує fetch і лише за потребою.
  • Можливість використання Go-шаблонів у файлі конфігурації збирання werf.yaml дозволяє описати складання, результат якого залежить від зовнішніх даних.
  • Використання монтування в werf значно прискорює збирання артефактів - за рахунок кешу, що є загальним для всіх pipeline.
  • werf дозволяє легко налаштувати очищення, що особливо актуально під час динамічного складання.

PS

Читайте також у нашому блозі:

Джерело: habr.com

Додати коментар або відгук