From 08361e891e05aed18914e5c38287585d4c9a5bf5 Mon Sep 17 00:00:00 2001 From: Jeff Mealo Date: Fri, 29 May 2026 12:36:27 -0400 Subject: [PATCH] feat: add `h3` container image Add a container image for the core `h3` PostgreSQL extension (h3-pg), which provides bindings for Uber's H3 hierarchical hexagonal geospatial indexing system, allowing CloudNativePG users to index and query location data on an H3 grid directly in SQL. The image bundles the `postgresql-NN-h3` package together with its required `libh3` system library (exposed via ld_library_path), built for PostgreSQL 18 on bookworm and trixie. Only the self-contained core `h3` extension is shipped; the optional `h3_postgis` companion, which requires PostGIS, is intentionally excluded. Closes #226 Signed-off-by: Jeff Mealo --- CODEOWNERS | 3 + h3/Dockerfile | 36 +++++++ h3/README.md | 124 +++++++++++++++++++++++++ h3/metadata.hcl | 55 +++++++++++ h3/system-libs/18-bookworm-os-libs.txt | 1 + h3/system-libs/18-trixie-os-libs.txt | 1 + 6 files changed, 220 insertions(+) create mode 100644 h3/Dockerfile create mode 100644 h3/README.md create mode 100644 h3/metadata.hcl create mode 100644 h3/system-libs/18-bookworm-os-libs.txt create mode 100644 h3/system-libs/18-trixie-os-libs.txt diff --git a/CODEOWNERS b/CODEOWNERS index 82a1a8a..e949562 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -9,3 +9,6 @@ # wal2json /wal2json/ @cloudnative-pg/maintainers @NiccoloFei @solidDoWant + +# h3 +/h3/ @cloudnative-pg/maintainers @NiccoloFei @jmealo diff --git a/h3/Dockerfile b/h3/Dockerfile new file mode 100644 index 0000000..6fe3b9c --- /dev/null +++ b/h3/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 + +# Install extension via `apt-get` +RUN apt-get update && apt-get install -y --no-install-recommends \ + "postgresql-${PG_MAJOR}-h3=${EXT_VERSION}" + +FROM scratch +ARG PG_MAJOR + +# Licenses +COPY --from=builder /usr/share/doc/postgresql-${PG_MAJOR}-h3/copyright /licenses/postgresql-${PG_MAJOR}-h3/ +COPY --from=builder /usr/share/doc/libh3-1/copyright /licenses/libh3-1/ + +# Libraries (core h3 extension only; h3_postgis is intentionally excluded) +COPY --from=builder /usr/lib/postgresql/${PG_MAJOR}/lib/h3.so /lib/ + +# Share (core h3 extension only) +COPY --from=builder \ + /usr/share/postgresql/${PG_MAJOR}/extension/h3.control \ + /usr/share/postgresql/${PG_MAJOR}/extension/h3--*.sql \ + /share/extension/ + +# System libs: h3.so dynamically links libh3.so.1, which is not part of the +# base image. It is loaded at runtime via `ld_library_path = ["system"]`. +COPY --from=builder /usr/lib/*-linux-gnu/libh3.so.1 /system/ + +USER 65532:65532 diff --git a/h3/README.md b/h3/README.md new file mode 100644 index 0000000..ec4b74c --- /dev/null +++ b/h3/README.md @@ -0,0 +1,124 @@ +# H3 + + +[H3](https://github.com/postgis/h3-pg) is a PostgreSQL extension that provides +bindings for [H3](https://h3geo.org/), Uber's open-source **hierarchical +hexagonal geospatial indexing system**. It lets you index, aggregate, and +join location data on a grid of hexagonal cells directly in SQL. + +This image provides a convenient way to deploy and manage the core `h3` +extension with [CloudNativePG](https://cloudnative-pg.io/). + +> [!NOTE] +> The upstream `h3-pg` package also ships a companion `h3_postgis` extension +> that bridges H3 and PostGIS. This image bundles only the self-contained +> core `h3` extension; it does not include `h3_postgis`. + +## Usage + +### 1. Add the H3 extension image to your Cluster + +Define the `h3` extension under the `postgresql.extensions` section of your +`Cluster` resource. For example: + +```yaml +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: cluster-h3 +spec: + imageName: ghcr.io/cloudnative-pg/postgresql:18-minimal-trixie + instances: 1 + + storage: + size: 1Gi + + postgresql: + extensions: + - name: h3 + image: + # renovate: suite=trixie-pgdg depName=postgresql-18-h3 + reference: ghcr.io/cloudnative-pg/h3:4.2.3-18-trixie +``` + +### 2. Enable the extension in a database + +You can install `h3` 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-h3-app +spec: + name: app + owner: app + cluster: + name: cluster-h3 + extensions: + - name: h3 + # renovate: suite=trixie-pgdg depName=postgresql-18-h3 extractVersion=^(?\d+\.\d+\.\d+) + version: '4.2.3' +``` + +### 3. Verify installation + +Once the database is ready, connect to it with `psql` and run: + +```sql +\dx +``` + +You should see `h3` listed among the installed extensions. You can then try a +basic call, for example resolving a coordinate to an H3 cell at resolution 9: + +```sql +SELECT h3_lat_lng_to_cell(POINT(-122.4194, 37.7749), 9); +``` + +## Contributors + +This extension is maintained by: + +- Jeff Mealo (@jmealo) + +The maintainers are responsible for: + +- Monitoring upstream releases and security vulnerabilities. +- Ensuring compatibility with supported PostgreSQL versions. +- Reviewing and merging contributions specific to this extension's container + image and lifecycle. + +--- + +## Licenses and Copyright + +This container image contains software that may be licensed under various +open-source licenses. + +The `h3-pg` bindings and the bundled `libh3` C library are both released +upstream under the Apache-2.0 license. + +> [!IMPORTANT] +> The Debian `libh3-1` package ships a `copyright` file (bundled in this image +> under `/licenses/`) that classifies two upstream files — `README.md` and +> `src/h3lib/lib/coordijk.c` — as `AGPL-3+`, attributing them to DGGRID / +> Southern Oregon University. This appears to be an over-conservative Debian +> classification of an algorithm-origin credit: the current upstream +> ([uber/h3](https://github.com/uber/h3)) carries Apache-2.0 headers on those +> files and contains no AGPL license text. Because `coordijk.c` is compiled +> into the bundled `libh3.so.1`, this is surfaced here for maintainer review. + +All relevant license and copyright information for the `h3` 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/h3/metadata.hcl b/h3/metadata.hcl new file mode 100644 index 0000000..57aafc1 --- /dev/null +++ b/h3/metadata.hcl @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: Copyright © contributors to CloudNativePG, established as CloudNativePG a Series of LF Projects, LLC. +# SPDX-License-Identifier: Apache-2.0 +metadata = { + name = "h3" + sql_name = "h3" + image_name = "h3" + + # h3-pg (the PostgreSQL bindings) and the bundled libh3 C library are both + # released upstream under Apache-2.0. + # + # CAVEAT: the Debian `libh3-1` package ships a `copyright` file that + # classifies two upstream files (`README.md` and `src/h3lib/lib/coordijk.c`) + # as AGPL-3+, attributing them to DGGRID / Southern Oregon University. This + # appears to be an over-conservative Debian classification of an + # algorithm-origin credit: the current upstream (uber/h3) carries Apache-2.0 + # headers on those files and contains no AGPL license text. This is flagged + # here for maintainer review, since `coordijk.c` is compiled into the bundled + # `libh3.so.1`. + licenses = ["Apache-2.0"] + + shared_preload_libraries = [] + postgresql_parameters = {} + extension_control_path = [] + dynamic_library_path = [] + + # `h3.so` dynamically links the non-base `libh3.so.1` system library, which + # the Dockerfile bundles under `/system` (see the `postgis` extension for the + # same pattern). + ld_library_path = ["system"] + + bin_path = [] + env = {} + auto_update_os_libs = true + required_extensions = [] + create_extension = true + + versions = { + bookworm = { + "18" = { + // renovate: suite=bookworm-pgdg depName=postgresql-18-h3 + package = "4.2.3-4.pgdg12+1" + // renovate: suite=bookworm-pgdg depName=postgresql-18-h3 extractVersion=^(?\d+\.\d+\.\d+) + sql = "4.2.3" + } + } + trixie = { + "18" = { + // renovate: suite=trixie-pgdg depName=postgresql-18-h3 + package = "4.2.3-4.pgdg13+1" + // renovate: suite=trixie-pgdg depName=postgresql-18-h3 extractVersion=^(?\d+\.\d+\.\d+) + sql = "4.2.3" + } + } + } +} diff --git a/h3/system-libs/18-bookworm-os-libs.txt b/h3/system-libs/18-bookworm-os-libs.txt new file mode 100644 index 0000000..85a3d19 --- /dev/null +++ b/h3/system-libs/18-bookworm-os-libs.txt @@ -0,0 +1 @@ +libh3-1_4.5.0-1.pgdg12+1_amd64.deb MD5Sum:1c586822fd295237155972ee7b7fe871 diff --git a/h3/system-libs/18-trixie-os-libs.txt b/h3/system-libs/18-trixie-os-libs.txt new file mode 100644 index 0000000..d3c7db3 --- /dev/null +++ b/h3/system-libs/18-trixie-os-libs.txt @@ -0,0 +1 @@ +libh3-1_4.5.0-1.pgdg13+1_amd64.deb MD5Sum:165ea95fb73e38c5cf9706e4e208e85c