--- title: Deploy K8s Service modified: 2026-02-15 last-reviewed: 2026-02-15 tags: - how-to - kubernetes - argocd --- # Deploy a Kubernetes Service Quick reference for deploying a new service to BlumeOps Kubernetes via ArgoCD. See [[adding-a-service|the tutorial]] for detailed explanations. ## Create Manifests ``` argocd/manifests// ├── deployment.yaml ├── service.yaml └── ingress-tailscale.yaml ``` Namespace should match service name. Use `registry.ops.eblu.me` for images. ## Create ArgoCD Application ```yaml # argocd/apps/.yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: namespace: argocd spec: project: default source: repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git targetRevision: main path: argocd/manifests/ destination: server: https://kubernetes.default.svc namespace: syncPolicy: syncOptions: - CreateNamespace=true ``` ## Configure Ingress Add a [[tailscale-operator|Tailscale Ingress]] routed through the ProxyGroup with Homepage annotations: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: -tailscale namespace: annotations: tailscale.com/proxy-class: "default" tailscale.com/proxy-group: "ingress" gethomepage.dev/enabled: "true" gethomepage.dev/name: "Service Name" gethomepage.dev/group: "Services" gethomepage.dev/icon: ".png" gethomepage.dev/href: "https://.ops.eblu.me" gethomepage.dev/pod-selector: "app=" spec: ingressClassName: tailscale defaultBackend: service: name: port: number: 80 tls: - hosts: - ``` Key points: - **`proxy-group: "ingress"`** routes through the shared ProxyGroup instead of spawning a per-ingress proxy - **Do not use `rules:` with `host:`** — the ProxyGroup proxy receives the FQDN as Host header (e.g. `.tail8d86e.ts.net`), so a short `host: ` won't match. Use `defaultBackend` instead. - **`tls.hosts`** sets the MagicDNS hostname (becomes `.tail8d86e.ts.net`) - **`gethomepage.dev/group`** — use one of the existing groups: "Services", "Content", or "Infrastructure" - **`tailscale.com/tags`** is not needed in the default case — the ProxyGroup already applies `tag:k8s`. Only add this annotation when the service needs public internet access via the [[flyio-proxy]]. When you do, you must include both tags (setting tags overrides the ProxyGroup default): ```yaml tailscale.com/tags: "tag:k8s,tag:flyio-target" ``` Then add a Caddy route and Fly.io proxy config per [[expose-service-publicly]]. ## Add Caddy Route (if needed) If other pods need to access the service, add to `ansible/roles/caddy/defaults/main.yml`: ```yaml caddy_services: - name: host: ".{{ caddy_domain }}" backend: "https://.tail8d86e.ts.net" ``` Then: `mise run provision-indri -- --tags caddy` See [[routing]] for when Caddy is needed. ## Deploy ```bash # Sync apps to pick up new Application argocd app sync apps # Test on feature branch first argocd app set --revision argocd app sync # Verify kubectl --context=minikube-indri -n get pods kubectl --context=minikube-indri -n logs -f deployment/ # After PR merge, reset to main argocd app set --revision main argocd app sync ``` ## Checklist - [ ] Manifests in `argocd/manifests//` - [ ] Application in `argocd/apps/.yaml` - [ ] Tailscale Ingress via ProxyGroup with Homepage annotations - [ ] Caddy route (if pod-to-service access needed) - [ ] Tested on feature branch - [ ] PR reviewed and merged - [ ] Reset to main branch - [ ] Service added to `service-versions.yaml` for version tracking ## Related - [[adding-a-service]] - Full tutorial with explanations - [[apps]] - ArgoCD application registry - [[routing]] - Service routing options