Skip to content

Installation

In Falcone is packaged as a single umbrella Helm chart (charts/in-falcone) plus a docker-compose stack (tests/env/docker-compose.yml) for local development. This page covers four deployment targets:

NOTE

The chart is an umbrella: each platform component (gateway, identity, databases, storage, events, functions, control plane, console, observability) is a dependency wrapped by a shared component-wrapper subchart and toggled with <component>.enabled. You can run everything in one cluster or point a component at an external managed service.

Prerequisites

TargetNeeds
Docker ComposeDocker / Docker Compose v2
KubernetesA cluster (1.27+), kubectl, Helm 3.14+
OpenShiftOpenShift 4.x, oc, Helm 3.14+
Air-gappedA reachable private OCI registry + the chart/images mirrored into it

The umbrella chart pulls file-based subcharts, so always build dependencies first:

bash
helm dependency build charts/in-falcone

Values layering

The chart is designed to be configured by layering values files, applied left-to-right (later files win). The recommended order (surfaced in the chart's NOTES.txt) is:

  1. common — shared defaults
  2. environmentdev.yaml / staging.yaml / prod.yaml
  3. customercustomer-reference.yaml (per-customer overrides)
  4. platformplatform-kubernetes.yaml / platform-openshift.yaml
  5. airgapairgap.yaml (only when air-gapped)
  6. local overridelocal.example.yaml (last-mile, never committed secrets)

Deployment profiles under charts/in-falcone/values/profiles/ size the install:

ProfileUse
all-in-one.yamlSingle-node / demo — every component in-cluster
standard.yamlTypical production split
ha.yamlHigh-availability (replicated components)

Set the active profile with deployment.profile and layer the matching file.


Docker Compose (local)

The compose stack in tests/env/docker-compose.yml brings up the real backends the platform runs against — ideal for development and for running the test suites against live services.

bash
cd tests/env
docker compose up -d

It starts:

ServiceImagePurpose
postgrespostgres:16-alpineRelational backend (with tenant RLS)
mongodbmongo:7 (--replSet rs0)Document backend + change streams
keycloakquay.io/keycloak/keycloak:26.0Identity (OIDC), realm auto-imported
redpandaredpandadata/redpanda:v24.2.7Kafka-compatible event bus
miniominio/minio:latestS3-compatible object storage
vaulthashicorp/vault:1.18 (dev)Secret backend
apisixapache/apisix:3.9.1-debianAPI gateway

IMPORTANT

MongoDB runs as a single-node replica set (rs0) because change streams (used by realtime) require one. The first time you start a fresh data directory you may need to initiate it:

bash
docker compose exec mongodb mongosh --eval \
  'rs.initiate({_id:"rs0",members:[{_id:0,host:"mongodb:27017"}]})'

Tear down (and wipe volumes):

bash
docker compose down -v

Kubernetes

Use the Ingress exposure profile. It assumes an ingress controller (e.g. ingress-nginx) is installed.

bash
helm dependency build charts/in-falcone

helm upgrade --install falcone charts/in-falcone \
  --namespace falcone --create-namespace \
  -f charts/in-falcone/values/prod.yaml \
  -f charts/in-falcone/values/platform-kubernetes.yaml \
  -f charts/in-falcone/values/profiles/standard.yaml

The platform-kubernetes.yaml profile sets:

yaml
platform:
  target: kubernetes
  network:
    exposureKind: Ingress        # publish via Ingress objects
  securityProfile: restricted
publicSurface:
  ingress:
    className: nginx
    annotations:
      kubernetes.io/ingress.class: nginx

After install, the chart prints the public endpoints it created:

  • APIhttps://<api-host>/
  • Identityhttps://<identity-host>/
  • Realtimehttps://<realtime-host>/
  • Consolehttps://<console-host>/

Set the hostnames under publicSurface.hostnames.* and TLS under publicSurface.tls.mode. A bootstrap job (<release>-bootstrap) runs on install to reconcile gateway routes, the identity realm and the initial platform configuration (guarded by a lock ConfigMap so it is idempotent).

Watch it converge:

bash
kubectl -n falcone rollout status deploy --timeout=300s
kubectl -n falcone get pods

OpenShift

OpenShift uses Routes instead of Ingress and a stricter security context. Layer platform-openshift.yaml:

bash
helm dependency build charts/in-falcone

helm upgrade --install falcone charts/in-falcone \
  --namespace falcone --create-namespace \
  -f charts/in-falcone/values/prod.yaml \
  -f charts/in-falcone/values/platform-openshift.yaml \
  -f charts/in-falcone/values/profiles/standard.yaml

The OpenShift profile sets:

yaml
platform:
  target: openshift
  network:
    exposureKind: Route           # publish via OpenShift Routes
  securityProfile: restricted-v2
  openshift:
    enabled: true
  routeAnnotations:
    haproxy.router.openshift.io/timeout: 30s
apisix:
  securityContext:
    allowPrivilegeEscalation: false
    capabilities:
      drop: [ALL]

It drops empty podSecurityContext blocks so OpenShift can inject the namespace's assigned UID range, and applies restricted-v2-compatible container security contexts. Routes are annotated with an HAProxy timeout suitable for the realtime SSE endpoints.

TIP

The platform image references can be retargeted to an OpenShift-internal registry (e.g. Harbor) the same way the air-gapped profile does — see below.


Air-gapped

For clusters with no internet access, mirror all images into a private registry and layer airgap.yaml. It rewrites every component's image repository to the private registry and wires the pull secret + CA bundle:

yaml
global:
  airgap:
    enabled: true
  privateRegistry:
    enabled: true
    registry: registry.airgap.in-falcone.local
    pullSecretNames: [in-falcone-registry]
    caBundleConfigMap: in-falcone-registry-ca
  imagePullSecrets:
    - name: in-falcone-registry
  imageRegistry: registry.airgap.in-falcone.local
apisix:    { image: { repository: registry.airgap.in-falcone.local/apache/apisix } }
keycloak:  { image: { repository: registry.airgap.in-falcone.local/keycloak/keycloak } }
postgresql:{ image: { repository: registry.airgap.in-falcone.local/bitnami/postgresql } }
mongodb:   { image: { repository: registry.airgap.in-falcone.local/bitnami/mongodb } }
kafka:     { image: { repository: registry.airgap.in-falcone.local/bitnami/kafka } }
storage:   { image: { repository: registry.airgap.in-falcone.local/minio/minio } }
controlPlane: { image: { repository: registry.airgap.in-falcone.local/example/in-falcone-control-plane } }
webConsole:   { image: { repository: registry.airgap.in-falcone.local/example/in-falcone-web-console } }

Workflow:

  1. Mirror images into registry.airgap.in-falcone.local (use skopeo copy or your registry's import tooling).
  2. Create the pull secret + CA configmap referenced above in the target namespace.
  3. Install, layering the airgap file last (before any local override):
bash
helm dependency build charts/in-falcone

helm upgrade --install falcone charts/in-falcone \
  --namespace falcone --create-namespace \
  -f charts/in-falcone/values/prod.yaml \
  -f charts/in-falcone/values/platform-kubernetes.yaml \
  -f charts/in-falcone/values/profiles/standard.yaml \
  -f charts/in-falcone/values/airgap.yaml

For OpenShift air-gapped installs, swap platform-kubernetes.yaml for platform-openshift.yaml.


Verifying the install

bash
# all workloads ready
kubectl -n falcone get pods

# the bootstrap job completed
kubectl -n falcone get job -l app.kubernetes.io/component=bootstrap

# reach the console
open https://<console-host>/

Then continue to the Quickstart to create your first tenant and app.

Troubleshooting

  • helm upgrade fails values schema validation — the chart ships a strict values.schema.json. If you are iterating on a partial values set, add --skip-schema-validation to the Helm command.
  • MongoDB realtime not delivering — ensure MongoDB is a replica set; change streams (and therefore realtime) require it.
  • Air-gapped images ImagePullBackOff — confirm the pull secret name matches global.imagePullSecrets and the CA bundle configmap exists in the namespace.

Released under the MIT License.