API Gateway End-to-End Example

What this page gives you

This deep dive explains a fan-out gateway pattern with one edge cell and three independent backend cells.

Shipped example location on NetBSD:

  • /usr/share/examples/cellmgr/api-gateway

Topology and dependency graph

Cells in this stack:

  • api-gateway-app-a-httpd (backend A on 8080)
  • api-gateway-app-b-httpd (backend B on 8081)
  • api-gateway-app-c-httpd (backend C on 8082)
  • api-gateway-edge-nginx (public edge on 80)

Dependency graph:

  • backend cells have no upstream deps
  • edge depends on all three backends

api-gateway-app-a-httpd, api-gateway-app-b-httpd, api-gateway-app-c-httpd -> api-gateway-edge-nginx

Operational meaning:

  • each backend can be reconciled independently
  • edge converges only after all required backends are present

Manifest deep dive

Backend cell manifests (api-gateway-app-*-httpd.cell)

All three backend manifests follow the same model:

  • CELL_CREATE_PROFILE="medium"
  • one reserved port per backend (8080, 8081, 8082)
  • CELL_SUPERVISE_CMD="/usr/libexec/httpd -I <port> -X -f -s <docroot>"
  • CELL_DEPENDS_ON=""
  • healthcheck asserts backend index.html file exists

This is a good pattern for horizontally split stateless services.

Edge manifest (api-gateway-edge-nginx.cell)

Key fields:

  • CELL_CREATE_PROFILE="high"
  • CELL_CREATE_RESERVED_PORTS="80"
  • CELL_DEPENDS_ON="api-gateway-app-a-httpd,api-gateway-app-b-httpd,api-gateway-app-c-httpd"
  • supervise command runs nginx as nginx user

This manifest is where dependency fan-in is modeled.

Apply plans

  • each backend *.apply writes themed static HTML page into its own docroot
  • edge api-gateway-edge-nginx.apply writes nginx routing config:
    • /a/ -> 127.0.0.1:8080
    • /b/ -> 127.0.0.1:8081
    • /c/ -> 127.0.0.1:8082

No volume manifests are used in this stack because content is static and per cell.

End-to-end deployment steps

Run commands as root (or prefix with doas).

  1. bootstrap host once (skip if already done)
cellmgr system bootstrap
  1. copy shipped example manifests
cp /usr/share/examples/cellmgr/api-gateway/* /etc/cellmgr/
  1. inspect desired state
cellmgr cell show api-gateway-app-a-httpd --view desired
cellmgr cell show api-gateway-app-b-httpd --view desired
cellmgr cell show api-gateway-app-c-httpd --view desired
cellmgr cell show api-gateway-edge-nginx --view desired
  1. run targeted dry-run
cellmgr apply --dry-run api-gateway-app-a-httpd api-gateway-app-b-httpd api-gateway-app-c-httpd api-gateway-edge-nginx
  1. apply stack
cellmgr apply api-gateway-app-a-httpd api-gateway-app-b-httpd api-gateway-app-c-httpd api-gateway-edge-nginx
  1. verify runtime
cellmgr cell list --view merged
cellctl list -T
cellctl stats -T
  1. validate edge routing
  • open http://<host-ip>/a/
  • open http://<host-ip>/b/
  • open http://<host-ip>/c/

You should see three different backend pages routed through one public edge.

Modeling takeaways

  • dependency fan-in on edge models gateway contracts clearly
  • reserved ports prevent accidental port collision between service cells
  • separate backend cells make per-service rollout and troubleshooting easier