95 lines
4.6 KiB
YAML
95 lines
4.6 KiB
YAML
# One hostname, two backends.
|
|
#
|
|
# The API is routed STRAIGHT AT ITS SERVICE rather than through the web container's nginx, which is
|
|
# what that nginx does on Compose. Two reasons: it removes a hop from every API request and every
|
|
# websocket frame, and it makes the web pod a pure static server again — no dependency on resolving
|
|
# the API, nothing to keep in sync between an ingress and a config file.
|
|
#
|
|
# The consequence has to be applied, not just noted: there is now exactly ONE proxy rewriting
|
|
# X-Forwarded-For, so `TRUST_PROXY_HOPS` is 1. It is 2 in the compose files, and leaving it there
|
|
# would make `req.ip` a value the caller chooses. See 02-config.yaml.
|
|
#
|
|
# Set `externalTrafficPolicy: Local` on the ingress controller's own Service as well, or the node's
|
|
# SNAT will make every request in the world appear to come from a handful of addresses — which
|
|
# defeats every per-address limit in the application at once.
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: jarvis
|
|
namespace: jarvis
|
|
# ONE annotations map. This file used to carry two `annotations:` keys under metadata — the
|
|
# sync-wave above the name, the proxy settings below it — and tools disagree about a duplicated
|
|
# key: kustomize merged the two, while `kubectl apply -f` kept only the second and dropped the
|
|
# sync-wave without a warning. What a cluster received depended on which tool rendered the file.
|
|
annotations:
|
|
# Last, so that the first traffic admitted from outside meets Services with endpoints behind
|
|
# them. An Ingress applied early is a route to a 503.
|
|
argocd.argoproj.io/sync-wave: "2"
|
|
# An agent is idle between operations and the server pings every 30s, so this only has to
|
|
# outlast a quiet period comfortably. Too short and a healthy fleet reconnects all day.
|
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
|
# Matches the API's own ceiling on a JSON body, `BodyLimit.MaxBytes` in
|
|
# src/Jarvis.Api/Common/BodyLimit.cs: 4 MiB, and nginx's `m` is MiB. A document may hold 400,000
|
|
# characters, which is over a megabyte once accented text is UTF-8 encoded, and a diagram export
|
|
# posts back the SVG the browser rendered. Below this they are rejected as a bare 413 with no
|
|
# message.
|
|
#
|
|
# File uploads need more and are NOT raised here: they post under /api/uploads/, which has its
|
|
# own Ingress in 06b-ingress-uploads.yaml, because ingress-nginx applies these annotations to
|
|
# every path of the object that carries them — 13376k here would be 13376k on every API route.
|
|
nginx.ingress.kubernetes.io/proxy-body-size: "4m"
|
|
#
|
|
# NO affinity annotation, and none should be added. The reflex is understandable — there are
|
|
# websockets here — but stickiness cannot solve the problem it would be hired for: the hard case
|
|
# is co-locating an operator's browser with an AGENT's websocket, which arrives from a different
|
|
# network at a different time and whose id is not even known at the browser's handshake. No
|
|
# ingress annotation can express that; it is handled in the application, over Redis.
|
|
#
|
|
# And there is no polling to make sticky: both the client and the server pin
|
|
# transports: ["websocket"], so one logical socket is one TCP connection.
|
|
spec:
|
|
ingressClassName: nginx
|
|
tls:
|
|
- hosts: ["jarvis.example.com"]
|
|
secretName: jarvis-tls
|
|
rules:
|
|
- host: jarvis.example.com
|
|
http:
|
|
paths:
|
|
# Longest prefix first for readers; the controller sorts by specificity itself.
|
|
#
|
|
# The agent websocket has its own rule even though it sits under /api/, mirroring the
|
|
# split in src/Jarvis.Web/nginx.conf: it is the one path where an idle connection
|
|
# legitimately stays open for an hour between frames.
|
|
- path: /api/agents/ws
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: jarvis-api
|
|
port:
|
|
name: http
|
|
- path: /socket.io/
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: jarvis-api
|
|
port:
|
|
name: http
|
|
- path: /api/
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: jarvis-api
|
|
port:
|
|
name: http
|
|
# Everything else is the SPA, whose nginx answers index.html for any path it does not
|
|
# have a file for.
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: jarvis-web
|
|
port:
|
|
name: http
|