Короткий ответ
Каждый собранный образ должен получать неизменяемый уникальный тег, построенный на git-коммите (например, `sha-` или семантическую версию для релизных тегов), и в манифестах деплоя использовать именно этот тег (а ещё надёжнее — immutable digest `@sha256:...`), не полагаясь на плавающие теги вроде `latest`, `dev`, `stable`.
Как это работает подробнее
неизменяемый тег однозначно привязан к конкретному содержимому образа — его нельзя перезаписать, не изменив имя. Digest (sha256-хэш содержимого манифеста образа) даёт ещё более сильную гарантию, чем тег: даже если кто-то случайно перепушит тег с тем же именем (что multiple registries позволяют запретить через immutability settings), digest всё равно укажет на исходное содержимое.
Пример кода
example.yaml
# deployment.yaml в GitOps-репозитории
spec:
containers:
- name: myapp
image: registry.example.com/myapp@sha256:9fa2b1c4e7d8...Что использовать на практике
- На практике. плавающие теги (`dev`, `latest`, `stable`) удобны для человекочитаемой навигации, но не должны использоваться как единственный способ деплоя в GitOps-манифестах, иначе невозможно точно сказать, какая версия сейчас работает, и теряется связь с конкретным коммитом для аудита/отката. Многие registry (ECR, Harbor, GCR) поддерживают настройку immutable tags, блокирующую перезапись тега после первой публикации — полезно включить это для релизных тегов.
- Пример. Ожидаемое поведение: команда `kubectl describe pod` всегда показывает один и тот же digest независимо от того, сколько раз перепушивали тег с тем же именем в registry, что гарантирует соответствие задеплоенного образа протестированному.
Подводные камни
- Частые ошибки. используют один и тот же тег `staging` для всех сборок в это окружение, из-за чего невозможно понять историю деплоев без отдельного журнала; полагаются на тег без включённой immutability в registry, допуская случайную перезапись существующего тега новым содержимым.