› 21 containers · forge + ezx · MIT

Containers you can read, not reverse-engineer.

Production-ready images for PostgreSQL, MariaDB, Kafka, Grafana, Prometheus, and more — each built from a declarative forge.toml manifest and supervised by a single Go binary. No setup.sh, no shell entrypoints, no root processes. An open alternative to Bitnami.

sh
$ docker pull ghcr.io/supanadit/containers/postgresql

The problem

Most community container images ask you to trust them blindly.

  • Entrypoints buried in setup.sh with implicit ordering and no review trail.
  • Applications running as root because nobody got around to chowning.
  • Config generated by sed one-liners that break on the first edge case.
  • Build layers that recompile the world whenever one ARG changes.
  • Health checks that return 200 while the app is still bootstrapping.

These containers are built differently — declaratively, from source, with supervision built in.

Why these containers

CONTAINERS

21

Databases to observability

SHELL ENTRYPOINTS

0

JavaScript + ezx only

NON-ROOT

100%

Dedicated user per app

CATEGORIES

6

One compose example each

␤ 01 BUILD

Declarative builds with forge

Every image is assembled by forge from a forge.toml manifest: apt packages, pinned source downloads with checksums, compiled binaries, users, and cleanup as an ordered, dependency-resolved op list.

␤ 02 RUNTIME

Supervised by ezx

A single Go binary stays PID 1: it forwards signals, reaps zombies, rotates logs, probes readiness, and drops privileges per process. The application never runs unsupervised.

␤ 03 ENTRYPOINT

JavaScript entrypoints, zero shell

Each container ships a small module set (env, validation, directories, config, runtime, health API) that validates, writes config, and starts the app. No bash to break at 3 a.m.

␤ 04 SECURITY

Non-root by default

Every application runs as its own dedicated user via process.user/process.group. /opt/containers/{data,config,logs,run,backup} is pre-created and pre-owned so volumes just work.

␥ 05 HEALTH

Composite health endpoints

Each image exposes a shared health server with app-specific probes plus a composite endpoint, so orchestrators see real readiness instead of a TCP handshake.

␦ 06 CONFIG

Env-var driven configuration

One env.js per container is the single source of truth for every variable. Config files are generated at boot from typed values — env.bool, env.int — never sed-edited.

␧ 07 SUPPLY

Checksum-verified downloads

forge, ezx, JDK tarballs, and every pinned binary are downloaded and checksum-verified during the build. The supply chain is explicit and auditable.

␨ 08 CI

Tested in CI, per container

Every container has compose-based test suites that assert the app answers on its own protocol, the composite health endpoint is healthy, the app runs as a non-root user, and ezx is PID 1.

␩ 09 OPS

TLS and clustering ready

Where the upstream app supports it, the container does too — PostgreSQL with TLS, etcd clusters, Kafka in KRaft mode, MinIO distributed — configured with plain environment variables.

␤ 10 EXAMPLES

Working examples included

The documentation site carries per-container guides — TLS, clustering, KRaft, pgBackRest — plus ready-made compose scenarios you can copy verbatim.

The containers

Twenty-one images across six categories. The full catalog lists every image name.

Databases

Run on their own protocol, health-checked and backed up.

postgresql mariadb pgpool-ii maxscale

Messaging & Coordination

KRaft Kafka, ZooKeeper, and etcd — clustering by environment variable.

apache-kafka apache-zookeeper etcd

Storage

Object storage built from source with distributed layouts.

minio

Observability

The full Grafana LGTM stack plus Prometheus and Thanos.

prometheus grafana grafana-loki grafana-mimir grafana-tempo grafana-alloy grafana-pyroscope thanos

Big Data & Workflow

Airflow, Cassandra, Flink, and Spark as supervised node sets.

apache-airflow apache-cassandra apache-flink apache-spark

Web

WordPress with generated configuration and tuned PHP.

wordpress

How it works

Every container follows the same contract: a declarative forge.toml build, a JavaScript entrypoint with no shell, and an ezx supervisor that stays PID 1 for the lifetime of the container.

LIFECYCLE OF EVERY CONTAINER

▦ forge.toml MANIFEST
⑃ DAG resolve TOPO + PARALLEL
▤ image REVIEWABLE LAYERS
⚙ entrypoint CONFIG + VALIDATE
◉ ezx PID 1 SUPERVISOR
▦ PACKAGES
⤓ SOURCES
# CHECKSUMS
▶ YOUR APP
♥ HEALTHZ

Packages, checksum-verified sources, and pinned variables flow into forge, which resolves the manifest into a DAG and builds the image in parallel, ordered operations. At run time the ezx entrypoint validates the environment and writes config, then the supervisor stays PID 1: it drops privileges, forwards signals, and probes the composite health endpoint for the whole lifetime of the container.

Built with forge, supervised by ezx.

Quickstart

Images are published to GHCR per container. Pull one, mount the volume tree, and it boots with sane defaults.

Pull a container
docker pull ghcr.io/supanadit/containers/postgresql:<tag>
Run PostgreSQL
docker run -d --name pg \
  -p 5432:5432 \
  -e POSTGRESQL_PASSWORD=secret \
  -v pgdata:/opt/containers/data \
  ghcr.io/supanadit/containers/postgresql:<tag>

# the entrypoint registers a composite health endpoint on its shared health server

Ready-made compose scenarios and per-container guides live in the documentation:

Or take a full example stack
open https://docs.containers.supanadit.com/postgresql

FAQ

What is this collection?

A set of production-ready Docker containers — PostgreSQL, MariaDB, Kafka, etcd, MinIO, the Grafana observability stack, Airflow, Spark, and more — intended as a transparent alternative to Bitnami images. Every build and runtime decision is visible in the repository.

What makes these different from other community images?

Nothing is hidden in shell scripts. Builds are declared in a forge.toml manifest executed by forge; the entrypoint is a small set of JavaScript modules executed by ezx, a Go supervisor that stays PID 1. Applications run as dedicated non-root users, downloads are checksum-verified, and every container ships compose-based CI tests.

Where do the images live?

On GHCR under ghcr.io/supanadit/containers/<container>, tagged per container as <container>-rX.Y.Z (sometimes prefixed with the upstream version, e.g. wordpress-apache-6.9-r5). Pull the tag that matches your container.

How do I configure a container?

With environment variables only. Each container declares its variables in a single env.js module, validates them at boot, and generates the application config file from them. Invalid environments fail fast — before any side effect.

Where are the volume paths?

Every container uses the same tree: /opt/containers/data, config, logs, run, and backup, pre-created and owned by the application user in the image. Mount your volumes directly onto those paths.

Is there an example for my use case?

Yes — the documentation site at docs.containers.supanadit.com has per-container guides and compose scenarios, including TLS setups, etcd and Kafka clusters, and S3-backed observability stacks.

What licence is this under?

MIT. The forge build tool and the ezx supervisor are separate open-source projects of the same author.

Stop trusting black-box images.

Twenty-one containers, every line reviewable, tested in CI on every pull request.

Browse the containers