Skip to content

Commit 8cca587

Browse files
committed
feat: image catalog artifacts
Signed-off-by: Gabriele Bartolini <[email protected]>
1 parent 6995028 commit 8cca587

File tree

5 files changed

+295
-0
lines changed

5 files changed

+295
-0
lines changed
119 KB
Loading
Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
---
2+
title: "CNPG Recipe 22 - Leveraging the New Supply Chain and Image Catalogs"
3+
date: 2025-10-06T12:23:56+02:00
4+
description: "Leverage a new, fully-controlled software supply chain and streamlined Image Catalogs for safer, simpler, and more declarative management of PostgreSQL on Kubernetes"
5+
tags:
6+
- postgresql
7+
- postgres
8+
- kubernetes
9+
- k8s
10+
- data on kubernetes
11+
- dok
12+
- cloudnativepg
13+
- cnpg
14+
- supply chain
15+
- container images
16+
- image catalogs
17+
- sbom
18+
- security
19+
- devsecops
20+
- upgrades
21+
- extensions
22+
- snyk
23+
- cosign
24+
- sigstore
25+
- tutorial
26+
- guide
27+
cover: cover.jpg
28+
thumb: thumb.jpg
29+
draft: false
30+
---
31+
32+
_This CNPG Recipe explores the latest enhancements to CloudNativePG's software
33+
supply chain and image management. Learn how our new, fully controlled build
34+
process—complete with Snyk scanning, image signing, and SBOMs—delivers smaller,
35+
more secure PostgreSQL images. We also detail how to leverage the newly
36+
streamlined image catalogs for simplified, declarative cluster management and
37+
safer fleet-wide upgrades in Kubernetes._
38+
39+
<!--more-->
40+
41+
---
42+
43+
The container image is the most fundamental building block of a database in
44+
Kubernetes. As the [Data on Kubernetes (DoK) community](https://dok.community/)
45+
continues to grow and mature, managing the source, version, and security of
46+
this supply chain is critical for any production-grade data service.
47+
48+
That's why I'm thrilled to announce a foundational improvement in how we build
49+
and source the official [PostgreSQL operand images](https://github.com/cloudnative-pg/postgres-containers)
50+
for CloudNativePG.
51+
52+
This evolution significantly enhances security and reliability, improves the
53+
user experience around image management, and paves a more modular future for
54+
PostgreSQL on Kubernetes.
55+
56+
In line with this, we have also converted our [PostGIS container images](https://github.com/cloudnative-pg/postgis-containers)
57+
to follow the same high standards as the main PostgreSQL images.
58+
59+
## Taking Full Control of Our PostgreSQL Images
60+
61+
First, we at CloudNativePG are making a landmark change to the operand images.
62+
We have definitively moved away from using the official `postgres` image from
63+
Docker Hub, which has accompanied the project since it was open-sourced.
64+
65+
Instead, we have transitioned to a **new software supply chain, built from the
66+
ground up with `docker bake`, that is entirely under the control of the
67+
CloudNativePG project**. While the images continue to be hosted at the standard
68+
registry, their origin and build process are now fundamentally more secure and
69+
robust.
70+
71+
This new, transparent, and secure supply chain provides several key guarantees:
72+
73+
- **Vulnerability Scanning:** Every image is continuously scanned for
74+
vulnerabilities with **Snyk**, allowing us to react faster to newly
75+
discovered CVEs.
76+
- **Image Signing:** All images are cryptographically signed using
77+
**sigstore/cosign**. This provides a guarantee that the images you use were
78+
built by our pipeline and have not been tampered with.
79+
- **Software Bill of Materials (SBOM):** We generate and distribute an SBOM for
80+
each image, providing a complete inventory of every software component and
81+
dependency for full transparency.
82+
- **Optimised Multi-Arch Builds:** Our new `docker bake` pipeline is designed
83+
from the start to efficiently produce multi-architecture images (**amd64**
84+
and **arm64**), ensuring first-class support for diverse Kubernetes
85+
environments.
86+
87+
## Image Catalogs, Perfected: A Reliable New Distribution Pipeline
88+
89+
[**Image Catalogs**](https://cloudnative-pg.io/documentation/current/image_catalog/)
90+
have been a powerful feature in CloudNativePG for over two years, allowing you
91+
to decouple your cluster configuration from specific image tags. However, the
92+
responsibility of creating and maintaining the catalog manifests often fell
93+
to you, the user.
94+
95+
Today, we are removing that friction completely. Our new, trusted distribution
96+
pipeline now provides a reliable, central source for these catalogs. Now,
97+
instead of managing these files yourself, you can install the complete,
98+
[officially maintained catalog](https://www.google.com/search?q=https://github.com/cloudnative-pg/artifacts/tree/main/image-catalogs)
99+
with a single command:
100+
101+
```sh
102+
# Deploy all supported PostgreSQL version catalogs to your cluster
103+
kubectl apply -k \
104+
https://github.com/cloudnative-pg/artifacts/image-catalogs?ref=main
105+
```
106+
107+
Once applied, you can verify that the catalogs have been successfully created
108+
in your cluster with the following command:
109+
110+
```sh
111+
kubectl get clusterimagecatalogs.postgresql.cnpg.io
112+
```
113+
114+
You should see an output similar to this, listing all the available catalogue
115+
options with format `postgresql-<type>-<debian_version>`:
116+
117+
```console
118+
NAME AGE
119+
postgresql-minimal-bookworm 19s
120+
postgresql-minimal-bullseye 19s
121+
postgresql-minimal-trixie 19s
122+
postgresql-standard-bookworm 19s
123+
postgresql-standard-bullseye 19s
124+
postgresql-standard-trixie 19s
125+
postgresql-system-bookworm 19s
126+
postgresql-system-bullseye 19s
127+
postgresql-system-trixie 19s
128+
```
129+
130+
To inspect a specific catalog and see the exact image versions it contains, you
131+
can use `kubectl describe`:
132+
133+
```sh
134+
kubectl describe clusterimagecatalogs.postgresql.cnpg.io \
135+
postgresql-minimal-trixie
136+
```
137+
138+
This reveals the mapping between each major PostgreSQL version and the precise,
139+
immutable container image digest that will be used:
140+
141+
```
142+
Name: postgresql-minimal-trixie
143+
...
144+
Spec:
145+
Images:
146+
Image: ghcr.io/cloudnative-pg/postgresql:16.10-202509290807-minimal-trixie@sha256:f69b49dc63c2988a358c58f8a1311ac98719846f91d8e97186eaf65c7085cf28
147+
Major: 16
148+
Image: ghcr.io/cloudnative-pg/postgresql:17.6-202509290807-minimal-trixie@sha256:f3e24407db6eb8c3c9a7cb433cfe81cbff006ba1f97ae9844a58c7d3cd8048d7
149+
Major: 17
150+
Image: ghcr.io/cloudnative-pg/postgresql:18.0-202509290807-minimal-trixie@sha256:dd7c678167cc6d06c2caf4e6ea7bc7a89e39754bc7e0111a81f5d75ac3068f70
151+
Major: 18
152+
...
153+
```
154+
155+
## Putting it to Work: Referencing the Catalog in a Cluster
156+
157+
Once the catalogs are installed, using them in your `Cluster` manifest is
158+
simple and powerful. Instead of a hardcoded `imageName`, you can use
159+
`imageCatalogRef` to select both a catalog and a specific major version from
160+
it.
161+
162+
```yaml
163+
{{< include "yaml/angus.yaml" >}}
164+
```
165+
166+
This elegant abstraction allows your manifest to declare its *intent*. In this
167+
case, you're requesting a cluster using the `postgresql-minimal-trixie`
168+
catalog, and pinning it specifically to **major version 18**.
169+
170+
After the cluster is up and running, you can `describe` it to see how the
171+
operator has resolved your request into a specific image digest in the `Status`
172+
section:
173+
174+
```sh
175+
kubectl describe cluster angus
176+
```
177+
178+
Notice how the `imageCatalogRef` from the `Spec` is translated into a concrete
179+
`Image` in the `Status`:
180+
181+
```
182+
...
183+
Spec:
184+
Image Catalog Ref:
185+
API Group: postgresql.cnpg.io
186+
Kind: ClusterImageCatalog
187+
Major: 18
188+
Name: postgresql-minimal-trixie
189+
...
190+
Status:
191+
...
192+
Image: ghcr.io/cloudnative-pg/postgresql:18.0-202509290807-minimal-trixie@sha256:dd7c678167cc6d06c2caf4e6ea7bc7a89e39754bc7e0111a81f5d75ac3068f70
193+
...
194+
```
195+
196+
## The Grand Finale: Safe, Automated Fleet Upgrades
197+
198+
This improved system truly shines when managing a database fleet at scale. When
199+
you update the Image Catalog in your cluster, all related clusters will be
200+
scheduled for a rolling update. To prevent a "thundering herd" that could
201+
overwhelm your system, you can control the rollout globally.
202+
203+
This feature, called **spread upgrades**, is configured in the operator's main
204+
`ConfigMap`. By setting the `CLUSTERS_ROLLOUT_DELAY` variable, you instruct the
205+
operator to wait a specific number of seconds before starting the update on the
206+
next cluster.
207+
208+
For example, to set a 2-minute delay between each cluster update:
209+
210+
```yaml
211+
{{< include "yaml/operator-config.yaml" >}}
212+
```
213+
214+
This is a powerful and simple way to ensure a safe, controlled, and completely
215+
automated rollout of updates across your entire database fleet.
216+
217+
## A More Declarative and Modular Future
218+
219+
These improvements—a fully controlled supply chain and a reliable distribution
220+
pipeline for catalogs—are more than just operational conveniences.
221+
They are foundational steps towards a more secure and modular architecture for
222+
running PostgreSQL on Kubernetes. Our ultimate goal is to ship "minimal"
223+
PostgreSQL images containing only the core database engine.
224+
225+
This vision is realised through another powerful feature called "extension
226+
image volumes". Instead of bundling every possible extension into a single,
227+
monolithic image, each extension is packaged in its own separate image.
228+
229+
A newborn project, [PostgreSQL Extension Containers](https://github.com/cloudnative-pg/postgres-extensions-containers),
230+
will contain these images.
231+
232+
When needed, CloudNativePG dynamically loads it into your PostgreSQL pod.
233+
234+
This combined approach is the future:
235+
236+
- **Enhanced Security:** Your core database has a **smaller surface attack**.
237+
- **Modularity and Flexibility:** Manage, version, and update extensions
238+
independently of the PostgreSQL engine.
239+
240+
The image catalogs are the control plane that makes this modular ecosystem
241+
possible, providing the robust, declarative mechanism to manage the entire
242+
suite of components that power your applications.
243+
244+
## Get Started Today
245+
246+
First, I want to thank the entire CloudNativePG team for completing this epic
247+
enhancement, which we started at the beginning of the year. I am really proud
248+
of the result we have achieved from every aspect: operations, security, and
249+
extensibility.
250+
251+
The fact that the [PostgreSQL 18 minimal image is now ~230MB]({{< relref "../20250926-postgresql-18/index.md" >}})
252+
—45% smaller than the equivalent for PostgreSQL 17—is a major step forward. The
253+
image catalogue artifacts are also an important achievement for
254+
standardisation, simplifying integration into any deployment.
255+
256+
I encourage you to adopt this new, simplified workflow for image catalogs
257+
today. You can get started by applying them from our
258+
[`artifacts` repository](https://github.com/cloudnative-pg/artifacts/tree/main/image-catalogs).
259+
260+
For a deeper dive, check out the official documentation on [image catalogs](https://cloudnative-pg.io/documentation/current/image_catalog/)
261+
and [spread upgrades](https://cloudnative-pg.io/documentation/current/installation_upgrade/#spread-upgrades).
262+
263+
To see where this is headed, I invite you to read my previous article on
264+
["The Immutable Future of PostgreSQL Extensions"]({{< relref "../20250303-volume-source-extension-control-path/index.md" >}})
265+
and the official docs on [extension image volumes](https://cloudnative-pg.io/documentation/current/imagevolume_extensions/).
266+
267+
---
268+
269+
Stay tuned for the upcoming recipes! For the latest updates, consider
270+
subscribing to my [LinkedIn](https://www.linkedin.com/in/gbartolini/) and
271+
[Twitter](https://twitter.com/_GBartolini_) channels.
272+
273+
If you found this article informative, feel free to share it within your
274+
network on social media using the provided links below. Your support is
275+
immensely appreciated!
46.3 KB
Loading
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: postgresql.cnpg.io/v1
2+
kind: Cluster
3+
metadata:
4+
name: angus
5+
spec:
6+
instances: 3
7+
imageCatalogRef:
8+
apiGroup: postgresql.cnpg.io
9+
kind: ClusterImageCatalog
10+
name: postgresql-minimal-trixie
11+
major: 18
12+
storage:
13+
size: 1Gi
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: cnpg-controller-manager-config
5+
namespace: cnpg-system
6+
data:
7+
CLUSTERS_ROLLOUT_DELAY: '120'

0 commit comments

Comments
 (0)