> Per AI Blitz Plan §platform.procedures. Layer: 1. Repo: devops-infra-helm-charts. # Procedure — Add or modify a Contour HTTPProxy route > **Layer:** Layer 1 — values diff + PR. > **Blast radius:** one Contour release × one cluster (a misrouted host can break ingress for the whole BU). > **Approval:** consuming-app owner + cluster owner. Platform team if the change touches `contour-external*`. This procedure covers HTTPProxy route changes that flow through one of the cluster's Contour releases. Most clusters run **multiple Contour instances** — read the [contour-nodeselector-tolerations-summary.md](../../../contour-nodeselector-tolerations-summary.md) (repo root) authoritative scheduling matrix before editing **any** Contour values. --- ## Multi-Contour topology | Release name | Plane | Typical purpose | |--------------|-------|-----------------| | `contour-external` | North-south | Public / external traffic (terminates at GCP external LB) | | `contour-external-1` | North-south | Second external Contour (blue-green or capacity split) | | `contour-internal-0` | East-west | Internal traffic, plane 0 | | `contour-internal-1` | East-west | Internal traffic, plane 1 | | `contour-internal-intra-0` | Intra-cluster | Cluster-local east-west, plane 0 | | `contour-internal-intra-1` | Intra-cluster | Cluster-local east-west, plane 1 | Each is a separate Helm release, on a separate node pool, with its own `nodeSelector` / `tolerations` / `computeClass`. Picking the wrong release is the most common authoring mistake. --- ## When to use - Adding a new HTTPProxy / route for a service. - Changing TLS, retry, timeout, or rate-limit policy on an existing route. - Re-pointing an HTTPProxy at a different upstream Service. - Adding a new host to an existing route's `virtualhost.fqdn`. Do **not** use this procedure for: - Changing Contour itself (sizing, scheduling, image) — that's [modify-observability-config.md](modify-observability-config.md)-style infra editing on the Contour release. - Bumping Contour's chart version — use [update-chart-version.md](update-chart-version.md) and consult the versioned sibling (`contour-v1.33.3`). - Curling production hostnames to test — [SANCTITY_RULES R3](../../global/SANCTITY_RULES.md) forbids it. Test from inside the cluster with a `curl` Pod. --- ## Inputs | Input | Example | |-------|---------| | Target cluster | `k8s-supply-prd-ase1` | | Target Contour release | `contour-internal-0` | | HTTPProxy host | `api-foo.internal.meeshogcp.in` | | Upstream Service | `foo-svc.foo-ns:8080` | | TLS source | `cert-manager` / `external-secret` / `none` | | Path prefixes | `/v1`, `/health` | | Approval ticket | CMR-… (if BU policy) | --- ## Pre-conditions - [ ] You know which Contour release is the right one for this host (north-south = `external*`; east-west between BUs = `internal-{0,1}`; cluster-local = `internal-intra-{0,1}`). When in doubt, sample existing HTTPProxies in the same namespace. - [ ] The upstream Service exists or will exist by the time of Sync. - [ ] The DNS name follows the cluster's `external-dns` pattern. - [ ] The TLS source (Secret, Issuer, etc.) exists on the cluster. --- ## Steps ### 1. Identify the right Contour release ```bash ls helm-overrides// | grep '^contour' ``` Pick the release whose plane matches the new route's traffic class. Cross-reference [contour-nodeselector-tolerations-summary.md](../../../contour-nodeselector-tolerations-summary.md). If unsure, look at existing HTTPProxies on the cluster: ```bash # Read existing routes already shipped via this repo yq e '.. | select(has("httpproxies"))' \ helm-overrides//contour-internal-0/custom-values.yaml ``` ### 2. Decide where the HTTPProxy lives Two patterns exist: | Pattern | When | Where to author | |---------|------|-----------------| | **Inline in Contour values** | Routes shared by the cluster's infra layer (e.g. Grafana, Argo CD). | `helm-overrides///custom-values.yaml` under `httpproxies:` (if the chart supports it) or as a sidecar manifest in the same dir. | | **In the consuming app's repo** | Routes for a specific service. | The service's own deployment artifacts. **Out of scope for this repo.** | If the route is service-owned, **redirect** to the consuming team's repo and stop. This procedure only covers infra-layer HTTPProxies. ### 3. Author the HTTPProxy Skeleton (sidecar manifest pattern): ```yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: namespace: spec: virtualhost: fqdn: tls: secretName: # cert-manager-managed Secret routes: - conditions: - prefix: / services: - name: port: timeoutPolicy: response: 30s retryPolicy: count: 2 retryOn: 5xx ``` Drop into `helm-overrides///httpproxies/.yaml` (sidecar manifest) — see [../schemas/raw-manifest-sidecar-schema.md](../schemas/raw-manifest-sidecar-schema.md). ### 4. Lint the HTTPProxy ```bash # Schema check (kubectl --dry-run against the cluster's CRD) kubectl --context= --dry-run=server -f helm-overrides///httpproxies/.yaml apply # Or local: validate against the projectcontour CRD schema kubeconform -schema-location default -schema-location \ 'https://raw.githubusercontent.com/projectcontour/contour/main/examples/contour/01-crds.yaml' \ helm-overrides///httpproxies/.yaml ``` ### 5. Render the chart ```bash helm template helm-templates/ \ -f helm-overrides///custom-values.yaml > /tmp/contour.yaml ``` The render must succeed; the HTTPProxy sidecar is applied alongside, not through Helm — but rendering catches values-side errors that would block sync of the same Argo Application. ### 6. Test from inside the cluster (post-merge, not pre-merge) **Do not** curl `.meeshogcp.in` from your laptop / a build agent. Run a curl Pod on-cluster: ```bash kubectl --context= run -it --rm curl-test \ --image=curlimages/curl --restart=Never -- \ curl -v -H "Host: " http://.projectcontour.svc.cluster.local ``` ### 7. Open the PR ```bash git checkout -b contour/- git add helm-overrides/// git commit -m "contour(/): add route " git push origin contour/- gh pr create --base main ``` ### PR description template ```markdown ## Summary Adds (or modifies) HTTPProxy `` on `` via `` for FQDN ``. ## Why <1-2 sentences> ## Topology - Cluster: `` - Contour release: `` (plane: external / internal / intra) - FQDN: `` - Upstream Service: `:` in namespace `` - TLS: cert-manager Secret `` ## Validation - [ ] HTTPProxy CRD schema validation passed (kubeconform / kubectl --dry-run) - [ ] `helm template` rendered cleanly - [ ] On-cluster curl from a curl Pod returns expected status - [ ] DNS / external-dns plumbed (existing wildcard or new external-dns Service) ## Approvers - App owner: - Cluster owner: - Platform (if `contour-external*`): ``` ### 8. After merge — Sync Open the cluster's Argo CD UI, find the Contour release's Application, **Sync**. Verify: ```bash kubectl --context= -n projectcontour get httpproxy kubectl --context= -n projectcontour describe httpproxy | grep -A5 'Status:' ``` A `Valid: true` status means Contour accepted the route. `Valid: false` with a reason → fix the values and re-PR. If the HTTPProxy is `Valid` but traffic still 5xx → [../runbooks/ingress-down.md](../runbooks/ingress-down.md) §4. --- ## Anti-patterns 1. **Wrong Contour release.** A route mounted on `contour-internal-intra-0` is unreachable from outside the cluster. Cross-check the matrix. 2. **Curling the production FQDN** from a developer machine to "test." Forbidden — see [SANCTITY_RULES R3](../../global/SANCTITY_RULES.md). 3. **Hand-edited values for a single host across all Contour releases** — pick one release, justify it. 4. **`tls.passthrough` for plain HTTP services** — silent: TLS terminates upstream, doesn't. 5. **Wildcard hosts that overlap an existing HTTPProxy** — Contour status will mark one of them invalid; check before merging. 6. **Editing `helm-templates/contour*/`** to "tweak the chart." Layer 1 forbids casual chart edits — the chart is vanilla upstream. --- ## Rollback - Revert the values PR. - Sync the Contour Application — Argo will prune the HTTPProxy or restore the prior values. --- ## Related - Reference (authoritative scheduling): [../../../contour-nodeselector-tolerations-summary.md](../../../contour-nodeselector-tolerations-summary.md). - Runbook: [../runbooks/ingress-down.md](../runbooks/ingress-down.md). - Schema: [../schemas/raw-manifest-sidecar-schema.md](../schemas/raw-manifest-sidecar-schema.md). - Schema: [../schemas/custom-values-schema.md](../schemas/custom-values-schema.md). - ADR: [../../../wiki/analyses/ADR-A3-per-cluster-scheduling.md](../../../wiki/analyses/ADR-A3-per-cluster-scheduling.md).