route: serve work.zoo.network via Traefik @file (hanzoai/ingress), drop k8s Ingress

This cluster's hanzoai/ingress (Traefik v3) routes every public zoo host through
the zoo-dynamic ConfigMap (@file provider) with TLS auto-issued by its built-in
ACME resolver over Cloudflare DNS-01 — exactly how api.zoo.network is served.
Kubernetes Ingress objects don't produce the :443 router here (the api-zoo-network
Ingress is vestigial too), so replace k8s/ingress.yaml with k8s/route.yaml, the
router+service fragment merged into zoo-system/zoo-dynamic. One ACME client
(Traefik), no cert-manager. Verified: https://work.zoo.network serves 200 with a
valid LE cert (CN=work.zoo.network).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
zeekay
2026-07-16 21:03:16 -07:00
co-authored by Hanzo Dev
parent 2e533c0d5a
commit 4b00b51a85
3 changed files with 43 additions and 31 deletions
+12 -5
View File
@@ -29,12 +29,19 @@ For production, build with the real RPC baked in:
## Deploy
CI (`.github/workflows/docker.yml`) builds the image on every push to `main`
via the canonical `hanzoai/.github` reusable and pushes it to
CI (`.github/workflows/docker.yml`) builds the image on every push to `main` on
luxfi's in-cluster ARC pool and pushes it to
`ghcr.io/luxfi/work-board:sha-<commit>` — never built locally. It runs on
zoo-k8s (namespace `zoo-mainnet`) behind hanzoai/ingress at
**https://work.zoo.network**. Manifests live in `k8s/` (Deployment + Service +
Ingress): pin `k8s/deployment.yaml` to the CI tag, then `kubectl apply -f k8s/`.
zoo-k8s (namespace `zoo-mainnet`) behind hanzoai/ingress (Traefik) at
**https://work.zoo.network**. Manifests live in `k8s/`:
- `deployment.yaml` + `service.yaml` — 2 replicas serving `dist` on :3000,
Service :80 → :3000. Pin the Deployment to the CI tag, then
`kubectl -n zoo-mainnet apply -f k8s/deployment.yaml -f k8s/service.yaml`.
- `route.yaml` — the Traefik dynamic-config router (host → Service, TLS via the
ingress's built-in ACME / Cloudflare DNS-01 resolver). hanzoai/ingress routes
every public zoo host through the `zoo-dynamic` ConfigMap (`@file` provider),
not Ingress objects; merge this fragment in (see the header in `route.yaml`).
## Data source (Zoo 200200)
-26
View File
@@ -1,26 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: work-zoo-network
namespace: zoo-mainnet
annotations:
# hanzoai/ingress (class "ingress") — NEVER nginx/caddy. Same class + issuer
# as the sibling api-zoo-network ingress in this namespace.
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: ingress
rules:
- host: work.zoo.network
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: work-board
port:
number: 80
tls:
- hosts:
- work.zoo.network
secretName: work-zoo-network-tls
+31
View File
@@ -0,0 +1,31 @@
# Traefik (hanzoai/ingress) dynamic-config route for work.zoo.network.
#
# This cluster's hanzoai/ingress (Traefik v3) routes every public host via the
# @file provider — ConfigMap zoo-system/zoo-dynamic mounted at
# /etc/traefik/dynamic — NOT via Kubernetes Ingress objects. api.zoo.network is
# served exactly this way (api-zoo-network router). TLS is auto-issued by
# Traefik's built-in ACME resolver over Cloudflare DNS-01 (certResolver:
# letsencrypt), so no cert-manager Certificate/secret is involved.
#
# Apply by merging this fragment into the zoo-dynamic ConfigMap's routes.yaml:
# CM=zoo-dynamic; NS=zoo-system
# kubectl -n $NS get configmap $CM -o jsonpath='{.data.routes\.yaml}' > /tmp/routes.yaml
# yq eval-all 'select(fileIndex==0) * select(fileIndex==1)' /tmp/routes.yaml k8s/route.yaml > /tmp/merged.yaml
# kubectl -n $NS patch configmap $CM --type merge \
# -p "$(jq -n --rawfile r /tmp/merged.yaml '{data:{"routes.yaml":$r}}')"
# Traefik (--providers.file.watch=true) hot-reloads within ~60s and issues the cert.
http:
routers:
work-zoo-network:
entryPoints:
- websecure
rule: Host(`work.zoo.network`)
service: work-board
tls:
certResolver: letsencrypt
services:
work-board:
loadBalancer:
passHostHeader: true
servers:
- url: http://work-board.zoo-mainnet.svc.cluster.local:80