Капстоун, шаг 4: полный CI/CD-пайплайн публикации

Уровень: expert ~55 мин Практика: Firefly III (AGPL-3.0)

Что нужно знать перед уроком

  • M11.03 — Application-чарт и зависимость от managed-mysql — нужен готовый и протестированный локально пакет перед автоматизацией его сборки в CI
  • M9.06 — Полный .gitlab-ci.yml для Application-пакета — нужен образец четырёхстадийного пайплайна setup/build/verify/publish
  • M9.02 — pkglint глубоко — нужно понимание проверок pkglint перед настройкой стадии verify

Что нужно знать перед уроком

M9 урок 6 — эталонный .gitlab-ci.yml с четырьмя стадиями (setup → build → verify → publish) и разделением dev/prod публикации. M9 урок 5 — семверный релизный процесс от git-тега до d8 package build --version. M8 урок 2--cache-repo для ускорения сборки в CI. Этот урок адаптирует эталонный пайплайн к особенностям пакета с двумя образами (app+web) и mandatory-зависимостью от managed-mysql.

Теория

Отличие от пайплайна Umami: два образа вместо одного

Пайплайн из M9 урока 6 был написан для пакета с одним образом (Umami). Firefly III, собранный в M11 уроке 2 как связка app+web, не требует никаких изменений в стадии buildwerf build без аргументов уже собирает все образы, объявленные в werf.yaml, независимо от их числа (это прямое свойство модели сборки werf, не специфичное для количества образов). Разница проявляется только в стадии verify, где pkglint проверяет корректность ссылок на оба образа из шаблонов Nelm (M9 урок 2, линтер images), и в объёме кэша (--cache-repo, M8 урок 2), который здесь работает эффективнее — независимые стадии PHP- и Node-сборки, разделённые в M11 уроке 2, кэшируются по отдельности.

Полный .gitlab-ci.yml для Firefly III

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
stages:
  - setup
  - build
  - verify
  - publish

variables:
  PACKAGE_BUILD_REPOSITORY: "$CI_REGISTRY_IMAGE/packages/firefly-iii"
  PACKAGE_BUILD_REPOSITORY_DEV: "$CI_REGISTRY_IMAGE/packages/firefly-iii-dev"

setup-tools:
  stage: setup
  script:
    - d8 package --help
    - trdl use werf 2 stable
  only:
    - merge_requests
    - main
    - tags

build-images:
  stage: build
  script:
    # werf build без аргументов собирает ОБА образа (app и web) из werf.yaml M11 урока 2
    - werf build --repo "$PACKAGE_BUILD_REPOSITORY_DEV" --cache-repo "$PACKAGE_BUILD_REPOSITORY_DEV/cache"
  only:
    - merge_requests
    - main

verify-package:
  stage: verify
  script:
    - d8 package verify
  only:
    - merge_requests
    - main
    - tags

publish-dev:
  stage: publish
  script:
    - d8 package build --version "0.0.0-dev.$CI_COMMIT_SHORT_SHA" --repo "$PACKAGE_BUILD_REPOSITORY_DEV"
  only:
    - main

publish-prod:
  stage: publish
  script:
    - d8 package build --version "${CI_COMMIT_TAG#v}" --repo "$PACKAGE_BUILD_REPOSITORY" --sign --sign-cert "$SIGN_CERT" --sign-key "$SIGN_KEY"
  when: manual
  only:
    - tags

Структурно это тот же пайплайн, что и в M9 уроке 6 — четыре стадии, разделение dev/prod, ручной gate на publish-prod. Это намеренный вывод капстоуна: единожды спроектированный по официальным принципам пайплайн переносится на новый пакет практически без изменений — специфика конкретного приложения (число образов, стек, зависимости) инкапсулирована в werf.yaml и templates/, а не в структуре CI.

oss.yaml для Firefly III — с учётом стороннего рантайма

В отличие от Umami (Node.js) и Vikunja (Go), где основной набор зависимостей — библиотеки экосистемы, oss.yaml для PHP-приложения также должен явно перечислять сам Firefly III как компонент верхнего уровня, аналогично тому, как это было сделано для Umami в M9 уроке 7:

1
2
3
4
5
6
- id: firefly-iii
  name: firefly-iii
  description: "Личный финансовый менеджер с открытым исходным кодом"
  license: AGPL-3.0
  link: https://github.com/firefly-iii/firefly-iii
  version: "6.1.0"

Важное отличие от Umami (MIT) — лицензия AGPL-3.0. Как разобрано в M9 уроке 7, oss.yaml служит инструментом реального юридического риск-менеджмента: AGPL-3.0 накладывает более строгие требования к раскрытию исходного кода при модификации и сетевом распространении, чем MIT/Apache-2.0 — организация, устанавливающая пакет через каталог, должна явно видеть эту лицензию в oss.yaml, чтобы принять осознанное решение, приемлема ли она для конкретного случая использования (в отличие от Umami, установка Firefly III через каталог сама по себе не создаёт обязательств по AGPL для устанавливающей организации, если она не модифицирует и не распространяет код дальше, — но oss.yaml обязан явно это отразить, а не скрывать лицензионный профиль зависимости).

Верификация зависимости от Module в verify-стадии

Стадия verify (d8 package verify, M9 урок 2) в контексте капстоуна дополнительно проверяет, что requirements.modules.mandatory из M11 урока 1 синтаксически корректен и ссылается на существующее имя Module (managed-mysql) — это статическая проверка на уровне package.yaml, не требующая доступа к реальному кластеру (в отличие от динамической проверки готовности зависимости из M6 урока 1, которая происходит уже во время установки Application в конкретном кластере, а не в CI).

Частые ошибки и подводные камни

  • Пытаться настроить отдельные CI-job’ы сборки для каждого из образов app/web. Это избыточно и противоречит модели werf — один вызов werf build уже собирает все образы werf.yaml за одну CI-стадию; раздельные job’ы усложнили бы пайплайн без выигрыша в скорости (werf уже параллелит независимые образы внутри одного вызова, если позволяет граф зависимостей import).
  • Указать в oss.yaml лицензию неверно (например, спутать AGPL-3.0 с GPL-3.0 или MIT). Это не формальная опечатка, а существенная юридическая ошибка — разные лицензии семейства GPL несут разные обязательства, а MIT принципиально отличается отсутствием copyleft-требований вовсе.
  • Не проверить requirements.modules.mandatory на стадии verify, полагаясь только на проверку при реальной установке в кластер. Ошибка в имени Module (опечатка manages-mysql вместо managed-mysql) должна быть поймана максимально рано — в CI, а не после публикации версии, когда пользователи каталога уже начнут получать DependencyMissing при установке.

Практика в кластере

Практики в кластере в этом уроке нет — материал относится к конфигурации CI-пайплайна и oss.yaml, не требующих доступа к практическому кластеру.

Практика разработки

🧩 Практика урока: Firefly III · лицензия AGPL-3.0
  1. Создайте .gitlab-ci.yml по образцу теории урока в корне пакета, настройте защищённые переменные проекта (PACKAGE_BUILD_REPOSITORY_TOKEN, SIGN_CERT, SIGN_KEY) по аналогии с M9 уроком 6.

  2. Составьте полный oss.yaml, включив сам Firefly III (AGPL-3.0) и любые значимые сторонние зависимости, не покрытые основным composer/npm деревом (например, если используются сторонние Docker-базовые образы с собственными лицензиями).

  3. Проведите полный цикл: коммит в main → dev-публикация → создание тега v0.1.0 → ручной запуск publish-prod:

1
2
3
4
5
git add werf.yaml templates/ openapi/ package.yaml oss.yaml .gitlab-ci.yml
git commit -m "feat: полный Application-пакет firefly-iii готов к CI"
git push origin main
git tag v0.1.0 && git push origin v0.1.0
# затем вручную запустить job publish-prod в интерфейсе GitLab CI

Шпаргалка команд урока

1
2
d8 package verify
d8 package build --version "<semver>" --repo "<путь>" [--sign --sign-cert <path> --sign-key <path>]

Полная шпаргалка d8 package: 📋 d8 . Полный образец .gitlab-ci.ymlM9 урок 6.

Вопросы для самопроверки

Нужно ли настраивать отдельные CI-job'ы сборки для образов app и web пакета Firefly III?

Это свойство модели сборки werf, не зависящее от числа образов в werf.yaml.

Источник: Werf — Обзор сборки образов

Чем принципиально отличается лицензионный профиль Firefly III (AGPL-3.0) от Umami (MIT) с точки зрения oss.yaml?

oss.yaml — инструмент реального юридического риск-менеджмента, а не формальность, как разобрано в M9 уроке 7.

Источник: Рекомендуемая литература

Что проверяет стадия verify применительно к requirements.modules.mandatory — до реальной установки в кластер?

Это отдельная, более ранняя проверка, дополняющая динамическую проверку готовности зависимости из M6 урока 1.

Источник: Рекомендуемая литература

Пришлось ли переписывать структуру четырёхстадийного пайплайна (setup/build/verify/publish) из M9 урока 6 для капстоуна?

Это ключевой вывод урока — единожды спроектированный по официальным принципам пайплайн универсален для разных пакетов.

Источник: Рекомендуемая литература

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Gene Kim, Jez Humble, Patrick Debois, John Willis. The DevOps Handbook. 2nd ed., 2021. ISBN 978-1942788003.

Связанные материалы