Оригинал: CNPG Recipe 26 — Extension Image Catalogs — 6 августа 2026. Адаптивный перевод; манифесты — как в оригинале.
В Рецепте 23 расширения научились приезжать отдельными OCI-образами через ImageVolume. Работало это так: в каждом Cluster прописывалась точная ссылка на образ расширения.
Проблема вылезает на парке кластеров. Вышла новая версия pgvector или сменился major PostgreSQL — и нужно править image.reference во всех манифестах разом. Каталоги расширений убирают эту связь.
Что изменилось
Знакомый по Рецепту 22 ClusterImageCatalog теперь несёт внутри записи про major-версию ещё и массив extensions. То есть каталог описывает связку: вот образ PostgreSQL 18, а вот образы расширений, совместимые именно с ним.
apiVersion: postgresql.cnpg.io/v1
kind: ClusterImageCatalog
metadata:
name: postgresql-minimal-trixie
spec:
images:
- major: 18
image: ghcr.io/cloudnative-pg/postgresql:18.4-...-minimal-trixie@sha256:...
extensions:
- name: pgvector
image:
reference: ghcr.io/cloudnative-pg/pgvector:0.8.6-...-18-trixie@sha256:...
- name: postgis
image:
reference: ghcr.io/cloudnative-pg/postgis-extension:3.6.4-...-18-trixie@sha256:...
ld_library_path:
- system
env:
- name: GDAL_DATA
value: ${image_root}/share/gdalОбратите внимание: каталог хранит не только ссылку, но и сопутствующие настройки — ld_library_path для PostGIS и переменные окружения с подстановкой ${image_root}. Раньше это приходилось дублировать в каждом кластере.
Кластер становится проще
Манифест сокращается до запроса по имени:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pgvector
spec:
imageCatalogRef:
apiGroup: postgresql.cnpg.io
kind: ClusterImageCatalog
name: postgresql-minimal-trixie
major: 18
postgresql:
extensions:
- name: pgvectorВсё остальное — образ, ld_library_path, extension_control_path — оператор разрешает из каталога. Локально переопределить разрешённые поля по-прежнему можно, если для конкретного кластера нужно отклонение.
Проверить, что именно разрешилось:
kubectl get cluster pgvector -o jsonpath='{.status.pgDataImageInfo}' | jqРазвернуть готовый каталог сообщества:
kubectl apply -k \
https://github.com/cloudnative-pg/artifacts/image-catalogs-extensions?ref=mainСейчас в нём семь расширений: pg-crash, pg-ivm, pgaudit, pgvector, postgis, timescaledb-oss, wal2json.
Обновления парка
Здесь и окупается вся конструкция:
- Обновить расширение или PostgreSQL — поднять версию в каталоге. Все ссылающиеся кластеры уйдут в rolling update сами, манифесты не трогаются.
- Массовую раскатку притормозить — тем же
CLUSTERS_ROLLOUT_DELAYиз Рецепта 22, чтобы не положить кластер Kubernetes одновременным обновлением сотни баз. - Major-апгрейд кластера — поменять
imageCatalogRef.major, и подтянется согласованный набор образов под новую версию.
Требования и ограничения
Механизм опирается на ImageVolume, поэтому планка по версиям высокая:
- Kubernetes 1.35+ (либо 1.33/1.34 с включённым feature gate
ImageVolume); - container runtime с поддержкой ImageVolume: containerd 2.1.0+ или CRI-O 1.31+;
- CloudNativePG 1.29+ — каталоги расширений доступны во всех поддерживаемых релизах;
- PostgreSQL 18 — массивы
extensionsесть только в записях major 18, потому чтоextension_control_pathпоявился именно в 18-й версии (см. статью про релиз).
Последний пункт стоит держать в голове: на PostgreSQL 17 и ниже этот подход не заработает — там остаётся прежний путь с кастомными образами.
Итог
Логика развития понятная: Рецепт 23 отвязал расширения от operand-образа, а Рецепт 26 отвязывает манифесты кластеров от версий расширений. Кластер декларирует «мне нужен pgvector», а какой именно образ этому соответствует — решает каталог. Для парка баз это разница между правкой одного объекта и обходом всех манифестов.