diff --git a/README.md b/README.md index 2e4659f..14795bf 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ kit upgrade goes through the app repo's normal review. | Here | `electron/infra` (wg-infra) | App repo | | --- | --- | --- | -| Reusable deploy workflow | Namespace, ServiceAccount, ExternalSecret `server-secrets`, `origin-tls` | `Dockerfile` | +| Reusable deploy workflow | Namespace, ServiceAccount, ExternalSecret `server-secrets` | `Dockerfile` | | kustomize bases (`node-web-app`, `cronjob`) | Key Vault + secrets, CI-push identity, ArgoCD project/app | `deploy/` overlays | | Templates | Repo secrets/variables, Cloudflare DNS, migration runbook | Caller workflow | @@ -60,7 +60,7 @@ kit upgrade goes through the app repo's normal review. ``` .github/workflows/deploy.yml reusable workflow (workflow_call) .github/workflows/ci.yml this repo's own checks -kustomize/node-web-app/ remote base: Deployment + Service + Ingress +kustomize/node-web-app/ remote base: Deployment + Service + HTTPRoute kustomize/cronjob/ remote base: Heroku Scheduler replacement kustomize/examples/ local-path overlay used by CI templates/ files an app copies diff --git a/kustomize/examples/local-overlay/kustomization.yaml b/kustomize/examples/local-overlay/kustomization.yaml index 3c7fc58..8a82c7b 100644 --- a/kustomize/examples/local-overlay/kustomization.yaml +++ b/kustomize/examples/local-overlay/kustomization.yaml @@ -17,9 +17,9 @@ images: newTag: main patches: - target: - kind: Ingress + kind: HTTPRoute name: server patch: |- - op: replace - path: /spec/rules/0/host + path: /spec/hostnames/0 value: example.electronjs.org diff --git a/kustomize/node-web-app/README.md b/kustomize/node-web-app/README.md index ba4345d..8d2f04a 100644 --- a/kustomize/node-web-app/README.md +++ b/kustomize/node-web-app/README.md @@ -1,12 +1,13 @@ # node-web-app -A `Deployment`, `Service` and `Ingress` for an HTTP service listening on -`$PORT` (8080). +A `Deployment`, `Service`, `HTTPRoute` and `BackendTrafficPolicy` for an HTTP +service listening on `$PORT` (8080). The route attaches to the shared +`ionic-platform` Gateway (Envoy Gateway). -Everything is named `server`: the Deployment, Service, Ingress, ServiceAccount -and the `server-secrets` Secret. That matches the `components = { server = … }` -entry in `electron/infra`, which provisions the ServiceAccount and the -ExternalSecret under those names. +Everything is named `server`: the Deployment, Service, HTTPRoute, +BackendTrafficPolicy, ServiceAccount and the `server-secrets` Secret. That +matches the `components = { server = … }` entry in `electron/infra`, which +provisions the ServiceAccount and the ExternalSecret under those names. ## Overlay contract @@ -23,7 +24,7 @@ Your overlays must set: | --- | --- | | Namespace | `namespace: ` | | Image | `images: [{ name: electronionicplatform.azurecr.io/PLACEHOLDER_APP, newName: electronionicplatform.azurecr.io/, newTag: main }]` | -| Hostname | JSON patch on `Ingress/server`: replace `/spec/rules/0/host` | +| Hostname | JSON patch on `HTTPRoute/server`: replace `/spec/hostnames/0` | | `part-of` label | `labels: [{ pairs: { app.kubernetes.io/part-of: }, includeTemplates: true }]` | Optional settings. Apart from replicas, these are JSON patches on @@ -46,3 +47,6 @@ Optional settings. Apart from replicas, these are JSON patches on * No service-account token, no capabilities, uid/gid 1000, `RuntimeDefault` seccomp. The cluster enforces these through Azure Policy, so an image that needs root won't run. +* Requests capped at 1 MiB of body, and cut off after 60s without any data + flowing (as ingress-nginx did) but with no cap on total duration + (`httproute.yaml`, `backendtrafficpolicy.yaml`). diff --git a/kustomize/node-web-app/backendtrafficpolicy.yaml b/kustomize/node-web-app/backendtrafficpolicy.yaml new file mode 100644 index 0000000..a65aa09 --- /dev/null +++ b/kustomize/node-web-app/backendtrafficpolicy.yaml @@ -0,0 +1,24 @@ +# Per-route on purpose: a Gateway-targeted BackendTrafficPolicy is not +# reliably enforced on routes (envoyproxy/gateway#9513), and a route-targeted +# one replaces the Gateway's rather than merging with it, so the Gateway's +# 60s stream idle limit is restated here. +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: BackendTrafficPolicy +metadata: + name: server +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: server + # Envoy has no body limit of its own. 1 MiB is ingress-nginx's old default + # (client_max_body_size); Envoy buffers up to it and answers 413 above it. + requestBuffer: + limit: 1Mi + timeout: + http: + streamIdleTimeout: 60s + # Node closes idle keep-alive connections after 5s (keepAliveTimeout). + # Envoy would otherwise reuse one the server had just closed and fail + # that request with a 503, so close them from Envoy's side first. + connectionIdleTimeout: 4s diff --git a/kustomize/node-web-app/httproute.yaml b/kustomize/node-web-app/httproute.yaml new file mode 100644 index 0000000..f55a093 --- /dev/null +++ b/kustomize/node-web-app/httproute.yaml @@ -0,0 +1,29 @@ +# Route on the shared ionic-platform Gateway (Envoy Gateway). The listener is +# picked by hostname, so no sectionName. +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: server +spec: + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: ionic-platform + namespace: envoy-gateway-system + hostnames: + # Replaced by the app's prod overlay. + - PLACEHOLDER_HOST + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: server + port: 80 + # Envoy's default is a 15s total, which would cut off streams and + # downloads. ingress-nginx only enforced 60s between reads, so the total + # is disabled here ("0s" turns Envoy's route timeout off) and + # backendtrafficpolicy.yaml applies the same 60s idle limit instead. + timeouts: + request: 0s diff --git a/kustomize/node-web-app/ingress.yaml b/kustomize/node-web-app/ingress.yaml deleted file mode 100644 index 444e1fb..0000000 --- a/kustomize/node-web-app/ingress.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: server -spec: - ingressClassName: nginx - tls: - # Shared origin certificate, delivered per namespace by the ionic-app module. - - secretName: origin-tls - rules: - # Replaced by the app's prod overlay. - - host: PLACEHOLDER_HOST - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: server - port: - name: http diff --git a/kustomize/node-web-app/kustomization.yaml b/kustomize/node-web-app/kustomization.yaml index f1228a5..5c0c21e 100644 --- a/kustomize/node-web-app/kustomization.yaml +++ b/kustomize/node-web-app/kustomization.yaml @@ -5,7 +5,8 @@ kind: Kustomization resources: - deployment.yaml - service.yaml - - ingress.yaml + - httproute.yaml + - backendtrafficpolicy.yaml labels: - pairs: app.kubernetes.io/managed-by: argocd diff --git a/templates/deploy/overlays/prod/kustomization.yaml b/templates/deploy/overlays/prod/kustomization.yaml index 34f6e91..783c528 100644 --- a/templates/deploy/overlays/prod/kustomization.yaml +++ b/templates/deploy/overlays/prod/kustomization.yaml @@ -9,11 +9,11 @@ replicas: count: 1 patches: - target: - kind: Ingress + kind: HTTPRoute name: server patch: |- - op: replace - path: /spec/rules/0/host + path: /spec/hostnames/0 value: my-app.electronjs.org # Optional: a health endpoint other than /healthz, plain (non-secret) env # vars and resource limits. Delete whatever you don't need.