Add last-reviewed; document the operator now running on both indri's minikube and ringtail's k3s; correct the ArgoCD apps row; pin upstream v1.94.2; add the ProxyGroup Ingress 'host: *' requirement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
61 lines
2.3 KiB
Markdown
61 lines
2.3 KiB
Markdown
---
|
|
title: Tailscale Operator
|
|
modified: 2026-06-08
|
|
last-reviewed: 2026-06-08
|
|
tags:
|
|
- kubernetes
|
|
- tailscale
|
|
---
|
|
|
|
# Tailscale Kubernetes Operator
|
|
|
|
The Tailscale operator enables Kubernetes services to be exposed directly on the Tailscale network via Ingress resources.
|
|
|
|
## Quick Reference
|
|
|
|
| Property | Value |
|
|
|----------|-------|
|
|
| **Namespace** | `tailscale` |
|
|
| **Upstream** | `mirrors/tailscale` on forge (static manifest, pinned `v1.94.2`) |
|
|
| **ArgoCD Apps** | `tailscale-operator` (indri/minikube), `tailscale-operator-ringtail` (ringtail/k3s) |
|
|
|
|
The operator runs on **both** clusters — indri's minikube and ringtail's k3s.
|
|
Both apps layer on the shared `tailscale-operator-base` kustomize directory
|
|
(operator manifest, `ProxyClass`, `dnsconfig`); each cluster supplies its own
|
|
`ProxyGroup` (indri: 2 replicas, ringtail: 1) and OAuth `ExternalSecret`. The
|
|
ringtail overlay additionally rewrites the proxy image to a locally nix-built
|
|
mirror. See [[ringtail]] and [[migrate-wave1-ringtail]] for the ongoing
|
|
migration of k8s workloads onto ringtail.
|
|
|
|
## How It Works
|
|
|
|
Ingresses use a shared ProxyGroup (`ingress`) rather than per-service Tailscale nodes. When you create an Ingress with `ingressClassName: tailscale`:
|
|
|
|
1. Operator configures the shared ProxyGroup pods to serve the new Ingress
|
|
2. Service gets a VIP (Virtual IP) address on the tailnet
|
|
3. Service becomes accessible at `<hostname>.tail8d86e.ts.net`
|
|
4. TLS is handled automatically via Tailscale
|
|
|
|
Two requirements for VIP routing to work:
|
|
|
|
1. Tailnet clients must have `--accept-routes` enabled to route to VIP addresses.
|
|
2. Ingress rules must **not** set an explicit `host:` field. The ProxyGroup
|
|
proxy receives the FQDN as the `Host` header (e.g.
|
|
`prometheus.tail8d86e.ts.net`), which won't match a short name. Use
|
|
`host: "*"` or omit `host:` entirely.
|
|
|
|
Services can be individually tagged (e.g., `tag:flyio-target`) via Ingress annotations to control which ACL grants apply. See [[expose-service-publicly]] for the tagging workflow.
|
|
|
|
## Limitations
|
|
|
|
Services exposed via Tailscale Ingress are **not accessible** from:
|
|
- Other Kubernetes pods (they're not Tailscale clients)
|
|
- Docker containers on indri
|
|
|
|
For pod-to-service communication, use [[routing|Caddy]] (`*.ops.eblu.me`) instead.
|
|
|
|
## Related
|
|
|
|
- [[tailscale]] - Network configuration
|
|
- [[routing]] - Service routing options
|
|
- [[apps]] - Application registry
|