# Choosing a deployment

> Binary, container, Kubernetes with several replicas, behind a mesh or without egress: which topology for which need.

Concept - Since version 0.1.0 - Flexway v1.7.1 - https://flexway.io/en/docs/operations-deployment/

> Operations guide: configure, deploy and observe the gateway. What the feature does, product side: [product guide](https://flexway.io/en/docs/product-overview/); calling it: [developer guide](https://flexway.io/en/docs/developer-overview/).

## What it is

Flexway is **a single binary**, with no database and no control plane. The same `flexway.yaml` and the
same contracts run everywhere; from one topology to another only three things change: how the process
is started, where the shared counters live, and who can reach the admin port.

## How to choose

```mermaid
%%{init: {'theme':'base','themeVariables':{'fontSize':'14px','lineColor':'#94a3b8'}}}%%
flowchart TD
  Q1{"Is one instance enough?"}:::hub
  Q1 -->|"yes"| Q2{"A container engine?"}:::hub
  Q2 -->|"yes"| C["Container"]:::spoke
  Q2 -->|"no"| B["Binary alone"]:::spoke
  Q1 -->|"no"| K["Kubernetes,<br/>several replicas"]:::spoke
  K --> Q3{"Tenant quotas or<br/>shared rates?"}:::hub
  Q3 -->|"yes"| S["+ shared cache"]:::data
  K --> Q4{"Does a mesh already<br/>encrypt the traffic?"}:::hub
  Q4 -->|"yes"| M["Behind the mesh"]:::private
  K --> Q5{"No egress beyond<br/>what is declared?"}:::hub
  Q5 -->|"yes"| E["Sovereign:<br/>egress limited to the declared"]:::private

  classDef hub     fill:#4f46e5,stroke:#3730a3,color:#fff,font-weight:bold
  classDef spoke   fill:#0891b2,stroke:#155e75,color:#fff,font-weight:bold
  classDef data    fill:#3b82f6,stroke:#1d4ed8,color:#fff,font-weight:bold
  classDef private fill:#10b981,stroke:#047857,color:#fff,font-weight:bold
```

The last three questions add up: a cluster can have a Redis-compatible shared cache, a mesh and limited egress at
once.

## The topologies

| Topology | For whom | What it takes | Guide |
| --- | --- | --- | --- |
| **Binary alone** (VM, bare metal) | One instance under systemd or any supervisor | The release archive for `amd64` or `arm64` and `FLEXWAY_CONFIG`; `SIGHUP` reloads, `SIGTERM` drains | [Configuring and running](https://flexway.io/en/docs/operations-overview/) |
| **Container** | A workstation, a VM with Docker or Podman | The image `ghcr.io/flexwiz/flexway:<version>` (`amd64` and `arm64`, no shell, non-root user), the configuration mounted read-only | [Serving your first API](https://flexway.io/en/docs/operations-first-api/) |
| **Kubernetes, several replicas** | Production: availability, scaling | The chart `oci://ghcr.io/flexwiz/charts/flexway`; `replicaCount`, `autoscaling` (2 to 10 replicas by default once enabled), `pdb` | [Moving to Kubernetes](https://flexway.io/en/docs/operations-kubernetes/) |
| **+ shared cache** | Rates shared across replicas, tenant quotas per day or month | A Redis, Dragonfly or Valkey in `server.counters` | [Setting quotas](https://flexway.io/en/docs/operations-quotas/) |
| **Behind a mesh** (Linkerd, Istio) | A cluster where the mesh already encrypts and authenticates pods | No TLS of the gateway's own; anonymous callers counted by peer identity (`server.trusted_proxies: [local]` and `server.peer_identity_header`); a trusted ingress's identity through `auth.trusted_headers` | [Setting quotas](https://flexway.io/en/docs/operations-quotas/), [Examples: inference](https://flexway.io/en/docs/operations-examples-inference/) |
| **Sovereign, limited egress** | An environment without internet access, or where every outbound flow is declared | The list of destinations below, and the chart's egress `NetworkPolicy` (`egress.enabled`, `egress.rules`) | [Moving to Kubernetes](https://flexway.io/en/docs/operations-kubernetes/) |

Without a shared cache, each replica counts for itself and no tenant quota can be declared. With the
shared cache lost, the gateway keeps serving on local counters and says so (`flexway_counters_store_up` at
`0`).

### What the gateway calls

The gateway opens connections only to what its configuration declares: the upstreams, the OIDC issuers
(discovery, keys, introspection, token exchange), the brokers, the schema registry, the KMS, the webhook
targets, the shared cache, and the OTLP collector when set - without `observability.otlp_endpoint` or
`OTEL_EXPORTER_OTLP_ENDPOINT`, nothing is pushed. No call to the product's vendor. For an isolated
environment: copy the images into your registry after verifying them with `cosign`, and write the
editor's schemas from the image with `flexway schema` ([command line](https://flexway.io/en/docs/reference-cli/)).

## Limits

| Topic | State |
| --- | --- |
| Shared state | The shared counter cache only. The response cache, `/events` and `/errors` are **per replica** |
| Admin port | Never exposed, whatever the topology ([admin API](https://flexway.io/en/docs/reference-admin-api/)) |
| Several gateways, one console | **Not built yet**: today one console per gateway deployment ([installing the console](https://flexway.io/en/docs/operations-console-install/)). A console shared between gateways is framed, with no version set |
| Edge mode | **Planned for `1.12.0`**: the same binary on a remote site, a signed configuration pulled, local decisions |

## Going further

- [Changing the configuration without a restart](https://flexway.io/en/docs/operations-live-config/)
- [Upgrading](https://flexway.io/en/docs/operations-upgrade/)
- [Glossary](https://flexway.io/en/docs/reference-glossary/)
