[Proposal] Unified Gateway Container: Consolidate Router and Policy Engine into a Single Container #939
Replies: 4 comments 10 replies
-
|
Regarding log prefixes, I don't see an Alternative 3. To me it sounds like log prefixes makes sense. |
Beta Was this translation helpful? Give feedback.
-
|
What should be the name of the unified gateway container? @nuwand, @pubudu538, @malinthaprasan, @Krishanx92, @VirajSalaka
Some suggestions.
|
Beta Was this translation helpful? Give feedback.
-
|
So we still have the gateway-controller container right? If so what if we call these the controller and processor?
|
Beta Was this translation helpful? Give feedback.
-
|
We may need to verify the functionality on Windows. As WSL is there we should be able to run this without any issue. Is there a way to get the memory and CPU usages for Router and Policy Engine separately? |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
tinias PID 1 init process with a bash entrypoint script managing both processes[rtr]/[pol]) to distinguish output — or skip prefixes entirely (see Alternative 1)Motivation
Proposal
tinias PID 1[rtr]or[pol]The unified container simplifies deployment while reducing latency. Note: The ext_proc gRPC communication between Router and Policy Engine cannot be eliminated — Envoy must call the Policy Engine for every request. What changes is the transport: UDS within the same container replaces TCP over container networking. Since Router depends entirely on Policy Engine for request processing, treating them as an atomic deployment unit reflects their operational coupling. The entrypoint script handles process lifecycle and signal propagation correctly using
tinifor proper signal handling and zombie reaping.Changes Required
Dockerfile- Create unified image containing both Router (Envoy) and Policy Engine binariesdocker-entrypoint.sh- New entrypoint script to launch and monitor both processestinias init process (many base images include it, or install via package manager)pkg/config/config.go- Add UDS socket path option toPolicyEngineConfig(alternative to host:port)pkg/xds/translator.go- UpdatecreatePolicyEngineCluster()to usecore.Address_Pipewhen UDS is configured/var/run/policy-engine.sock) instead of TCP portMakefile- Update build targets to produce single unified gateway imagedocker-compose.yaml- Replace separate router and policy-engine services with single gateway servicegateway/it/docker-compose.test.yamlto use unified gateway image; adjust test steps that target policy-engine container directly (e.g., admin endpoint on port 9002, metrics on port 9003)Process Architecture
The unified container uses this process tree:
Signal handling across three layers:
tiniat PID 1Shutdown timeout ownership: Whoever initiates the shutdown owns the timeout. Orchestrator-initiated shutdown (docker stop / k8s) → orchestrator owns the timeout (
--stop-timeout/terminationGracePeriodSeconds). Crash-initiated shutdown → entrypoint owns the timeout, configured viaSHUTDOWN_TIMEOUTenv var (default 10s, matches Docker's default--stop-timeout).Reference Entrypoint Script
Why explicit PIDs in
wait -n: The log-tagging process substitution spawns reader subshells. Without explicit PIDs,wait -nmight return when a reader exits rather than when Router or Policy Engine exits.Why the trap doesn't loop with a timeout: In Flow B, the orchestrator (Docker/K8s) is responsible for the force-kill deadline. The entrypoint just needs to stay alive and wait — if both processes are hung, the orchestrator will SIGKILL the entire container. Adding a redundant timeout loop here would just duplicate the orchestrator's responsibility.
Inter-Process Communication (IPC) via UDS
The Router (Envoy) communicates with the Policy Engine via gRPC for the ext_proc filter. This communication cannot be eliminated — it's fundamental to how policies are executed.
Current architecture (two containers):
Proposed architecture (unified container with UDS):
Gateway-Controller xDS cluster configuration change:
Policy Engine listener change:
Drawbacks
Alternatives Considered
Alternative 1: No Log Prefixes (NGINX Ingress Controller approach)
"started listening on port X"is ambiguous — is that Router or Policy Engine?while readloop.kubectl logsordocker logsgrep becomes unreliable when both processes use similar log patterns.The entrypoint would simplify to:
Alternative 2: In-Container Process Supervisor (supervisord)
Compatibility
Migration Steps
docker-compose.yamlor Kubernetes manifests to use single gateway service instead of separate router and policy-engine servicesUnresolved Questions
[rtr]/[pol]) or skip them entirely like NGINX Ingress Controller does? (see Alternative 1)References
Beta Was this translation helpful? Give feedback.
All reactions