## Summary Migrates the docs build pipeline to Dagger (Phase 2 of the Dagger CI adoption plan). - **Backfill `date-modified` frontmatter** on all 80 docs — Dagger's `--src=.` excludes `.git`, so Quartz can't use git history for page dates. Frontmatter dates work with or without git. - **New `docs-check-frontmatter` mise task + pre-commit hook** — validates all docs have `title`, `tags`, and `date-modified` - **New Dagger functions** — `build_changelog` (towncrier in Python container) and `build_docs` (chains changelog → Quartz build in Node container, returns tarball) - **Simplified CI workflow** — the ~44-line inline Quartz build (clone, npm ci, build, tar, cleanup) is replaced by `dagger call build-docs`. Changelog step remains local on the runner since towncrier needs to modify the host working tree for the git commit. ### Design decisions - **Towncrier runs twice in CI**: once inside Dagger (for the docs tarball) and once on the runner (for the git commit). This is intentional — Dagger's directory export is additive and can't delete the consumed changelog fragments from the host. - **Artifact hosting stays on Forgejo Releases** (not migrated to Forgejo Packages as the plan doc originally suggested). That migration can happen independently. - **`date-modified` frontmatter** preserved even though `build_changelog` installs git — the git there is only for towncrier's `git add` call, not for history. The local iteration story (`dagger call build-docs --src=. --version=dev` with uncommitted changes) depends on frontmatter dates. ### Local iteration ```bash dagger call build-docs --src=. --version=dev export --path=./docs-dev.tar.gz tar tf docs-dev.tar.gz | head -20 ``` ## Deployment and Testing - [x] `dagger call build-docs --src=. --version=dev` produces valid 1.1MB tarball (149 HTML pages) - [x] Pre-commit hooks pass (including new `docs-check-frontmatter`) - [ ] Full `workflow_dispatch` run after merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/157
5 KiB
| title | date-modified | tags | |||
|---|---|---|---|---|---|
| ArgoCD Config | 2026-02-07 |
|
Configuring ArgoCD
Audiences: Replicator
This tutorial walks through installing ArgoCD and establishing GitOps-driven deployments for your homelab.
What is GitOps?
GitOps means your git repository is the source of truth for infrastructure:
- Infrastructure state is defined in git
- Changes happen through commits and pull requests
- A controller (ArgoCD) syncs git state to the cluster
- Drift is detected and can be corrected automatically
For BlumeOps specifics, see argocd.
Step 1: Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Wait for pods to be ready:
kubectl -n argocd get pods -w
Step 2: Access the UI
Get the Initial Password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Expose the Service
For Tailscale access:
tailscale serve --bg --https 8443 https+insecure://localhost:$(kubectl -n argocd get svc argocd-server -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
Or create a Tailscale Ingress in Kubernetes (see tailscale-operator).
Access at https://your-server.tailnet.ts.net:8443
Install the CLI
BlumeOps includes argocd in its Brewfile (brew bundle), or install it however you prefer.
Login:
argocd login your-server.tailnet.ts.net:8443
Step 3: Connect Your Git Repository
Create a repository credential:
# For SSH
argocd repo add git@github.com:you/your-repo.git \
--ssh-private-key-path ~/.ssh/id_ed25519
# For HTTPS
argocd repo add https://github.com/you/your-repo.git \
--username you \
--password your-token
Step 4: Create Your First Application
Create a directory in your repo:
your-repo/
└── apps/
└── hello-world/
├── deployment.yaml
└── service.yaml
With a simple deployment:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello
image: nginx:alpine
ports:
- containerPort: 80
Create the ArgoCD Application:
argocd app create hello-world \
--repo git@github.com:you/your-repo.git \
--path apps/hello-world \
--dest-server https://kubernetes.default.svc \
--dest-namespace default
Step 5: Sync and Verify
# See what will be deployed
argocd app diff hello-world
# Deploy it
argocd app sync hello-world
# Check status
argocd app get hello-world
The pods should now be running:
kubectl get pods -l app=hello-world
Step 6: App of Apps Pattern
For managing multiple applications, use the "app of apps" pattern:
your-repo/
├── argocd/
│ ├── apps/ # Application definitions
│ │ ├── hello-world.yaml
│ │ └── another-app.yaml
│ └── manifests/ # Actual Kubernetes manifests
│ ├── hello-world/
│ └── another-app/
Create a root Application that manages other Applications:
# argocd/apps/apps.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: apps
namespace: argocd
spec:
project: default
source:
repoURL: git@github.com:you/your-repo.git
targetRevision: main
path: argocd/apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
Now adding a new application is just creating a YAML file.
Step 7: Configure Sync Policies
| Policy | When to Use |
|---|---|
| Manual sync | Production, explicit control |
| Auto sync | Development, or trusted workloads |
| Auto prune | Remove resources deleted from git |
| Self heal | Revert manual kubectl changes |
BlumeOps uses manual sync for workloads, auto sync only for the apps Application itself.
What You Now Have
- GitOps workflow for deployments
- UI for visualizing application state
- Automatic drift detection
- Declarative application management
Next Steps
- observability-stack - Monitor your deployments
- Add more applications to your repo
- Set up notifications for sync failures
BluemeOps Specifics
BlumeOps' ArgoCD configuration includes:
- SSH connection to forgejo git server
- Manual sync policy for all workloads
- Separate manifests and apps directories
See argocd and apps for full details.
Troubleshooting
| Problem | Solution |
|---|---|
| Sync failed | Check argocd app get <app> for error details |
| Can't connect to repo | Verify credentials, check SSH key permissions |
| Resources not appearing | Ensure path in Application matches repo structure |
| Out of sync but no diff | Check for ignored differences in app config |