# fxhnt cockpit — Deployment with an in-pod Tailscale **userspace** sidecar (the proper exposure for this
# cluster). The pod CIDR (100.64.0.0/15) overlaps Tailscale's CGNAT range (100.64.0.0/10), so a kernel-mode
# (TS_USERSPACE=false) tailscale proxy hijacks cross-node pod routes and cannot reach the Service. Running
# tailscale in USERSPACE mode inside the cockpit pod avoids that entirely: it never touches kernel routes,
# and `tailscale serve` proxies the tailnet to 127.0.0.1:8080 (same pod, no cross-node hop). Reachable over
# the tailnet at https://fxhnt-dashboard.<tailnet>.ts.net (Tailscale-provisioned TLS via MagicDNS).
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fxhnt-dashboard
  namespace: foxhunt
  labels: { app.kubernetes.io/name: fxhnt-dashboard, app.kubernetes.io/part-of: foxhunt }
spec:
  replicas: 1
  selector: { matchLabels: { app.kubernetes.io/name: fxhnt-dashboard } }
  template:
    metadata:
      labels: { app.kubernetes.io/name: fxhnt-dashboard, app.kubernetes.io/part-of: foxhunt }   # part-of -> postgres ingress allow
    spec:
      serviceAccountName: tailscale-dashboard        # RBAC to read/write the TS state secret
      nodeSelector:
        k8s.scaleway.com/pool-name: platform
      imagePullSecrets:
        - name: gitlab-registry
      containers:
        - name: cockpit
          image: gitlab-registry.foxhunt.svc.cluster.local:5000/root/foxhunt/fxhnt-cockpit:latest
          command: ["fxhnt", "serve", "--host", "0.0.0.0", "--port", "8080"]   # 0.0.0.0 so the kubelet probe (pod IP) + sidecar (localhost) both reach it
          env:
            - name: FXHNT_OPERATIONAL_DSN
              value: "postgresql+psycopg://foxhunt@postgres.foxhunt.svc.cluster.local:5432/fxhnt"
            - name: PGPASSWORD
              valueFrom: { secretKeyRef: { name: db-credentials, key: password } }
          readinessProbe: { httpGet: { path: /healthz, port: 8080 }, initialDelaySeconds: 5, periodSeconds: 10 }
          livenessProbe:  { httpGet: { path: /healthz, port: 8080 }, initialDelaySeconds: 10, periodSeconds: 20 }
          resources: { requests: { cpu: 50m, memory: 128Mi }, limits: { cpu: 500m, memory: 512Mi } }
        - name: tailscale
          image: ghcr.io/tailscale/tailscale:latest
          env:
            - name: TS_AUTHKEY
              valueFrom: { secretKeyRef: { name: tailscale-auth, key: TS_AUTHKEY } }
            - name: TS_KUBE_SECRET
              value: fxhnt-dashboard-ts-state
            - name: TS_USERSPACE
              value: "true"                          # netstack — no kernel route hijack (CGNAT-safe)
            - name: TS_HOSTNAME
              value: "fxhnt-dashboard"               # -> fxhnt-dashboard.<tailnet>.ts.net
            - name: TS_SERVE_CONFIG
              value: /etc/ts/serve.json
          volumeMounts:
            - { name: ts-serve, mountPath: /etc/ts, readOnly: true }
          resources: { requests: { cpu: 25m, memory: 64Mi }, limits: { cpu: 200m, memory: 128Mi } }
      volumes:
        - name: ts-serve
          configMap: { name: fxhnt-dashboard-ts-serve }
---
# tailscale serve: terminate HTTPS on the node's MagicDNS cert, proxy everything to the local cockpit.
apiVersion: v1
kind: ConfigMap
metadata:
  name: fxhnt-dashboard-ts-serve
  namespace: foxhunt
data:
  serve.json: |
    {
      "TCP": {
        "443": { "HTTPS": true },
        "80": { "TCPForward": "127.0.0.1:8080" }
      },
      "Web": {
        "${TS_CERT_DOMAIN}:443": {
          "Handlers": { "/": { "Proxy": "http://127.0.0.1:8080" } }
        }
      }
    }
---
apiVersion: v1
kind: Service
metadata:
  name: fxhnt-dashboard
  namespace: foxhunt
spec:
  selector: { app.kubernetes.io/name: fxhnt-dashboard }
  ports: [{ port: 80, targetPort: 8080, name: http }]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tailscale-dashboard
  namespace: foxhunt
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: tailscale-dashboard
  namespace: foxhunt
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["create", "get", "update", "patch", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: tailscale-dashboard
  namespace: foxhunt
subjects:
  - kind: ServiceAccount
    name: tailscale-dashboard
    namespace: foxhunt
roleRef:
  kind: Role
  name: tailscale-dashboard
  apiGroup: rbac.authorization.k8s.io
