High level overview
The image below sketches out the components of the NOUMENA environment. At the center we have the three components that constitute the NOUMENA runtime: the Engine, the (optional) History application and the (optional) Read Model. These components all connect to a PostgreSQL database.
Applications are deployed in the engine, after which they become available through all three components. Authorization is managed using an Identity and Access Management of choice, as long as it supports OIDC.
We typically suggest running a reverse proxy in front of the runtime.
Depending on individual preferences and requirements there are several ways to realize the environment. The diagram below shows an example of a possible configuration.
Docker compose file
Realising such a set-up can be achieved with a docker compose file. What follows is a minimal working example:
version: "2.17.0" services: # the engine requires a PostgreSQL database engine-db: image: postgres:14.5-alpine mem_limit: 256m environment: - POSTGRES_DB=platform - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - ENGINE_DB_USER=engine - ENGINE_DB_PASSWORD=engine_pwd - HISTORY_DB_USER=history - HISTORY_DB_PASSWORD=history_pwd - POSTGRAPHILE_DB_USER=postgraphile - POSTGRAPHILE_DB_PASSWORD=postgraphile_pwd volumes: # refer to database user setup script example (below) for details on how to set up database users - ./bin/init-db-users.sh:/docker-entrypoint-initdb.d/init-db.sh healthcheck: test: pg_isready -U postgres interval: 1s timeout: 5s retries: 50 engine: # refer to Dockerfile example (below) for what would usually get wrapped around an engine image build: . ports: - "12000:12000" environment: ENGINE_DB_URL: "jdbc:postgresql://engine-db/platform" ENGINE_DB_USER: engine ENGINE_DB_PASSWORD: engine_pwd ENGINE_DB_POSTGRAPHILE_USER: postgraphile ENGINE_DB_POSTGRAPHILE_PASSWORD: postgraphile_pwd ENGINE_DB_HISTORY_USER: history ENGINE_DB_HISTORY_PASSWORD: history_pwd ENGINE_DB_HISTORY_SCHEMA: history JWT_TRUSTED_ISSUERS: "http://keycloak:11000/realms/noumena" depends_on: engine-db: condition: service_healthy keycloak: condition: service_healthy history: image: ghcr.io/noumenadigital/packages/history:2023.3.0 ports: - "12010:12010" environment: HISTORY_DB_URL: "jdbc:postgresql://engine-db/platform" HISTORY_DB_USER: history HISTORY_DB_PASSWORD: history_pwd depends_on: engine-db: condition: service_healthy engine: condition: service_healthy postgraphile: image: ghcr.io/noumenadigital/packages/postgraphile:2023.3.0 ports: - "5555:5555" environment: POSTGRAPHILE_DB_URL: "postgres://postgraphile:postgraphile_pwd@engine-db:5432/platform" POSTGRAPHILE_DB_USER: postgraphile POSTGRAPHILE_TRUSTED_ISSUERS: "http://keycloak:11000/realms/noumena," POSTGRAPHILE_ENGINE_HEALTH_ENDPOINT: "http://engine:12000/actuator/health" depends_on: engine-db: condition: service_healthy engine: condition: service_healthy # the engine requires an OIDC provider for authentication # Keycloak provides a lot of options to get this up and running keycloak: image: quay.io/keycloak/keycloak:20.0 command: start --hostname-strict=false --hostname-strict-https=false --metrics-enabled=true --db=postgres environment: KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: Keycloak123! KC_DB_URL: jdbc:postgresql://keycloak-db/postgres KC_DB_USERNAME: postgres KC_DB_PASSWORD: testing KC_HEALTH_ENABLED: "true" KC_HTTP_ENABLED: "true" KC_HTTP_PORT: 11000 KC_HOSTNAME: keycloak healthcheck: test: curl -s localhost:11000/health || exit 1 interval: 1s retries: 60 depends_on: keycloak-db: condition: service_healthy keycloak-db: image: postgres:14.5-alpine mem_limit: 256m environment: POSTGRES_PASSWORD: testing healthcheck: test: pg_isready -U postgres interval: 1s timeout: 5s retries: 50
To run this set-up, execute the following command:
docker compose up --wait --build
To deploy an engine image with NPL source code, you can wrap the engine image and add NPL, which gets deployed during engine startup.
# For a production setup, we advise to use the actual version number instead of 2023.3.0 FROM ghcr.io/noumenadigital/packages/engine:2023.3.0 # Files in npl/npl-1.0.0 contain NPL source code COPY npl/migration.yml migration.yml COPY npl/npl-1.0.0 npl-1.0.0 # Copy migration files to the /migrations folder COPY npl/npl-1.0.0/* /migrations/npl-1.0.0/
We recommend setting up distinct database users for the different applications. What follows is the example script used
in the docker compose file,
#!/bin/sh set -e psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL CREATE ROLE "$ENGINE_DB_USER" LOGIN PASSWORD '$ENGINE_DB_PASSWORD'; ALTER ROLE "$ENGINE_DB_USER" CREATEROLE NOINHERIT; GRANT CREATE ON DATABASE $POSTGRES_DB TO "$ENGINE_DB_USER"; -- CREATE ROLE "$POSTGRAPHILE_DB_USER" LOGIN PASSWORD '$POSTGRAPHILE_DB_PASSWORD'; ALTER ROLE "$POSTGRAPHILE_DB_USER" CREATEROLE NOINHERIT; GRANT CONNECT ON DATABASE $POSTGRES_DB TO "$POSTGRAPHILE_DB_USER"; -- CREATE ROLE "$HISTORY_DB_USER" LOGIN PASSWORD '$HISTORY_DB_PASSWORD'; ALTER ROLE "$HISTORY_DB_USER" CREATEROLE NOINHERIT; GRANT CREATE ON DATABASE $POSTGRES_DB TO "$HISTORY_DB_USER"; EOSQL