{ "index": 126, "slug": "editorial-2024-07-practice-release-engineering", "title": "Релиз без догадок: как проверить связь между commit, artifact и rollback", "excerpt": "Одинаковый tag не доказывает, что команда собирается доставить нужный код. Разбираем проверяемую цепочку от commit до rollout, отрицательный путь и границу rollback для данных.", "contentHtml": "
После выкладки сервис отвечает кодом старой версии, хотя в заявке указан новый релиз. В карточке сборки, образе и rollout стоит один tag. Команда повторяет запуск, но не может быстро ответить на три вопроса: из какого commit собран artifact, какой digest отправили и совместима ли migration с данными. Цена ошибки растёт с каждой попыткой: увеличивается окно сбоя, меняется состояние базы, а точку возврата приходится восстанавливать по разным журналам.
\nОдинаковая версия не связывает объекты сама по себе. Релиз готов к следующему действию только тогда, когда можно сравнить exact commit id, immutable digest, migration target и return point. Если одна связь неизвестна или ложна, проверка должна остановить выпуск. Новый retry не исправляет расхождение записей.
\nУ релиза есть несколько разных объектов. commit фиксирует исходный revision. artifact содержит собранное содержимое и digest. migration меняет схему или данные и должна назвать целевую версию и совместимость. rollout описывает намерение отправить конкретный digest. return point указывает версию и digest, к которым можно вернуться.
Эти записи не заменяют друг друга. Artifact должен ссылаться на exact commit, а не только на имя ветки. Rollout должен содержать digest artifact, а не mutable tag. Migration должна отвечать на вопрос о совместимости. Return point должен быть известен до разрешения операции. Такая цепочка не доказывает, что deploy уже состоялся. Она делает расхождение видимым до действия.
\nНиже приведён учебный пример с вымышленными значениями. Код не обращается к Git, registry, CI, Kubernetes API или базе данных. Он только сравнивает записи. Положительный результат означает согласованность этих записей, а не готовность реальной среды.
\nconst release = { version: '2024.07.0' };\nconst commit = { id: 'commit-7f4a0c1' };\nconst artifact = {\n digest: 'sha256:release-070-a1',\n sourceCommitId: 'commit-7f4a0c1',\n};\nconst migration = {\n targetReleaseVersion: '2024.07.0',\n compatibleWith: '2024.06.3',\n};\nconst rollout = {\n requestedArtifactDigest: 'sha256:release-070-a1',\n migrationVersion: '2024.07.0',\n};\n\nconst checks = {\n source: artifact.sourceCommitId === commit.id,\n migration: migration.targetReleaseVersion === release.version,\n artifact: rollout.requestedArtifactDigest === artifact.digest,\n rollout: rollout.migrationVersion === migration.targetReleaseVersion,\n};\n\nconst readyForReview = Object.values(checks).every(Boolean);\nif (!readyForReview) throw new Error('stop: reconcile release records');\nКаждая проверка отвечает только на один вопрос. Если заменить sourceCommitId на другой id, результат станет отрицательным. Если изменить digest в rollout, tag всё ещё будет выглядеть правильно, но содержимое уже не совпадёт. Отрицательный путь важнее зелёной строки: система не выбирает за инженера «примерно подходящую» запись.
Название readyForReview намеренно не означает readyForDeploy. Код не проверяет подпись, права, конфигурацию среды, состояние базы, доступность сервиса или факт доставки. Он лишь открывает следующий этап проверки, если четыре связи согласованы.
| Симптом | Причина | Проверка | Действие |
|---|---|---|---|
| Tag совпадает, но artifact ссылается на другой commit. | Tag используют вместо точной связи с исходным revision. | Сравнить artifact.sourceCommitId и commit id. | Остановить выпуск. Исправить запись или пересобрать artifact после решения владельца. |
| Старый код не читает новую схему. | Rollback образа ошибочно считают rollback данных. | Проверить target migration, совместимость и обратную процедуру. | Вернуть только разрешённый artifact. Изменение данных рассмотреть отдельно. |
| Rollout прошёл с тем же tag, но другим digest. | Намерение ссылается на изменяемую метку. | Сравнить requested digest с digest artifact. | Не запускать rollout. Пересоздать запись после сверки. |
| После остановки предлагают повторить deploy. | Retry используют вместо объяснения mismatch. | Найти первую ложную связь и её источник. | Сначала исправить записи, затем повторить только проверки. |
| Точку возврата называют «предыдущим релизом». | У return point нет конкретного содержимого. | Проверить version и immutable digest. | Не обещать возврат, пока обе величины не записаны. |
Таблица разделяет разные классы риска. Ошибка commit относится к происхождению artifact. Ошибка digest относится к содержимому, выбранному для rollout. Ошибка migration относится к совместимости данных и кода. Неопределённый return point относится к возможности безопасно назвать действие после сбоя. Одно поле release=green не заменяет эти проверки.
Rollback Deployment возвращает прежнюю ревизию Pod template. Это помогает вернуть код и настройки, которые входят в этот template. Но такой rollback не отменяет произвольный SQL, удалённую запись, заполненное поле или изменение внешнего contract. Если migration уже изменила данные, старый artifact может не уметь с ними работать.
\nПоэтому return point должен содержать две границы. Первая говорит, какой artifact можно запустить. Вторая говорит, что разрешено делать с данными. Возможны обратная migration, совместимый промежуточный код, восстановление из резервной копии или запрет автоматического возврата. Пока выбранный путь не проверен, честная формулировка звучит так: «возврат artifact определён; откат данных не доказан».
\nТа же граница действует для provenance и attestation. Provenance описывает происхождение сборки. Attestation может подтверждать утверждение об этом происхождении. Ни одно из них само по себе не доказывает совместимость migration, approval rollout или здоровье сервиса. Эти вопросы требуют собственных источников и проверок.
\nСхема ловит расхождения между названными записями. Она не доказывает правдивость каждого значения. Она не проверяет историю Git, содержимое образа, подпись, policy CI, права на кластер, runtime configuration, состояние базы, трафик, метрики или факт доставки.
\nЕсли commit неизвестен, digest отсутствует, migration не содержит compatibility statement или return point не назван, результат должен быть отрицательным. Не подставляйте «последний main». Не ищите образ по tag. Не объявляйте rollback данных по факту возврата Pod template. Остановитесь на первой неизвестной границе и назначьте источник, который может её подтвердить.
\nЗапись готова к передаче на авторизованную проверку, если второй инженер без устных пояснений может показать exact commit id, artifact digest, связь artifact с commit, migration target и compatibility, rollout digest, migration version и return point. Для каждой строки есть источник, владелец и действие при mismatch. Проверка даёт либо все утверждения true, либо конкретный stop с названием ложной связи.
В учебном примере все значения вымышлены и не описывают production-результат. В реальном выпуске критерий нужно применять к доступным и разрешённым записям. Если одна строка не имеет источника или действия, выпуск не готов: сначала уточните contract, затем повторите сверку.
\n