blumeops/docs/how-to/deploy-k8s-service.md
Erich Blume dc46eb7def Update all docs titles to human-readable (#117)
## Summary
- Updated frontmatter `title:` in all 63 doc cards from slug-case to human-readable (e.g. `borgmatic` → `Borgmatic`, `ai-assistance-guide` → `AI Assistance Guide`)
- Titles now closely match file stems so `[[wiki-links]]` render naturally without alternate anchor text
- Corrected titles that diverged from stems (e.g. `host-inventory` → `Hosts`, `grafana-alloy` → `Alloy`, `argocd-applications` → `Apps`)
- Deleted `title-test-alpha.md` and `title-test-beta.md` test cards and removed their reference index entry

## Deployment and Testing
- [x] `docs-check-links` passes — all wiki-links valid
- [x] `docs-check-index` passes
- [x] `docs-check-filenames` passes
- [ ] Verify titles render correctly on docs site after deploy

Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/117
2026-02-07 21:44:57 -08:00

2.8 KiB

title tags
Deploy K8s Service
how-to
kubernetes
argocd

Deploy a Kubernetes Service

Quick reference for deploying a new service to BlumeOps Kubernetes via ArgoCD. See adding-a-service for detailed explanations.

Create Manifests

argocd/manifests/<service>/
├── deployment.yaml
├── service.yaml
└── ingress-tailscale.yaml

Namespace should match service name. Use registry.ops.eblu.me for images.

Create ArgoCD Application

# argocd/apps/<service>.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: <service>
  namespace: argocd
spec:
  project: default
  source:
    repoURL: ssh://forgejo@indri.tail8d86e.ts.net:2200/eblume/blumeops.git
    targetRevision: main
    path: argocd/manifests/<service>
  destination:
    server: https://kubernetes.default.svc
    namespace: <service>
  syncPolicy:
    syncOptions:
    - CreateNamespace=true

Configure Ingress

Add tailscale-operator with Homepage annotations:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: <service>
  namespace: <service>
  annotations:
    gethomepage.dev/enabled: "true"
    gethomepage.dev/name: "Service Name"
    gethomepage.dev/group: "Apps"
    gethomepage.dev/icon: "<service>.png"
    gethomepage.dev/href: "https://<service>.ops.eblu.me"
    gethomepage.dev/pod-selector: "app=<service>"
spec:
  ingressClassName: tailscale
  rules:
  - host: <service>
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: <service>
            port:
              number: 80

Add Caddy Route (if needed)

If other pods need to access the service, add to ansible/roles/caddy/defaults/main.yml:

caddy_services:
  - name: <service>
    upstream: "https://<service>.tail8d86e.ts.net"

Then: mise run provision-indri -- --tags caddy

See routing for when Caddy is needed.

Deploy

# Sync apps to pick up new Application
argocd app sync apps

# Test on feature branch first
argocd app set <service> --revision <branch>
argocd app sync <service>

# Verify
kubectl --context=minikube-indri -n <service> get pods
kubectl --context=minikube-indri -n <service> logs -f deployment/<service>

# After PR merge, reset to main
argocd app set <service> --revision main
argocd app sync <service>

Checklist

  • Manifests in argocd/manifests/<service>/
  • Application in argocd/apps/<service>.yaml
  • Tailscale Ingress with Homepage annotations
  • Caddy route (if pod-to-service access needed)
  • Tested on feature branch
  • PR reviewed and merged
  • Reset to main branch