diff --git a/.github/workflows/bake.yml b/.github/workflows/bake.yml index 24e7125..495e955 100644 --- a/.github/workflows/bake.yml +++ b/.github/workflows/bake.yml @@ -49,6 +49,9 @@ jobs: postgis: - 'postgis/**' - *shared + timescaledb: + - 'timescaledb/**' + - *shared pgaudit: - 'pgaudit/**' - *shared diff --git a/README.md b/README.md index d45e7bd..505d3dc 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ they are maintained by their respective authors, and PostgreSQL Debian Group | **[pgAudit](pgaudit)** | PostgreSQL audit extension | [https://github.com/pgaudit/pgaudit](https://github.com/pgaudit/pgaudit) | | **[pgvector](pgvector)** | Vector similarity search for PostgreSQL | [https://github.com/pgvector/pgvector](https://github.com/pgvector/pgvector) | | **[PostGIS](postgis)** | Geospatial database extension for PostgreSQL | [https://postgis.net/](https://postgis.net/) | +| **[Timescaledb](timescaledb)** | Time-series database for PostgreSQL | [https://github.com/timescale/timescaledb/](https://github.com/timescale/timescaledb/) | Extensions are provided only for the OS versions already built by the diff --git a/timescaledb/Dockerfile b/timescaledb/Dockerfile new file mode 100644 index 0000000..d1ad4ec --- /dev/null +++ b/timescaledb/Dockerfile @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: Copyright © contributors to CloudNativePG, established as CloudNativePG a Series of LF Projects, LLC. +# SPDX-License-Identifier: Apache-2.0 + +ARG BASE=ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie +FROM $BASE AS builder + +ARG PG_MAJOR +ARG EXT_VERSION + +USER 0 +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends gnupg postgresql-common apt-transport-https lsb-release wget ca-certificates; \ + # Add TimescaleDB package repository + echo "deb https://packagecloud.io/timescale/timescaledb/debian/ $(lsb_release -c -s) main" > /etc/apt/sources.list.d/timescaledb.list; \ + wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | gpg --dearmor -o /etc/apt/trusted.gpg.d/timescaledb.gpg; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + timescaledb-2-oss-postgresql-${PG_MAJOR}=${EXT_VERSION}* +###################################################################### +# Final SCRATCH image +###################################################################### +FROM scratch +ARG PG_MAJOR + +# Licenses +COPY --from=builder /usr/share/doc/timescaledb-2-oss-postgresql-${PG_MAJOR}/copyright /licenses/timescaledb/ + +# Libraries — .so and bitcode for TimescaleDB +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/timescaledb* /lib/ +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/timescaledb-2* /lib/ + +# Extension SQL + control files +COPY --from=builder /usr/share/postgresql/${PG_MAJOR}/extension/timescaledb* /share/extension/ + +USER 65532:65532 \ No newline at end of file diff --git a/timescaledb/README.md b/timescaledb/README.md new file mode 100644 index 0000000..c91be52 --- /dev/null +++ b/timescaledb/README.md @@ -0,0 +1,104 @@ +# TimescaleDB (Apache 2.0 Edition) + +[TimescaleDB](https://github.com/timescale/timescaledb) is an open-source time-series database built on PostgreSQL. It enables fast analytics, efficient storage, and powerful querying for time-series workloads. + +**Note**: This image contains only the Apache 2.0 licensed components of TimescaleDB to ensure CNCF licensing compliance. Advanced features requiring the Timescale License (TSL) are not included. + +This image provides a convenient way to deploy and manage the open-source core of `TimescaleDB` with +[CloudNativePG](https://cloudnative-pg.io/). + +## Usage + +### 1. Add the TimescaleDB extension image to your Cluster + +Define the `timescaledb` extension under the `postgresql.extensions` section of +your `Cluster` resource. For example: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: cluster-timescaledb +spec: + imageName: ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie + instances: 1 + + storage: + size: 1Gi + + postgresql: + shared_preload_libraries: + - "timescaledb" + parameters: + timescaledb.telemetry_level: 'off' + max_locks_per_transaction: '128' + + extensions: + - name: timescaledb + image: + reference: ghcr.io/cloudnative-pg/timescaledb:2.24.0-18-trixie +``` + +### 2. Enable the extension in a database + +You can install `timescaledb` in a specific database by creating or updating a +`Database` resource. For example, to enable it in the `app` database: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: cluster-timescaledb-app +spec: + name: app + owner: app + cluster: + name: cluster-timescaledb + extensions: + - name: timescaledb + version: '2.24.0' +``` + +### 3. Verify installation + +Once the database is ready, connect to it with `psql` and run: + +```sql +\dx +``` + +You should see `timescaledb` listed among the installed extensions. + +### 4. Create a hypertable + +To use TimescaleDB's time-series features, create a hypertable: + +```sql +-- Create a regular table +CREATE TABLE sensor_data ( + time TIMESTAMPTZ NOT NULL, + sensor_id INTEGER, + temperature DOUBLE PRECISION, + humidity DOUBLE PRECISION +); + +-- Convert it to a hypertable +SELECT create_hypertable('sensor_data', 'time'); + +-- Insert some data +INSERT INTO sensor_data VALUES (NOW(), 1, 21.5, 45.0); +``` + +## License + +This image contains only the Apache 2.0 licensed components of TimescaleDB. Features requiring the Timescale License (TSL) are not included to ensure compliance with CNCF licensing requirements. + +All relevant license and copyright information for the `timescaledb` extension +and its dependencies are bundled within the image at: + +```text +/licenses/ +``` + +By using this image, you agree to comply with the terms of the licenses +contained therein. diff --git a/timescaledb/metadata.hcl b/timescaledb/metadata.hcl new file mode 100644 index 0000000..47889ac --- /dev/null +++ b/timescaledb/metadata.hcl @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright © contributors to CloudNativePG, established as CloudNativePG a Series of LF Projects, LLC. +# SPDX-License-Identifier: Apache-2.0 +metadata = { + name = "timescaledb" + sql_name = "timescaledb" + image_name = "timescaledb" + shared_preload_libraries = ["timescaledb"] + extension_control_path = [] + dynamic_library_path = [] + ld_library_path = [] + auto_update_os_libs = false + required_extensions = [] + create_extension = true + versions = { + trixie = { + // renovate: datasource=postgresql depName=timescaledb-2-oss-postgresql-18 versioning=deb + "18" = "2.24.0~debian13-1801" + } + bookworm = { + // renovate: datasource=postgresql depName=timescaledb-2-oss-postgresql-18 versioning=deb + "18" = "2.24.0~debian12-1801" + } + } +} diff --git a/timescaledb/test/chainsaw-test.yaml b/timescaledb/test/chainsaw-test.yaml new file mode 100644 index 0000000..9257f93 --- /dev/null +++ b/timescaledb/test/chainsaw-test.yaml @@ -0,0 +1,28 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: verify-timescaledb-extension +spec: + timeouts: + apply: 5s + assert: 3m + delete: 30s + description: Verify TimescaleDB extension is properly installed + steps: + - name: Create a Cluster with the extension + try: + - apply: + file: cluster.yaml + - apply: + file: database.yaml + - assert: + file: cluster-assert.yaml + - assert: + file: database-assert.yaml + + - name: Verify extension is installed + try: + - apply: + file: check-extension.yaml + - assert: + file: check-extension-assert.yaml diff --git a/timescaledb/test/check-extension-assert.yaml b/timescaledb/test/check-extension-assert.yaml new file mode 100644 index 0000000..a7971fc --- /dev/null +++ b/timescaledb/test/check-extension-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: extension-installed +status: + succeeded: 1 diff --git a/timescaledb/test/check-extension.yaml b/timescaledb/test/check-extension.yaml new file mode 100644 index 0000000..e5efd83 --- /dev/null +++ b/timescaledb/test/check-extension.yaml @@ -0,0 +1,29 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: extension-installed +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: EXT_VERSION + value: ($values.version) + - name: DB_URI + valueFrom: + secretKeyRef: + name: (join('-', [$values.name, 'app'])) + key: uri + image: alpine/psql:latest + command: ['sh', '-c'] + args: + - | + set -e + DB_URI=$(echo $DB_URI | sed "s|/\*|/|") + test "$(psql "$DB_URI" -tAc "SELECT EXISTS (SELECT FROM pg_catalog.pg_extension WHERE extname = 'timescaledb' AND extversion = '${EXT_VERSION}')" -q)" = "t" + psql "$DB_URI" -c "CREATE TABLE test_hypertable (time TIMESTAMPTZ NOT NULL, value DOUBLE PRECISION);" + psql "$DB_URI" -c "SELECT create_hypertable('test_hypertable', 'time');" + psql "$DB_URI" -c "INSERT INTO test_hypertable VALUES (NOW(), 1.0);" + test "$(psql "$DB_URI" -tAc "SELECT COUNT(*) FROM test_hypertable" -q)" = "1" diff --git a/timescaledb/test/cluster-assert.yaml b/timescaledb/test/cluster-assert.yaml new file mode 100644 index 0000000..aa22123 --- /dev/null +++ b/timescaledb/test/cluster-assert.yaml @@ -0,0 +1,8 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: ($values.name) +status: + readyInstances: 1 + phase: Cluster in healthy state + image: ($values.pg_image) diff --git a/timescaledb/test/cluster.yaml b/timescaledb/test/cluster.yaml new file mode 100644 index 0000000..1a06cd3 --- /dev/null +++ b/timescaledb/test/cluster.yaml @@ -0,0 +1,14 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: ($values.name) +spec: + imageName: ($values.pg_image) + instances: 1 + + storage: + size: 1Gi + + postgresql: + shared_preload_libraries: ($values.shared_preload_libraries) + extensions: ($values.extensions) diff --git a/timescaledb/test/database-assert.yaml b/timescaledb/test/database-assert.yaml new file mode 100644 index 0000000..dcc0f42 --- /dev/null +++ b/timescaledb/test/database-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: (join('-', [$values.name, 'app'])) +status: + applied: true + extensions: + - applied: true + name: ($values.sql_name) + observedGeneration: 1 diff --git a/timescaledb/test/database.yaml b/timescaledb/test/database.yaml new file mode 100644 index 0000000..fd61499 --- /dev/null +++ b/timescaledb/test/database.yaml @@ -0,0 +1,12 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Database +metadata: + name: (join('-', [$values.name, 'app'])) +spec: + name: app + owner: app + cluster: + name: ($values.name) + extensions: + - name: ($values.sql_name) + version: ($values.version)