Docker¶
Build Images¶
make docker
Compose Modes¶
The stack runs in four modes by selecting an env file and compose profiles as needed.
Quickstart from published GHCR images (LocalStack + :main tags):
make quickstart-up
make quickstart-down
In-memory (default storage, no AWS dependencies):
FLOECAT_ENV_FILE=./env.inmem docker compose -f docker/docker-compose.yml up -d
This mode runs with DEV auth (OIDC disabled), so it does not require Keycloak. The default
docker/env.inmem also enables seeding in iceberg mode.
LocalStack (DynamoDB + S3, DEV auth, no OIDC):
FLOECAT_ENV_FILE=./env.localstack docker compose -f docker/docker-compose.yml --profile localstack up -d
LocalStack + OIDC (DynamoDB + S3 + Keycloak):
FLOECAT_ENV_FILE=./env.localstack-oidc docker compose -f docker/docker-compose.yml --profile localstack-oidc up -d
Real AWS (DynamoDB + S3):
FLOECAT_ENV_FILE=./env.aws docker compose -f docker/docker-compose.yml up -d
Make equivalents:
# In-memory
make compose-up
make compose-down
# LocalStack
make compose-up COMPOSE_ENV_FILE=./env.localstack COMPOSE_PROFILES=localstack
make compose-down COMPOSE_ENV_FILE=./env.localstack COMPOSE_PROFILES=localstack
# LocalStack + OIDC
make compose-up COMPOSE_ENV_FILE=./env.localstack-oidc COMPOSE_PROFILES=localstack-oidc
make compose-down COMPOSE_ENV_FILE=./env.localstack-oidc COMPOSE_PROFILES=localstack-oidc
Split reconciler mode¶
The same service image can run as a control-plane node or as a remote executor node.
Run a control plane plus one executor node:
QUARKUS_PROFILE_SERVICE=reconciler-control \
FLOECAT_ENV_FILE=./env.localstack \
COMPOSE_PROFILES=localstack,reconciler-executor \
docker compose -f docker/docker-compose.yml up -d
Run a control plane plus three executor nodes:
QUARKUS_PROFILE_SERVICE=reconciler-control \
FLOECAT_ENV_FILE=./env.localstack \
COMPOSE_PROFILES=localstack,reconciler-executor \
docker compose -f docker/docker-compose.yml up -d --scale executor=3
Run the same split deployment in local OIDC mode:
QUARKUS_PROFILE_SERVICE=reconciler-control \
FLOECAT_ENV_FILE=./env.localstack-oidc \
COMPOSE_PROFILES=localstack-oidc,reconciler-executor \
docker compose -f docker/docker-compose.yml up -d --scale executor=1
Notes:
- For a true split deployment, run
serviceas the control plane by settingQUARKUS_PROFILE_SERVICE=reconciler-control. The compose file pinsexecutortoQUARKUS_PROFILE_EXECUTOR=reconciler-executorby default. That keeps the public APIs, durable queue ownership, and automatic scheduling on theservicecontainer while settingreconciler.max-parallelism=0there. executoruses the same image but sets:QUARKUS_PROFILE=reconciler-executor,FLOECAT_RECONCILER_REMOTE_FILE_GROUP_EXECUTOR_ENABLED=true,FLOECAT_RECONCILER_WORKER_MODE=remote, andFLOECAT_RECONCILER_AUTO_ENABLED=false.docker compose --scale executor=3starts three identical executor replicas. Each replica connects toservice:9100, leases work independently, and heartbeats/completes jobs through the control-plane RPCs. No executor leader election is required.- Both services must share the same blob/kv backend configuration.
- The durable reconcile store is split into native job-index, ready-queue, lease, and projection domains. Control-plane job-state transitions own job-index and ready mutations. Executor replicas only participate in lease coordination; they do not repair or rebuild queue indexes on reads.
- In OIDC mode, configure the reconciler worker service principal with
FLOECAT_RECONCILER_OIDC_ISSUER,FLOECAT_RECONCILER_OIDC_CLIENT_ID, andFLOECAT_RECONCILER_OIDC_CLIENT_SECRET. Executors then authenticate toReconcileExecutorControlautomatically with cached client-credentials tokens.
In Kubernetes or another orchestrator, the equivalent shape is:
- 1
servicereplica withQUARKUS_PROFILE=reconciler-control - 3 executor replicas with
QUARKUS_PROFILE=reconciler-executor - Shared durable blob/kv configuration for all 4 pods
- Executor gRPC client target pointed at the control-plane service DNS name and port
Interactive CLI in a container:
make compose-shell
OIDC-enabled CLI (for docker/env.localstack-oidc) with automatic token refresh:
make cli-docker
Attach/Detach CLI Container¶
If the stack is already running (including cli), attach to the running CLI process:
docker compose -f docker/docker-compose.yml attach cli
Detach without stopping the container:
Ctrl+P, Ctrl+Q
To open a new one-off interactive CLI session instead of attaching:
make compose-shell
If you switch between LocalStack modes, stop the previous stack first to avoid leftover services:
FLOECAT_ENV_FILE=./env.localstack docker compose -f docker/docker-compose.yml --profile localstack down --remove-orphans
FLOECAT_ENV_FILE=./env.localstack-oidc docker compose -f docker/docker-compose.yml --profile localstack-oidc down --remove-orphans
Configuration and Overrides¶
Compose uses env files to set ports, storage backends, AWS wiring, and feature flags. Defaults live
in docker/docker-compose.yml, and per-mode overrides live in docker/env.*.
Common configuration knobs:
- Hosts/IPs:
FLOECAT_HTTP_HOST(service bind),FLOECAT_REST_HOST(Iceberg REST bind),FLOECAT_GRPC_HOST(gateway → service target). - Ports:
FLOECAT_HTTP_PORT(service),FLOECAT_REST_PORT(Iceberg REST),FLOECAT_GRPC_PORT(gateway → service target). - Storage backends:
FLOECAT_KV,FLOECAT_BLOB,FLOECAT_KV_TABLE,FLOECAT_BLOB_S3_BUCKET. - AWS wiring:
FLOECAT_STORAGE_AWS_REGION,FLOECAT_STORAGE_AWS_S3_ENDPOINT,FLOECAT_STORAGE_AWS_DYNAMODB_ENDPOINT,FLOECAT_STORAGE_AWS_ACCESS_KEY_ID,FLOECAT_STORAGE_AWS_SECRET_ACCESS_KEY,FLOECAT_STORAGE_AWS_S3_PATH_STYLE. - Gateway client-safe storage defaults:
FLOECAT_CONNECTOR_INTEGRATION_STORAGE_CREDENTIAL_PROPERTIES_S3_ENDPOINTandFLOECAT_CONNECTOR_INTEGRATION_STORAGE_CREDENTIAL_PROPERTIES_S3_PATH_STYLE_ACCESSfor non-default endpoints. Temporary vended credentials come from storage authorities. - Seed/fixtures:
FLOECAT_SEED_ENABLED,FLOECAT_SEED_MODE,FLOECAT_FIXTURES_USE_AWS_S3. - Reconciler split deployment:
FLOECAT_RECONCILER_WORKER_MODE,FLOECAT_RECONCILER_MAX_PARALLELISM,FLOECAT_RECONCILER_REMOTE_DEFAULT_EXECUTOR_ENABLED,FLOECAT_RECONCILER_REMOTE_PLANNER_EXECUTOR_ENABLED,FLOECAT_RECONCILER_REMOTE_SNAPSHOT_PLANNER_EXECUTOR_ENABLED,FLOECAT_RECONCILER_REMOTE_FILE_GROUP_EXECUTOR_ENABLED,FLOECAT_RECONCILER_AUTHORIZATION_HEADER,FLOECAT_RECONCILER_OIDC_ISSUER,FLOECAT_RECONCILER_OIDC_CLIENT_ID,FLOECAT_RECONCILER_OIDC_CLIENT_SECRET,QUARKUS_PROFILE_SERVICE,QUARKUS_PROFILE_EXECUTOR.
Where variables are consumed (all FLOECAT_*):
service/src/main/resources/application.propertiesprotocol-gateway/iceberg-rest/src/main/resources/application.propertiesclient-cli/src/main/resources/application.properties
AWS Credentials (Local Dev)¶
The containers can use credentials in this order: env vars first, then a local AWS profile when mounted. This lets SSO or named profiles work without exporting short-lived keys.
Option A: Export credentials into env vars before docker compose up:
aws configure export-credentials --profile awsmark --format env
Option B: Mount ~/.aws and set a profile (this is already wired in docker/docker-compose.yml):
export AWS_PROFILE=awsmark
If AWS_PROFILE is unset, the SDK falls back to env vars or the instance/container role.
If your images run as a non-root user, mount ~/.aws into that user’s home in
docker/docker-compose.yml.
For Iceberg REST credential vending, define a storage authority after the stack starts instead of
injecting static gateway credentials. In LocalStack-style setups, the authority typically carries a
storage prefix, region, endpoint, path-style flag, and source credentials supplied with
storage-authority create ... --cred-type aws ....
OIDC Notes¶
docker/env.inmemexplicitly uses DEV auth (FLOECAT_AUTH_MODE=dev,FLOECAT_GATEWAY_AUTH_MODE=dev) and disables OIDC.docker/env.localstackalso uses DEV auth and keeps OIDC disabled for quick starts.docker/env.localstack-oidcenables OIDC and expects the Keycloak service.- Services running inside the Docker network must use the Keycloak service name:
http://keycloak:8080/realms/floecat. - Clients running on the host (or external containers not on the
docker_floecatnetwork) must usehttp://host.docker.internal:8080/realms/floecat(orKEYCLOAK_PORTif overridden). - If you use Trino with the REST catalog, ensure the gateway audience list includes both
floecat-clientandtrino-client, and ensure the service audience list also includes the reconciler worker client (seedocker/env.localstack-oidc).
OIDC Token for Shell¶
When the stack is running with docker/env.localstack-oidc, the CLI must send a bearer token.
make compose-shell does not fetch/inject a token. Use one of:
# Recommended: fetch token and run CLI in one step
make cli-docker
# Token only (if you want to run compose manually)
make cli-docker-token