Skip to content

Commit fa96023

Browse files
committed
ci: build minimal and standard images
Build images without barman-cloud, to be used with backup plugins. Closes #132 Signed-off-by: Francesco Canovai <[email protected]>
1 parent ff6034a commit fa96023

File tree

4 files changed

+352
-11
lines changed

4 files changed

+352
-11
lines changed

.github/workflows/bake.yaml

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
name: Bake images
2+
3+
on:
4+
schedule:
5+
- cron: 0 8 * * 1
6+
workflow_dispatch:
7+
inputs:
8+
environment:
9+
type: choice
10+
options:
11+
- testing
12+
- production
13+
default: testing
14+
description: "Choose the environment to bake the images for"
15+
# TODO: remove this, it is used to test a workflow that is not on main
16+
push:
17+
18+
jobs:
19+
# Start by building images for testing. We want to run security checks before pushing those to production.
20+
testbuild:
21+
name: Build for testing
22+
runs-on: ubuntu-latest
23+
permissions:
24+
contents: read
25+
packages: write
26+
security-events: write
27+
outputs:
28+
metadata: ${{ steps.build.outputs.metadata }}
29+
images: ${{ steps.images.outputs.images }}
30+
steps:
31+
- name: Checkout Code
32+
uses: actions/checkout@v4
33+
34+
- name: Log in to the GitHub Container registry
35+
uses: docker/login-action@v3
36+
with:
37+
registry: ghcr.io
38+
username: ${{ github.actor }}
39+
password: ${{ secrets.GITHUB_TOKEN }}
40+
41+
# TODO: review this when GitHub has linux/arm64 runners available (Q1 2025?)
42+
# https://github.com/github/roadmap/issues/970
43+
- name: Set up QEMU
44+
uses: docker/setup-qemu-action@v3
45+
with:
46+
platforms: 'arm64'
47+
48+
- name: Set up Docker Buildx
49+
uses: docker/setup-buildx-action@v3
50+
with:
51+
driver-opts: network=host
52+
53+
- name: Build and push
54+
uses: docker/bake-action@v6
55+
id: build
56+
env:
57+
environment: testing
58+
registry: ghcr.io/${{ github.repository_owner }}
59+
revision: ${{ github.sha }}
60+
with:
61+
push: true
62+
63+
# Get a list of the images that were built and pushed. We only care about a single tag for each image.
64+
- name: Generated images
65+
id: images
66+
run: |
67+
echo "images=$(echo '${{steps.build.outputs.metadata}}' | jq -c '[ .[]."image.name" | sub(",.*";"" )]')" >> "$GITHUB_OUTPUT"
68+
69+
security:
70+
name: Security checks
71+
runs-on: ubuntu-latest
72+
needs:
73+
- testbuild
74+
strategy:
75+
matrix:
76+
image: ${{fromJson(needs.testbuild.outputs.images)}}
77+
steps:
78+
- name: Checkout Code
79+
uses: actions/checkout@v4
80+
81+
- name: Log in to the GitHub Container registry
82+
uses: docker/login-action@v3
83+
with:
84+
registry: ghcr.io
85+
username: ${{ github.actor }}
86+
password: ${{ secrets.GITHUB_TOKEN }}
87+
88+
- name: Dockle
89+
uses: erzz/dockle-action@v1
90+
with:
91+
image: ${{ matrix.image }}
92+
exit-code: '1'
93+
94+
- name: Snyk
95+
uses: snyk/actions/docker@master
96+
continue-on-error: true
97+
env:
98+
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
99+
with:
100+
image: "${{ matrix.image }}"
101+
args: --severity-threshold=high --file=Dockerfile
102+
103+
- name: Upload result to GitHub Code Scanning
104+
uses: github/codeql-action/upload-sarif@v3
105+
continue-on-error: true
106+
with:
107+
sarif_file: snyk.sarif
108+
109+
# Build the image for production.
110+
#
111+
# TODO: no need to rebuild everything, just copy the testing images we have generated to the production registry
112+
# if we get here and we are building for production.
113+
prodbuild:
114+
if: github.event.inputs.environment == 'production' || github.event_name == 'schedule'
115+
name: Build for production
116+
runs-on: ubuntu-latest
117+
needs:
118+
- security
119+
permissions:
120+
contents: read
121+
packages: write
122+
security-events: write
123+
steps:
124+
- name: Checkout Code
125+
uses: actions/checkout@v4
126+
127+
- name: Log in to the GitHub Container registry
128+
uses: docker/login-action@v3
129+
with:
130+
registry: ghcr.io
131+
username: ${{ github.actor }}
132+
password: ${{ secrets.GITHUB_TOKEN }}
133+
134+
- name: Set up QEMU
135+
uses: docker/setup-qemu-action@v3
136+
with:
137+
platforms: 'arm64'
138+
139+
- name: Set up Docker Buildx
140+
uses: docker/setup-buildx-action@v3
141+
with:
142+
driver-opts: network=host
143+
144+
- name: Build and push
145+
uses: docker/bake-action@v6
146+
id: build
147+
env:
148+
environment: production
149+
registry: ghcr.io/${{ github.repository_owner }}
150+
revision: ${{ github.sha }}
151+
with:
152+
push: true

Dockerfile

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
ARG BASE=debian:bookworm-slim
2+
FROM $BASE AS minimal
3+
4+
ARG PG_VERSION
5+
ARG PG_MAJOR=${PG_VERSION%%.*}
6+
7+
ENV PATH=$PATH:/usr/lib/postgresql/$PG_MAJOR/bin
8+
9+
RUN apt-get update && \
10+
apt-get install -y --no-install-recommends postgresql-common ca-certificates gnupg && \
11+
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y && \
12+
apt-get install --no-install-recommends -o Dpkg::::="--force-confdef" -o Dpkg::::="--force-confold" postgresql-common -y && \
13+
sed -ri 's/#(create_main_cluster) .*$/\1 = false/' /etc/postgresql-common/createcluster.conf && \
14+
apt-get install --no-install-recommends \
15+
-o Dpkg::::="--force-confdef" -o Dpkg::::="--force-confold" "postgresql-${PG_MAJOR}=${PG_VERSION}*" -y && \
16+
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \
17+
rm -rf /var/lib/apt/lists/* /var/cache/* /var/log/*
18+
19+
20+
RUN usermod -u 26 postgres
21+
USER 26
22+
23+
FROM minimal AS standard
24+
25+
LABEL org.opencontainers.image.title="CloudNativePG PostgreSQL $PG_VERSION standard"
26+
LABEL org.opencontainers.image.description="A standard PostgreSQL $PG_VERSION container image, with a minimal set of extensions and all the locales"
27+
28+
USER root
29+
RUN apt-get update && \
30+
apt-get install -y --no-install-recommends locales-all \
31+
"postgresql-${PG_MAJOR}-pgaudit" \
32+
"postgresql-${PG_MAJOR}-pgvector" \
33+
"postgresql-${PG_MAJOR}-pg-failover-slots" && \
34+
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \
35+
rm -rf /var/lib/apt/lists/* /var/cache/* /var/log/*
36+
37+
USER 26

README.md

+56-11
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ for all available PostgreSQL versions (13 to 17) to be used as
55
operands with the [CloudNativePG operator](https://cloudnative-pg.io)
66
for Kubernetes.
77

8+
## Images
9+
10+
We build three types of images:
11+
* [system](#system)
12+
* [minimal](#minimal)
13+
* [standard](#standard)
14+
15+
Switching from system images to minimal or standard images on an existing
16+
cluster is not currently supported.
17+
18+
Minimal and standard images are supposed to be used alongside a backup plugin
19+
like [Barman Cloud](https://github.com/cloudnative-pg/plugin-barman-cloud).
20+
21+
Images are available via
22+
[GitHub Container Registry](https://github.com/cloudnative-pg/postgres-containers/pkgs/container/postgresql).
23+
24+
Currently, images are automatically rebuilt once a week (Monday).
25+
26+
### System
27+
828
These images are built on top of the [Official Postgres image](https://hub.docker.com/_/postgres)
929
maintained by the [PostgreSQL Docker Community](https://github.com/docker-library/postgres),
1030
by adding the following software:
@@ -14,7 +34,42 @@ by adding the following software:
1434
- Postgres Failover Slots
1535
- pgvector
1636

17-
Currently, images are automatically rebuilt once a week (Monday).
37+
### Minimal
38+
39+
These images are build on top of [official Debian images](https://hub.docker.com/_/debian)
40+
by installing PostgreSQL.
41+
42+
Minimal images include `minimal` in the tag name, e.g.
43+
`17.2-standard-bookworm`.
44+
45+
### Standard
46+
47+
These images are build on top of the minimal images by adding the following
48+
software:
49+
50+
- PGAudit
51+
- Postgres Failover Slots
52+
- pgvector
53+
54+
and all the locales.
55+
56+
Standard images include `standard` in the tag name, e.g.
57+
`17.2-standard-bookworm`.
58+
59+
## SBOMs
60+
61+
Software Bills of Materials (SBOMs) are available for minimal and standard
62+
images. The SBOM for an image can be retrieved with the following command:
63+
64+
```shell
65+
docker buildx imagetools inspect <IMAGE> --format "{{ json .SBOM.SPDX}}"
66+
```
67+
68+
## License and copyright
69+
70+
This software is available under [Apache License 2.0](LICENSE).
71+
72+
Copyright The CloudNativePG Contributors.
1873

1974
Barman Cloud is distributed by EnterpriseDB under the
2075
[GNU GPL 3 License](https://github.com/EnterpriseDB/barman/blob/master/LICENSE).
@@ -28,18 +83,8 @@ Postgres Failover Slots is distributed by EnterpriseDB under the
2883
pgvector is distributed under the
2984
[PostgreSQL License](https://github.com/pgvector/pgvector/blob/master/LICENSE).
3085

31-
Images are available via
32-
[GitHub Container Registry](https://github.com/cloudnative-pg/postgres-containers/pkgs/container/postgresql).
33-
34-
## License and copyright
35-
36-
This software is available under [Apache License 2.0](LICENSE).
37-
38-
Copyright The CloudNativePG Contributors.
39-
4086
## Trademarks
4187

4288
*[Postgres, PostgreSQL and the Slonik Logo](https://www.postgresql.org/about/policies/trademarks/)
4389
are trademarks or registered trademarks of the PostgreSQL Community Association
4490
of Canada, and used with their permission.*
45-

docker-bake.hcl

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
variable "environment" {
2+
default = "testing"
3+
validation {
4+
condition = contains(["testing", "production"], environment)
5+
error_message = "environment must be either testing or production"
6+
}
7+
}
8+
9+
variable "registry" {
10+
default = "localhost:5000"
11+
}
12+
13+
// Use the revision variable to identify the commit that generated the image
14+
variable "revision" {
15+
default = ""
16+
}
17+
18+
fullname = ( environment == "testing") ? "${registry}/postgresql-testing" : "{registry}/postgresql"
19+
now = timestamp()
20+
21+
target "default" {
22+
matrix = {
23+
tgt = [
24+
"minimal",
25+
// "standard"
26+
]
27+
pgVersion = [
28+
// "13.18",
29+
// "14.15",
30+
// "15.10",
31+
"16.6",
32+
"17.2"
33+
]
34+
base = [
35+
// renovate: datasource=docker versioning=loose
36+
// "debian:bookworm-slim@sha256:d365f4920711a9074c4bcd178e8f457ee59250426441ab2a5f8106ed8fe948eb",
37+
// renovate: datasource=docker versioning=loose
38+
"debian:bullseye-slim@sha256:b0c91cc181796d34c53f7ea106fbcddaf87f3e601cc371af6a24a019a489c980"
39+
]
40+
}
41+
dockerfile = "Dockerfile"
42+
name = "postgresql-${index(split(".",pgVersion),0)}-${tgt}-${distroVersion(base)}"
43+
tags = [
44+
"${fullname}:${index(split(".",pgVersion),0)}-${tgt}-${distroVersion(base)}",
45+
"${fullname}:${pgVersion}-${tgt}-${distroVersion(base)}",
46+
"${fullname}:${pgVersion}-${formatdate("YYYYMMDDhhmm", now)}-${tgt}-${distroVersion(base)}"
47+
]
48+
context = "."
49+
target = "${tgt}"
50+
args = {
51+
PG_VERSION = "${pgVersion}"
52+
BASE = "${base}"
53+
}
54+
attest = [
55+
"type=provenance,mode=max",
56+
"type=sbom"
57+
]
58+
annotations = [
59+
"index,manifest:org.opencontainers.image.created=${now}",
60+
"index,manifest:org.opencontainers.image.url=https://github.com/cloudnative-pg/postgres-containers",
61+
"index,manifest:org.opencontainers.image.source=https://github.com/cloudnative-pg/postgres-containers",
62+
"index,manifest:org.opencontainers.image.version=${pgVersion}",
63+
"index,manifest:org.opencontainers.image.revision=${revision}",
64+
"index,manifest:org.opencontainers.image.vendor=The CloudNativePG Contributors",
65+
"index,manifest:org.opencontainers.image.title=CloudNativePG PostgreSQL ${pgVersion} ${tgt}",
66+
"index,manifest:org.opencontainers.image.description=A ${tgt} PostgreSQL ${pgVersion} container image",
67+
"index,manifest:org.opencontainers.image.documentation=https://github.com/cloudnative-pg/postgres-containers",
68+
"index,manifest:org.opencontainers.image.authors=The CloudNativePG Contributors",
69+
"index,manifest:org.opencontainers.image.licenses=Apache-2.0",
70+
"index,manifest:org.opencontainers.image.base.name=docker.io/library/${tag(base)}",
71+
"index,manifest:org.opencontainers.image.base.digest=${digest(base)}"
72+
]
73+
labels = {
74+
"org.opencontainers.image.created" = "${now}",
75+
"org.opencontainers.image.url" = "https://github.com/cloudnative-pg/postgres-containers",
76+
"org.opencontainers.image.source" = "https://github.com/cloudnative-pg/postgres-containers",
77+
"org.opencontainers.image.version" = "${pgVersion}",
78+
"org.opencontainers.image.revision" = "${revision}",
79+
"org.opencontainers.image.vendor" = "The CloudNativePG Contributors",
80+
"org.opencontainers.image.title" = "CloudNativePG PostgreSQL ${pgVersion} ${tgt}",
81+
"org.opencontainers.image.description" = "A ${tgt} PostgreSQL ${pgVersion} container image",
82+
"org.opencontainers.image.documentation" = "https://github.com/cloudnative-pg/postgres-containers",
83+
"org.opencontainers.image.authors" = "The CloudNativePG Contributors",
84+
"org.opencontainers.image.licenses" = "Apache-2.0"
85+
"org.opencontainers.image.base.name" = "docker.io/library/debian:${tag(base)}"
86+
"org.opencontainers.image.base.digest" = "${digest(base)}"
87+
}
88+
// platforms = [
89+
// "linux/amd64",
90+
// "linux/arm64"
91+
// ]
92+
}
93+
94+
function tag {
95+
params = [ imageNameWithSha ]
96+
result = index(split("@", index(split(":", imageNameWithSha), 1)), 0)
97+
}
98+
99+
function distroVersion {
100+
params = [ imageNameWithSha ]
101+
result = index(split("-", tag(imageNameWithSha)), 0)
102+
}
103+
104+
function digest {
105+
params = [ imageNameWithSha ]
106+
result = index(split("@", imageNameWithSha), 1)
107+
}

0 commit comments

Comments
 (0)