# Advanced multi-catalog DEV sandbox: backend (with bundled Spark) + Postgres + # MinIO + REST + Nessie + Polaris, for exercising every catalog type locally. # For the plain app, use the tiered docker-compose.yml instead (see README). # docker compose -f docker-compose.dev.yml up -d name: iceguard-dev services: # ─── IceGuard Backend (Quarkus, with bundled Spark) ─── backend: build: context: ./backend dockerfile: Dockerfile.spark container_name: iceguard-backend ports: - "8080:8080" environment: QUARKUS_DATASOURCE_DB_KIND: postgresql QUARKUS_DATASOURCE_USERNAME: iceguard QUARKUS_DATASOURCE_PASSWORD: iceguard QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://postgres:5432/iceguard # Schema via Flyway + Hibernate validate (app defaults). Start on an empty DB. QUARKUS_OIDC_ENABLED: "false" QUARKUS_HTTP_CORS: "true" QUARKUS_HTTP_CORS_ORIGINS: http://localhost:5173,http://localhost:3000 # Allow large data-insert request bodies (default is ~10M). QUARKUS_HTTP_LIMITS_MAX_BODY_SIZE: 64M AWS_ACCESS_KEY_ID: minioadmin AWS_SECRET_ACCESS_KEY: minioadmin AWS_REGION: us-east-1 # Spark executor: spark-sql is bundled in the image; Iceberg jars are baked into # $SPARK_HOME/jars, so disable --packages (avoids a runtime download). ICEGUARD_SPARK_SQL_PATH: /opt/spark/bin/spark-sql ICEGUARD_SPARK_ICEBERG_RUNTIME: "" ICEGUARD_SPARK_AWS_BUNDLE: "" depends_on: postgres: condition: service_started networks: - iceguard # ─── Catalog 1: Iceberg REST Catalog (Apache reference) ─── # Backed by PostgreSQL (db `restcat`) via the postgres-enabled fixture image, so # namespaces/tables persist across restarts (the stock image uses ephemeral SQLite). rest-catalog: build: context: ./docker/iceberg-rest-pg image: iceguard-iceberg-rest-pg container_name: iceguard-rest-catalog restart: unless-stopped ports: - "8181:8181" environment: AWS_ACCESS_KEY_ID: minioadmin AWS_SECRET_ACCESS_KEY: minioadmin AWS_REGION: us-east-1 CATALOG_WAREHOUSE: s3://warehouse/rest/ CATALOG_IO__IMPL: org.apache.iceberg.aws.s3.S3FileIO CATALOG_S3_ENDPOINT: http://minio:9000 CATALOG_S3_PATH__STYLE__ACCESS: "true" # Persistent JDBC catalog backend (PostgreSQL). CATALOG_CATALOG__IMPL: org.apache.iceberg.jdbc.JdbcCatalog CATALOG_URI: jdbc:postgresql://postgres:5432/restcat CATALOG_JDBC_USER: iceguard CATALOG_JDBC_PASSWORD: iceguard depends_on: minio-init: condition: service_completed_successfully postgres: condition: service_healthy networks: - iceguard # ─── Catalog 2: a REAL Apache Nessie Catalog Server ─── # An actual Nessie server: it serves the Iceberg REST API at :19120/iceberg and keeps # a Git-like commit log, so IceGuard's Nessie history view shows the full reconstructed # history. Version store: JDBC (Postgres `nessie` DB — schema auto-created on first start). # Object store: MinIO via server-side S3FileIO; static keys are passed as a Nessie secret ref # (urn:nessie-secret:quarkus:nessie-s3-creds -> NESSIE_S3_CREDS_NAME / _SECRET). nessie: image: ghcr.io/projectnessie/nessie:0.104.1 container_name: iceguard-nessie restart: unless-stopped ports: - "19120:19120" environment: NESSIE_VERSION_STORE_TYPE: JDBC NESSIE_VERSION_STORE_PERSIST_JDBC_DATASOURCE: postgresql QUARKUS_DATASOURCE_POSTGRESQL_DB_KIND: postgresql QUARKUS_DATASOURCE_POSTGRESQL_JDBC_URL: jdbc:postgresql://postgres:5432/nessie QUARKUS_DATASOURCE_POSTGRESQL_USERNAME: iceguard QUARKUS_DATASOURCE_POSTGRESQL_PASSWORD: iceguard NESSIE_CATALOG_DEFAULT_WAREHOUSE: warehouse NESSIE_CATALOG_WAREHOUSES_WAREHOUSE_LOCATION: s3://warehouse/nessie-real/ NESSIE_CATALOG_SERVICE_S3_DEFAULT_OPTIONS_REGION: us-east-1 NESSIE_CATALOG_SERVICE_S3_DEFAULT_OPTIONS_ENDPOINT: http://minio:9000/ NESSIE_CATALOG_SERVICE_S3_DEFAULT_OPTIONS_PATH_STYLE_ACCESS: "true" NESSIE_CATALOG_SERVICE_S3_DEFAULT_OPTIONS_AUTH_TYPE: STATIC NESSIE_CATALOG_SERVICE_S3_DEFAULT_OPTIONS_ACCESS_KEY: urn:nessie-secret:quarkus:nessie-s3-creds # The secret values must be enumerable config (SmallRye can't enumerate env-only keys, so # the secret provider wouldn't see them) — pass them as -D system properties. JAVA_OPTS_APPEND: >- -Dnessie-s3-creds.name=minioadmin -Dnessie-s3-creds.secret=minioadmin depends_on: minio-init: condition: service_completed_successfully postgres: condition: service_healthy networks: - iceguard # ─── Catalog 3: Apache Polaris (catalog-as-a-service) ─── # ─── Polaris schema/realm bootstrap (one-shot, into Postgres) ─── # One-shot, run manually on a fresh DB: `docker compose --profile bootstrap run --rm polaris-bootstrap` # (Re-running on an already-bootstrapped realm fails, so it is NOT a startup dependency.) polaris-bootstrap: image: apache/polaris-admin-tool:latest container_name: iceguard-polaris-bootstrap profiles: ["bootstrap"] depends_on: postgres: condition: service_healthy environment: polaris.persistence.type: relational-jdbc quarkus.datasource.db-kind: postgresql quarkus.datasource.username: iceguard quarkus.datasource.password: iceguard quarkus.datasource.jdbc.url: jdbc:postgresql://postgres:5432/polaris command: - "bootstrap" - "--realm=POLARIS" - "--credential=POLARIS,polaris-root,polaris-secret" networks: - iceguard polaris: image: apache/polaris:latest container_name: iceguard-polaris restart: unless-stopped ports: - "8182:8181" depends_on: postgres: condition: service_healthy environment: # Real AWS S3 (bucket polaris-iceguard, us-east-1). Temporary STS creds — refresh when expired. AWS_ACCESS_KEY_ID: ${POLARIS_AWS_ACCESS_KEY_ID:-} AWS_SECRET_ACCESS_KEY: ${POLARIS_AWS_SECRET_ACCESS_KEY:-} AWS_SESSION_TOKEN: ${POLARIS_AWS_SESSION_TOKEN:-} AWS_REGION: us-east-1 # Persistence: Postgres (relational-jdbc) — survives restarts. polaris.persistence.type: relational-jdbc quarkus.datasource.db-kind: postgresql quarkus.datasource.username: iceguard quarkus.datasource.password: iceguard quarkus.datasource.jdbc.url: jdbc:postgresql://postgres:5432/polaris polaris.realm-context.realms: POLARIS JAVA_OPTS_APPEND: >- -Dpolaris.features.SKIP_CREDENTIAL_SUBSCOPING_INDIRECTION=true -Dpolaris.catalog.io.default-options.s3.region=us-east-1 networks: - iceguard # ─── MinIO (S3-compatible object storage) ─── minio: image: minio/minio:latest container_name: iceguard-minio ports: - "9000:9000" - "9001:9001" environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin command: server /data --console-address ":9001" volumes: - minio-data:/data networks: - iceguard # ─── MinIO init (create buckets) ─── minio-init: image: minio/mc:latest container_name: iceguard-minio-init depends_on: minio: condition: service_started entrypoint: > /bin/sh -c " sleep 3; mc alias set local http://minio:9000 minioadmin minioadmin; mc mb --ignore-existing local/warehouse; echo 'Bucket warehouse created'; " networks: - iceguard # ─── PostgreSQL (IceGuard metadata) ─── postgres: image: postgres:16-alpine container_name: iceguard-postgres restart: unless-stopped ports: - "5433:5432" environment: POSTGRES_DB: iceguard POSTGRES_USER: iceguard POSTGRES_PASSWORD: iceguard volumes: - postgres-data:/var/lib/postgresql/data # Creates the dedicated catalog databases (polaris, restcat, nessie) on a fresh volume. - ./scripts/init-catalog-dbs.sql:/docker-entrypoint-initdb.d/10-catalog-dbs.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U iceguard"] interval: 5s timeout: 3s retries: 10 networks: - iceguard volumes: minio-data: postgres-data: networks: iceguard: driver: bridge