blob: 344abdad8ec35b861d087f7e6f2e1e7fa9fa31f1 [file] [view]
# Deployment & Operations
**Audience:** operators deploying EventMesh images and ports, single- vs
multi-instance coordination, connector deployment, security checklist, and
the incident runbook.
---
## Deployment modes
The capability surface is honest about what the default bootstrap starts
(issue #5380). Three supported modes:
| Mode | How to start | What it includes |
| --- | --- | --- |
| **Core Runtime** *(default)* | `bin/start.sh`, Docker image, `EventMeshApplication.main()` | Traffic HTTP (`/events/*`, legacy `/eventmesh/*`), admin plane (token-guarded, fail-closed), WebSocket push (opt-in `-Deventmesh.ws.port`), connector scheduling. **A2A gateway and v2 streaming sessions are NOT wired.** |
| **Session/streaming Runtime** | Embedder builds the session layer via builders (`withAgentRegistrar` / `withMatchmaker` / `withSessionRouter`) before `start()` the channel strategy is an explicit embedder choice (no `-D`) | Everything in core, plus `/session/*` streaming endpoints |
| **A2A Gateway** | Separate launcher wiring `A2AGatewayServer` *(Experimental)* | `/a2a/tasks*` endpoints on their own port |
The A2A *quota classification*, *auth/ACL/quota gate* and *HTTP handler*
live in the core module and are exercised by tests, but the default
distribution does not start the A2A listener.
## Ports
| Port | Server | Notes |
| --- | --- | --- |
| 10105 | Traffic HTTP | `/events/*`, `/session/*`, `/agent/*`, legacy `/eventmesh/*` |
| 10106 | Admin HTTP | `/admin/*` + `/metrics` (Prometheus); token-guarded |
| 10107 | WebSocket *(opt-in)* | `-Deventmesh.ws.port=10107`; disabled by default |
## Running
### Docker
```shell
docker run -d --name eventmesh \
-e EVENTMESH_STORAGE_TYPE=kafka \
-e EVENTMESH_KAFKA_NAMESRV=YOUR_KAFKA:9092 \
-p 10105:10105 -p 10106:10106 \
apache/eventmesh:latest
```
`docker/Dockerfile` is a two-stage build (Gradle 8.5 + JDK 21 builder
Temurin 21 JRE runtime, non-root). Storage/protocol plugins are discovered
from `./plugin/` by the SPI class loader.
### From source
```shell
git clone https://github.com/apache/eventmesh.git && cd eventmesh
export EVENTMESH_STORAGE_TYPE=kafka # rocketmq | rocketmq5 | kafka
export EVENTMESH_KAFKA_NAMESRV=localhost:9092
./gradlew :eventmesh-runtime:clean :eventmesh-runtime:dist
cd eventmesh-runtime/dist && bash bin/start.sh
```
`bin/start.sh` maps `EVENTMESH_STORAGE_TYPE` / `EVENTMESH_HTTP_PORT` /
`EVENTMESH_ADMIN_PORT` / `EVENTMESH_OFFSET_PATH` (+ arbitrary `JAVA_OPTS`)
onto `-D` system properties.
### Verify
```shell
curl http://localhost:10106/admin/health # {"status":"UP"}
```
## Kubernetes
Plain manifests live in [`deploy/kubernetes/`](../../deploy/kubernetes/)
runtime **StatefulSet** (PVC-backed RocksDB offsets, `/admin/health` probes,
non-root) + connector-runtime **Deployment**, kustomize-ready:
```shell
kubectl apply -k deploy/kubernetes
```
Edit `runtime-configmap.yaml` (storage endpoints) and `runtime-secret.yaml`
(admin token) first. Scaling to `PARTITION_OWNED_PULL` requires the meta keys
in `JAVA_OPTS` see the manifests README. A Helm chart and a decision on the
legacy operator path (#3327) are planned follow-ups.
## Single-instance vs multi-instance
The delivery topology (`-Deventmesh.delivery.topology`, see
[Control plane](control-plane.md#1-deliverytopology)):
| Mode | Default | What it does | Requires |
| --- | --- | --- | --- |
| `LOCAL_STICKY_PULL` | **Yes** | Every instance polls every partition of every subscribed topic | Nothing the single-instance default |
| `PARTITION_OWNED_PULL` | No | Each instance owns a strict subset of partitions (Meta CAS + fencing); no duplicate consumption | A meta store |
Multi-instance coordination keys:
```properties
-Deventmesh.meta.type=nacos # cluster mode; currently: nacos
-Deventmesh.meta.addr=nacos:8848
-Deventmesh.instance.id=10.0.0.5:10105 # defaults to host:port
-Deventmesh.offset.meta=true # opt-in remote offset tier (see below)
```
- An **unknown meta type fails fast at boot** in cluster mode (no silent
in-memory isolation).
- The meta-backed offset tier is **opt-in** (`eventmesh.offset.meta=true`)
local RocksDB is the default deliver/ack progress layer because the
rocketmq5 backend gets broker-side at-least-once via POP.
## Connectors
Connectors (23 source/sink plugins: Kafka, JDBC, MongoDB, S3, DingTalk,
Slack, WeChat, Lark, ChatGPT, MCP, Prometheus, …) run in a **separate
process** `eventmesh-connector-runtime` and talk to the runtime over
HTTP + CloudEvents:
```shell
docker run -e EVENTMESH_RUNTIME_URL=http://runtime:10105 eventmesh-connector:uni
```
Connector definitions are managed through `/admin/connectors` (CRUD) and
scheduled by the runtime's `ConnectorScheduler` with **generation
fencing** (#5382): every (re)assignment bumps a per-connector generation,
and a stale delayed start can never take over a connector running a newer
generation. Status: **Experimental** — all 23 plugins carry unit tests
since [#5412](https://github.com/apache/eventmesh/pull/5412) (hermetic
webhook tests + contract tests for external-client plugins); real-backend
integration tests remain the GA gate.
## Production checklist
- [ ] `EVENTMESH_STORAGE_TYPE` + backend address consistent on every instance
- [ ] `eventmesh.offset.path` on persistent storage (survives restarts)
- [ ] Decide WebSocket port (default disabled)
- [ ] **Set `-Deventmesh.admin.token`** — without it the admin API is
fail-closed (503) by design
- [ ] Install a `SecurityGate` (auth tokens + ACL + quota + audit) for the
traffic plane — see [Security](../architecture/security.md)
- [ ] TLS on the traffic port for anything beyond localhost
(`eventmesh.tls.keystore.*`)
- [ ] Per-topic rate limits for known hot topics
- [ ] Prometheus scraping `/metrics`; alerts per
[Observability](observability.md)
## Runbook — common failures
| Symptom | Check | Fix |
| --- | --- | --- |
| Boot: `no MeshStoragePlugin for '<type>'` | Storage type / plugin jar | Set correct `EVENTMESH_STORAGE_TYPE`; ensure the storage plugin jar is on the classpath |
| Boot: `topic not exist` (CODE 17) | Broker `autoCreateTopicEnable=false` | Pre-create the topic (4+ queues) |
| Boot: `unsupported eventmesh.meta.type` | Cluster mode meta type | Use `nacos` (or drop cluster mode) |
| Boot: `admin_locked` on admin calls | No admin token set | `-Deventmesh.admin.token=<secret>` |
| Events not delivered | `/admin/health` → `pendingDeliveries` | Subscriber not assigned / ACK backlog; check subscriptions on `/admin/subscriptions` |
| DLQ piling up | `/admin/dlq/browse?topic=` | Fix the consumer, then `/admin/dlq/replay` |
| Publishes throttled | `/admin/metrics` → `rateLimited` | Adjust `/admin/ratelimit` |
| Offset write failures growing | `RocksDBOffsetStore` counter | Disk full / permissions on `eventmesh.offset.path` |
| SSE client silent | Connection write failed → auto-nack | Client network; event will be re-delivered |
## Upgrade / rollback
- **Rolling restart**: stop → start per instance. Offsets persist (RocksDB)
and in-flight deliveries re-dispatch on boot (at-least-once) — no lost
window.
- **Rollback**: swap the previous image; the RocksDB offset/state format is
unchanged across patch releases.
## Known limitations
- **Container-dependent test suites** (Testcontainers E2E, broker-failover
chaos, rolling-upgrade drills) require a Docker environment; they are
tracked as deferred coverage, not as passing guarantees
([HA plan](../architecture/review/production-ha-plan.md)).
- Nacos watch timing can fluctuate under churn; multi-instance watch-suite
runs are occasionally flaky (timing, not correctness).
- A2A gateway and v2 streaming sessions need a dedicated launcher (see
deployment modes above).