Skip to content

Latest commit

 

History

History
282 lines (197 loc) · 8.06 KB

File metadata and controls

282 lines (197 loc) · 8.06 KB

Building Postgres Extensions Container Images for CloudNativePG

This guide explains how to build Postgres extensions container images for CloudNativePG locally, using Docker Bake.

Important

If you are looking to contribute a new PostgreSQL extension to this repository, please refer to the CONTRIBUTING_NEW_EXTENSION.md file. This guide covers the entire lifecycle, from proposing the extension and scaffolding the project to local validation and submitting a Pull Request.

Prerequisites

Before you begin, ensure that you have met the following prerequisites, which primarily include:

  1. Task: required to run tasks defined in the Taskfile.
  2. Dagger: Must be installed and configured.
  3. Docker: Must be installed and running.
  4. Docker Command Line: The docker command must be executable.
  5. Docker Buildx: The docker buildx plugin must be available.
  6. Docker Context: A valid Docker context must be configured.

To verify that all prerequisites are correctly installed and configured:

task prereqs

Scaffolding a New Extension

To create a new extension project structure, use the create-extension task:

task create-extension NAME=<extension-name>

This command generates a new directory named after your extension with the following scaffolded files:

  • Dockerfile: The base file to build the extension container image.
  • metadata.hcl: Provides specific metadata information used to build and test the extension.
  • README.md: A template to help you document the extension's usage.

Note

These files are generated from generic templates and should be customized to meet your extension's specific requirements. For a complete walkthrough of the requirements and package discovery phase, see CONTRIBUTING_NEW_EXTENSION.md.

Advanced Scaffolding

For more complex setups, you can use the dagger command directly to customize distributions or package names:

dagger call -sm ./dagger/maintenance/ create --name="<name>" [ARGUMENTS]

Common Arguments:

Argument Description Default
--distros Debian distributions the extension supports. [trixie, bookworm]
--package-name The Debian package name (uses %version% placeholder). postgresql-%version%-<name>
--versions Supported Postgres major versions. [18]
--templates-dir Source directory containing custom template files. Internal template dir

Usage and Targets

1. Build configuration check (dry run)

To verify the configuration (running docker buildx bake --check) for all projects without building or pulling layers:

task checks:all

2. Build all projects

To build all discovered projects:

task
# or
task bake:all

3. Build a specific project

To build a single project (e.g., the directory named pgvector):

task bake TARGET=pgvector

4. Push all images

To build all images and immediately push them to the configured registry:

task bake:all PUSH=true

5. Push images for a specific project

To push images for a single project (e.g., the directory named pgvector):

task bake TARGET=pgvector PUSH=true

6. Dry run mode

To see the commands that would be executed without running the actual docker buildx bake command, set the DRY_RUN flag:

task DRY_RUN=true
# or
task bake TARGET=pgvector DRY_RUN=true

Local testing guide

Testing your extensions locally ensures high-quality PRs and faster iteration cycles. This environment uses a local Docker container registry and a Kind cluster with CloudNativePG pre-installed.

Important

Pre-submission requirement: You must successfully run local tests before submitting a Pull Request for any extension.

The Fast Path (Automated Testing)

End-to-end (E2E) tests are powered by Chainsaw. To simplify the workflow, use the e2e:test:full task. This single command automates environment setup, image building, and test execution:

# Replace <extension> with the name of the extension (e.g., pgvector)
task e2e:test:full TARGET="<extension>"

Example for testing the pgvector extension:

task e2e:test:full TARGET="pgvector"

When to use the step-by-step guide: If the automated test fails during environment setup, image building, or test execution, the step-by-step guide below provides granular control for debugging each phase independently.


E2E step-by-step Guide

Initialize the environment

The e2e:setup-env utility creates a Kind cluster and attaches a local Docker registry (available at localhost:5000).

task e2e:setup-env

Note

Use the REGISTRY_HOST_PORT variable to customize the local registry port. If changed, you must pass this variable to all subsequent tasks that interact with the registry to ensure connectivity.

Configuring credentials for private registries

If you need to pull images from a private registry during testing, you can configure authentication credentials when setting up the environment:

REGISTRY_PASSWORD="your-password" task e2e:setup-env \
  REGISTRY_HOST="registry.example.com" \
  REGISTRY_USERNAME="your-username"

These credentials are configured at the kubelet level, allowing pods to pull images from the private registry without requiring ImagePullSecrets.

Get access to the cluster

To interact with the cluster via kubectl from your local terminal:

task e2e:export-kubeconfig KUBECONFIG_PATH=./kubeconfig
export KUBECONFIG=$PWD/kubeconfig

Important

The local registry running alongside the Kind cluster is reachable within Kubernetes at registry.pg-extensions:5000. When testing your local builds, you must point the extension's reference to this internal address. For example, if you are testing a locally built pgvector image, use: reference: registry.pg-extensions:5000/pgvector-testing:<tag>

To allow the test suite (which runs within the Docker network) to reach the Kubernetes API server, export the internal Kubeconfig:

task e2e:export-kubeconfig KUBECONFIG_PATH=./kubeconfig INTERNAL=true

Build and push the extension (bake)

Build the image and push it to the local registry. This command tags the image for localhost:5000 automatically.

task bake TARGET="<extension>" PUSH=true

Note

The destination registry is controlled by the REGISTRY_HOST_NAME and REGISTRY_HOST_PORT variables defined in the Taskfile.yml.

Prepare testing values

Generate configuration values so Chainsaw knows which local image to target for the E2E tests:

task e2e:generate-values TARGET="<extension>" EXTENSION_IMAGE="<my-local-image>"

Using private registries

If your extension image is hosted in a private registry, you can provide authentication credentials when generating test values:

REGISTRY_PASSWORD="your-password" task generate-values \
  TARGET="<extension>" \
  EXTENSION_IMAGE="<my-private-registry>/image:tag" \
  REGISTRY_USERNAME="your-username"

Execute End-to-End tests

Run the test suite using the internal Kubeconfig. This executes both the generic tests (global /test folder) and extension-specific tests (target /test folder).

task e2e:test TARGET="<extension>" KUBECONFIG_PATH="./kubeconfig"

Pass arguments to chainsaw test

It is possible to pass arguments to the Chainsaw test command by using the EXTRA_ARGS argument, like:

task e2e:test TARGET="pgvector" KUBECONFIG_PATH="./kubeconfig" EXTRA_ARGS="--skip-delete,--fail-fast"

Tear down the local test environment

To clean up all the resources created by the e2e:setup-env task, run:

task e2e:cleanup