Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ So far we have the following datasets which are being used in the images.

## Databases

Two database engines are supported, each published as its own image repository:
Four database engines are supported, each published as its own image repository:

* [PostgreSQL](https://www.postgresql.org/) as [`aa8y/postgres-dataset`](https://hub.docker.com/r/aa8y/postgres-dataset). We use the `alpine` version of the official image as the base image to keep our image slim.
* [MySQL](https://www.mysql.com/) as [`aa8y/mysql-dataset`](https://hub.docker.com/r/aa8y/mysql-dataset). There is no official Alpine image for Oracle MySQL (the official `mysql` image is Oracle Linux / Debian based) and Alpine's own package repositories ship [MariaDB](https://mariadb.org/) in place of MySQL, so to keep the "thin, Alpine-based" goal we build on the community [`yobasystems/alpine-mariadb`](https://hub.docker.com/r/yobasystems/alpine-mariadb) image. MariaDB is the MySQL drop-in Alpine substitutes, and its entrypoint honours the same `MYSQL_*` env vars and `/docker-entrypoint-initdb.d/*.sql` convention as the official postgres image, so the dataset pattern carries over unchanged. See [MySQL images](#mysql-images) for the datasets and tags available.
* [CockroachDB](https://www.cockroachlabs.com/) as [`aa8y/cockroach-dataset`](https://hub.docker.com/r/aa8y/cockroach-dataset). There is no official Alpine image (the official [`cockroachdb/cockroach`](https://hub.docker.com/r/cockroachdb/cockroach) image is UBI-minimal), but it is slim (~170 MB) and multi-arch, and its entrypoint honours the same `/docker-entrypoint-initdb.d/*.sql` convention as the official postgres image (plus a `COCKROACH_DATABASE` env var) when the container is started with `start-single-node`. CockroachDB is PostgreSQL wire- and SQL-compatible, so the dataset pattern carries over and these reuse the same PostgreSQL-dialect sample dumps. See [CockroachDB images](#cockroachdb-images) for the datasets and tags available.
* [SQLite](https://www.sqlite.org/) as [`aa8y/sqlite-dataset`](https://hub.docker.com/r/aa8y/sqlite-dataset). SQLite is serverless — a database is just a file — so there is no server to boot and no init scripts; the build assembles the database file and the image ships it. We use the Alpine, statically-linked [`keinos/sqlite3`](https://hub.docker.com/r/keinos/sqlite3) image (multi-arch) as the base, keeping the image genuinely thin and Alpine-based. See [SQLite images](#sqlite-images) for the datasets and tags available.

## Tags
Expand Down Expand Up @@ -96,6 +97,26 @@ The remaining PostgreSQL datasets are either sourced from PostgreSQL-only upstre
* `omdb`: [df7cb/omdb-postgresql](https://github.com/df7cb/omdb-postgresql) is PostgreSQL-specific — its views rely on the `tsm_system_rows` extension (no MySQL equivalent), so a port would have to drop them and would no longer be the upstream dataset.
* `yugabyte-chinook`, `yugabyte-northwind`, `yugabyte-sportsdb`: superseded on MySQL by the native/ported `chinook`, `northwind`, and `sportsdb` tags above (the Yugabyte SQL is PostgreSQL dialect; `sportsdb` is hand-translated from the same dump, so the prefixed tag is not duplicated here).

## CockroachDB images

The CockroachDB images mirror the PostgreSQL ones: each [`aa8y/cockroach-dataset`](https://hub.docker.com/r/aa8y/cockroach-dataset) image carries exactly one dataset, loaded into its own database, and is built through the same Extract -> Transform -> Load [Dockerfile](cockroach/Dockerfile) driven by `manifest.yml`. The engine is [CockroachDB](https://www.cockroachlabs.com/) (see [Databases](#databases) for the base-image choice); it is PostgreSQL wire- and SQL-compatible, so these reuse the same PostgreSQL-dialect dumps the Yugabyte PostgreSQL tags do. The official `cockroachdb/cockroach` entrypoint creates the database named by the `COCKROACH_DATABASE` env var and runs every `/docker-entrypoint-initdb.d/*.sql` script against it (under `start-single-node`), so — unlike the postgres images — the build emits no `CREATE DATABASE` header; the database is the bare dataset name. All CockroachDB tags are published for `linux/amd64` and `linux/arm64`.

The images run a single-node cluster in insecure mode (these are throwaway practice/test images, mirroring the trivial credentials the postgres/mysql images use), which keeps connecting simple. Start a container and connect with the built-in `cockroach sql` client:
```
docker run -d --name cr-ds-<tag> aa8y/cockroach-dataset:<tag>
docker exec -it cr-ds-<tag> cockroach sql --insecure --database <db_name>
```
where `<tag>` is one of the CockroachDB tags below and `<db_name>` is the matching dataset name.

### CockroachDB datasets

* `chinook`: the [Chinook](https://github.com/lerocha/chinook-database) digital-media store — artists, albums, tracks, customers, and invoices (11 tables in the `public` schema; quoted CamelCase identifiers like `"Track"`, `"InvoiceLine"`). Sourced from [Yugabyte's sample data repo](https://github.com/yugabyte/yugabyte-db/tree/master/sample) (the same PostgreSQL-dialect dump behind the PostgreSQL `yugabyte-chinook` tag), which loads on CockroachDB unchanged.
* `northwind`: the classic Northwind specialty-foods import/export company — customers, orders, products, employees, and suppliers (14 tables in the `public` schema; snake_case identifiers). Sourced from [Yugabyte's sample data repo](https://github.com/yugabyte/yugabyte-db/tree/master/sample) (the same dump behind the PostgreSQL `yugabyte-northwind` tag).

### CockroachDB tags

Available CockroachDB tags are `chinook`, `northwind` and `latest`. Each image carries exactly one dataset, loaded into a database of the same name. `latest` currently tracks the `chinook` dataset.

## SQLite images

The SQLite images follow the same one-dataset-per-image model, but since SQLite is serverless the build inverts: rather than shipping init scripts that run at container start, the build assembles the database file and the final image carries it. Each [`aa8y/sqlite-dataset`](https://hub.docker.com/r/aa8y/sqlite-dataset) image carries exactly one dataset as `/data/<dataset>.db`, built through the [Dockerfile](sqlite/Dockerfile) driven by `manifest.yml`: a dataset is described either by a native SQLite SQL script (fed to the `sqlite3` CLI to build the database) or by a prebuilt SQLite database file (shipped as-is). All SQLite tags are published for `linux/amd64` and `linux/arm64`.
Expand Down Expand Up @@ -247,6 +268,7 @@ integration tests).
## Future Work

* [MySQL](https://www.mysql.com/) images are now shipped (see [MySQL images](#mysql-images)), including the full Stack Exchange family. Remaining MySQL work: port more of the PostgreSQL datasets where a MySQL-native source can be found or the upstream is format-neutral enough to hand-translate faithfully (see [Datasets not ported to MySQL](#datasets-not-ported-to-mysql)).
* [CockroachDB](https://www.cockroachlabs.com/) images are now shipped (see [CockroachDB images](#cockroachdb-images)), starting with the PostgreSQL-dialect `chinook` and `northwind` datasets. Remaining CockroachDB work: extend the dataset set (most plain DDL + data PostgreSQL dumps should load with little or no change).
* [SQLite](https://www.sqlite.org/) images are now shipped (see [SQLite images](#sqlite-images)), starting with the `chinook` and `northwind` datasets. Remaining SQLite work: add more datasets from native SQLite sources or by building from format-neutral SQL.
* Images for other popular databases.
* Find and add more free data sources.
148 changes: 148 additions & 0 deletions cockroach/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# syntax=docker/dockerfile:1
#
# Two-stage, ETL-shaped build. Exactly one dataset per image.
#
# This is the CockroachDB counterpart of ../postgres/Dockerfile and keeps the
# same shape: the builder stage runs Extract -> Transform -> Load as three
# distinct RUN steps driven entirely by build args from manifest.yml, and the
# final stage COPYs the assembled init artifacts onto the official CockroachDB
# image. Build tools live only in the builder, so the final image never carries
# them.
#
# Engine note. CockroachDB is PostgreSQL wire- and (largely) SQL-compatible, so
# the dataset pattern carries over from postgres almost unchanged. The official
# `cockroachdb/cockroach` image's entrypoint (cockroach.sh) honours the same
# /docker-entrypoint-initdb.d/*.sql convention the official postgres image uses
# *when the container is started with `start-single-node`*: it brings up a
# single node, creates the database named by COCKROACH_DATABASE, then runs every
# init script against that database. So unlike postgres we do NOT emit a
# `CREATE DATABASE` + `\c` header -- COCKROACH_DATABASE (set per dataset below)
# creates the database and the scripts already run inside it.
#
# There is no official Alpine image for CockroachDB (the official image is
# UBI-minimal). It is still slim (~170 MB) and multi-arch (amd64 + arm64), so it
# satisfies the "thin" goal while keeping the upstream-supported init flow.
#
# The Dockerfile is dataset-agnostic: nothing here names a specific dataset.
# Most datasets are fully described by EXTRACT_URL + SQL_FILES. Datasets with
# bespoke logic plug into the ETL steps without editing this file, via the
# convention-located scripts/<dataset>/{extract,transform,load} hooks (run at
# the matching stage if present, keyed on $DATASET).
#
# Data Sources.
# Chinook: https://github.com/yugabyte/yugabyte-db/tree/master/sample
# (PostgreSQL-dialect Chinook digital-media store; quoted CamelCase
# identifiers, plain DDL + INSERT data.)
# Northwind: https://github.com/yugabyte/yugabyte-db/tree/master/sample
# (PostgreSQL-dialect Northwind sample; plain DDL + INSERT data.)

# ---------------------------------------------------------------------------
# Builder: extract, transform, load.
# ---------------------------------------------------------------------------
FROM alpine:3.21 AS builder

ARG DATASET
# One URL or a space-separated list. Dispatched on suffix: *.git is cloned,
# *.tar.gz is streamed through tar, anything else is treated as a list of
# files to fetch individually (e.g. the chinook/northwind .sql dump set).
ARG EXTRACT_URL
# Ordered, space-separated paths (relative to the build dir) cat'd into the
# init script after extract/transform.
ARG SQL_FILES
# apk packages beyond the shared set.
ARG EXTRA_PREREQS
# Optional: target access method for `USING lsm` index DDL. Defaults to "lsm"
# (a no-op); set to "gin"/"btree"/etc. to rewrite Yugabyte's lsm indexes.
ARG INDEX_METHOD=lsm

WORKDIR /tmp/build
# Per-dataset ETL hooks, located by convention as scripts/<dataset>/<step>
# (extract|transform|load) and executed at the matching stage below if present.
# Hooks are extensionless and run via their shebang, so a hook may be written in
# any language whose interpreter is in the builder (bash always; others via
# EXTRA_PREREQS).
COPY scripts/ /usr/local/lib/scripts/

# Resilient download options shared by the extract step and any dataset extract
# hook (inherited via the environment). Upstreams return transient 5xx/429s
# under load; retry with backoff so a momentary hiccup doesn't fail the whole
# build. Builder-only, so it never leaks into the final image.
ENV WGET_OPTS="--tries=5 --waitretry=10 --timeout=30 --retry-connrefused --retry-on-host-error --retry-on-http-error=429,500,502,503,504"

# Upstream-content fingerprint, computed on the host from cheap source metadata
# by bin/dataset-checksum and passed in as a build arg. Referenced in the RUN
# below so a real upstream change busts this layer and cascades a rebuild
# through EXTRACT -> TRANSFORM -> LOAD, while an unchanged dataset reuses the
# registry cache. Builder-only, so it never leaks into the final image.
ARG DATASET_CHECKSUM=
RUN echo "dataset checksum: ${DATASET_CHECKSUM}"

# EXTRACT. Shared tools + per-dataset extras, then fetch by URL type and run an
# optional dataset extract hook.
RUN apk add --no-cache \
bash \
bzip2 \
ca-certificates \
git \
unzip \
wget \
$EXTRA_PREREQS && \
bash -c ' \
set -e; \
case "$EXTRACT_URL" in \
*.git) git clone "$EXTRACT_URL" ;; \
*.tar.gz) wget $WGET_OPTS -qO- "$EXTRACT_URL" | tar -xzf - ;; \
*) for u in $EXTRACT_URL; do wget $WGET_OPTS -q "$u"; done ;; \
esac; \
h="/usr/local/lib/scripts/${DATASET}/extract"; if [ -f "$h" ]; then "$h"; fi'

# TRANSFORM. Optional index-method rewrite (a no-op unless INDEX_METHOD is set)
# plus an optional dataset transform hook.
RUN bash -c ' \
set -e; \
if [ "$INDEX_METHOD" != "lsm" ]; then sed -i "s/USING lsm/USING ${INDEX_METHOD}/g" *.sql; fi; \
h="/usr/local/lib/scripts/${DATASET}/transform"; if [ -f "$h" ]; then "$h"; fi'

# LOAD. Assemble the per-dataset init script by concatenating the SQL files.
# No CREATE DATABASE / connect header: the official entrypoint creates the
# COCKROACH_DATABASE database (set per dataset in the final stage) and runs
# every init script against it. An optional dataset load hook can ship extra
# data dirs the dump references.
RUN bash -c ' \
set -e; \
mkdir -p /docker-entrypoint-initdb.d; \
INIT="/docker-entrypoint-initdb.d/${DATASET}.sql"; \
for f in $SQL_FILES; do cat "$f" >> "$INIT"; echo >> "$INIT"; done; \
h="/usr/local/lib/scripts/${DATASET}/load"; if [ -f "$h" ]; then "$h"; fi'

# ---------------------------------------------------------------------------
# Final image: official CockroachDB + the assembled init artifacts only.
# ---------------------------------------------------------------------------
FROM cockroachdb/cockroach:v25.4.11

# Re-declared in this stage so the upstream-content fingerprint can be recorded
# on the final image (visible via `docker inspect`) for observability.
ARG DATASET_CHECKSUM=
LABEL org.opencontainers.image.authors="https://github.com/aa8y" \
org.opencontainers.image.description="CockroachDB images pre-populated with sample datasets for practice and testing." \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.revision="${DATASET_CHECKSUM}" \
org.opencontainers.image.source="https://github.com/aa8y/docker-dataset" \
org.opencontainers.image.title="aa8y/cockroach-dataset" \
org.opencontainers.image.url="https://hub.docker.com/r/aa8y/cockroach-dataset" \
org.opencontainers.image.vendor="https://github.com/aa8y"

ARG DATASET
# Names the database the entrypoint creates and runs the init scripts against.
# The cockroach.sh entrypoint only honours this (and /docker-entrypoint-initdb.d)
# when the container is started with `start-single-node`, which the CMD does.
ENV COCKROACH_DATABASE=${DATASET}

COPY --from=builder /docker-entrypoint-initdb.d /docker-entrypoint-initdb.d

# Single-node cluster in insecure mode -- these are throwaway practice/test
# images (mirroring the trivial credentials the postgres/mysql images use), and
# insecure mode gives the simplest connection: `cockroach sql --insecure`. The
# entrypoint still runs the init scripts under /docker-entrypoint-initdb.d on
# first boot, after the COCKROACH_DATABASE database is created.
CMD ["start-single-node", "--insecure"]
Empty file added cockroach/scripts/.gitkeep
Empty file.
Loading
Loading