From 1c86134a62e330c875083c4e3fd9d40ebd5382e2 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Tue, 3 Feb 2026 10:52:20 -0800 Subject: [PATCH] Phase 1b: Deploy docs hosting with Quartz (#85) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Add ArgoCD Application and manifests for `quartz` service - Add `docs.ops.eblu.me` to Caddy reverse proxy configuration - ConfigMap points to blumeops v1.0.0 release tarball - Tailscale ingress with homepage annotations for auto-discovery ## Deployment and Testing **Pre-deployment (container build):** - [ ] Build and tag quartz container: `mise run container-tag-and-release quartz v1.0.0` **K8s deployment:** - [ ] Sync apps: `argocd app sync apps` - [ ] Point quartz at feature branch: `argocd app set quartz --revision feature/docs-phase-1b-hosting` - [ ] Sync quartz: `argocd app sync quartz` - [ ] Verify pod is running: `kubectl --context=minikube-indri get pods -n quartz` - [ ] Verify Tailscale ingress: `kubectl --context=minikube-indri get ingress -n quartz` **Caddy deployment:** - [ ] Dry run: `mise run provision-indri -- --tags caddy --check --diff` - [ ] Apply: `mise run provision-indri -- --tags caddy` **Verification:** - [ ] Test https://docs.tail8d86e.ts.net - [ ] Test https://docs.ops.eblu.me - [ ] Verify homepage dashboard shows docs link **Post-merge:** - [ ] Reset to main: `argocd app set quartz --revision main && argocd app sync quartz` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/85 --- ansible/roles/caddy/defaults/main.yml | 3 ++ argocd/apps/docs.yaml | 18 ++++++++ argocd/manifests/docs/configmap.yaml | 10 +++++ argocd/manifests/docs/deployment.yaml | 43 ++++++++++++++++++++ argocd/manifests/docs/ingress-tailscale.yaml | 25 ++++++++++++ argocd/manifests/docs/kustomization.yaml | 9 ++++ argocd/manifests/docs/service.yaml | 13 ++++++ containers/quartz/Dockerfile | 35 +--------------- containers/quartz/default.conf | 28 +++++++++++++ docs/README.md | 1 + 10 files changed, 152 insertions(+), 33 deletions(-) create mode 100644 argocd/apps/docs.yaml create mode 100644 argocd/manifests/docs/configmap.yaml create mode 100644 argocd/manifests/docs/deployment.yaml create mode 100644 argocd/manifests/docs/ingress-tailscale.yaml create mode 100644 argocd/manifests/docs/kustomization.yaml create mode 100644 argocd/manifests/docs/service.yaml create mode 100644 containers/quartz/default.conf diff --git a/ansible/roles/caddy/defaults/main.yml b/ansible/roles/caddy/defaults/main.yml index 2aefc3d..c35ef76 100644 --- a/ansible/roles/caddy/defaults/main.yml +++ b/ansible/roles/caddy/defaults/main.yml @@ -70,6 +70,9 @@ caddy_services: - name: hajimari host: "go.{{ caddy_domain }}" backend: "https://go.tail8d86e.ts.net" + - name: docs + host: "docs.{{ caddy_domain }}" + backend: "https://docs.tail8d86e.ts.net" - name: sifaka host: "nas.{{ caddy_domain }}" backend: "http://sifaka:5000" diff --git a/argocd/apps/docs.yaml b/argocd/apps/docs.yaml new file mode 100644 index 0000000..cd8db35 --- /dev/null +++ b/argocd/apps/docs.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: docs + namespace: argocd +spec: + project: default + source: + repoURL: ssh://forgejo@forge.ops.eblu.me:2222/eblume/blumeops.git + targetRevision: main + path: argocd/manifests/docs + destination: + server: https://kubernetes.default.svc + namespace: docs + syncPolicy: + syncOptions: + - CreateNamespace=true diff --git a/argocd/manifests/docs/configmap.yaml b/argocd/manifests/docs/configmap.yaml new file mode 100644 index 0000000..7970f3c --- /dev/null +++ b/argocd/manifests/docs/configmap.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: docs-config + namespace: docs +data: + # BlumeOps docs release URL + # Update this to deploy a new docs version + DOCS_RELEASE_URL: "https://forge.ops.eblu.me/eblume/blumeops/releases/download/v1.0.0/docs-v1.0.0.tar.gz" diff --git a/argocd/manifests/docs/deployment.yaml b/argocd/manifests/docs/deployment.yaml new file mode 100644 index 0000000..01e4e9b --- /dev/null +++ b/argocd/manifests/docs/deployment.yaml @@ -0,0 +1,43 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: docs + namespace: docs +spec: + replicas: 1 + selector: + matchLabels: + app: docs + template: + metadata: + labels: + app: docs + spec: + containers: + - name: docs + image: registry.ops.eblu.me/blumeops/quartz:v1.0.0 + ports: + - containerPort: 80 + name: http + envFrom: + - configMapRef: + name: docs-config + resources: + requests: + memory: "64Mi" + cpu: "10m" + limits: + memory: "128Mi" + livenessProbe: + httpGet: + path: /healthz + port: 80 + initialDelaySeconds: 10 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /healthz + port: 80 + initialDelaySeconds: 5 + periodSeconds: 10 diff --git a/argocd/manifests/docs/ingress-tailscale.yaml b/argocd/manifests/docs/ingress-tailscale.yaml new file mode 100644 index 0000000..4c6710f --- /dev/null +++ b/argocd/manifests/docs/ingress-tailscale.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: docs-tailscale + namespace: docs + annotations: + tailscale.com/proxy-class: "default" + gethomepage.dev/enabled: "true" + gethomepage.dev/name: "Docs" + gethomepage.dev/group: "Apps" + gethomepage.dev/icon: "mdi-book-open-page-variant" + gethomepage.dev/description: "BlumeOps Documentation" + gethomepage.dev/href: "https://docs.ops.eblu.me" + gethomepage.dev/pod-selector: "app=docs" +spec: + ingressClassName: tailscale + defaultBackend: + service: + name: docs + port: + number: 80 + tls: + - hosts: + - docs diff --git a/argocd/manifests/docs/kustomization.yaml b/argocd/manifests/docs/kustomization.yaml new file mode 100644 index 0000000..9d55928 --- /dev/null +++ b/argocd/manifests/docs/kustomization.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: docs +resources: + - configmap.yaml + - deployment.yaml + - service.yaml + - ingress-tailscale.yaml diff --git a/argocd/manifests/docs/service.yaml b/argocd/manifests/docs/service.yaml new file mode 100644 index 0000000..62b0f83 --- /dev/null +++ b/argocd/manifests/docs/service.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: docs + namespace: docs +spec: + selector: + app: docs + ports: + - name: http + port: 80 + targetPort: 80 diff --git a/containers/quartz/Dockerfile b/containers/quartz/Dockerfile index 5701990..63e5757 100644 --- a/containers/quartz/Dockerfile +++ b/containers/quartz/Dockerfile @@ -11,42 +11,11 @@ FROM nginx:alpine # Install curl for downloading release assets RUN apk add --no-cache curl -# Copy startup script +# Copy startup script and nginx config COPY start.sh /start.sh +COPY default.conf /etc/nginx/conf.d/default.conf RUN chmod +x /start.sh -# Custom nginx config for SPA routing -RUN cat > /etc/nginx/conf.d/default.conf << 'EOF' -server { - listen 80; - server_name _; - root /usr/share/nginx/html; - index index.html; - - # Enable gzip compression - gzip on; - gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript; - - # Cache static assets - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - } - - # SPA fallback - serve index.html for client-side routing - location / { - try_files $uri $uri/ $uri.html /index.html; - } - - # Health check endpoint - location /healthz { - access_log off; - return 200 "ok\n"; - add_header Content-Type text/plain; - } -} -EOF - EXPOSE 80 CMD ["/start.sh"] diff --git a/containers/quartz/default.conf b/containers/quartz/default.conf new file mode 100644 index 0000000..4009101 --- /dev/null +++ b/containers/quartz/default.conf @@ -0,0 +1,28 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Enable gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript; + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # SPA fallback - serve index.html for client-side routing + location / { + try_files $uri $uri/ $uri.html /index.html; + } + + # Health check endpoint + location /healthz { + access_log off; + return 200 "ok\n"; + add_header Content-Type text/plain; + } +} diff --git a/docs/README.md b/docs/README.md index 1ba602f..b694cb9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,6 +63,7 @@ The documentation is being restructured to follow the [Diataxis](https://diataxi ``` - [ ] Test end-to-end: commit -> build -> release -> deploy - [ ] Set up `CHANGELOG.md` with [towncrier](https://towncrier.readthedocs.io/) using news fragments from zk cards +- [ ] Add `docs.ops.eblu.me` link to homepage dashboard ### Phase 2: Tutorials Learning-oriented content for getting started.