Address PR review feedback for Phase 3 tutorials

Tutorial changes:
- Replace what-is-blumeops with adding-a-service tutorial
- Update ai-assistance-guide with Mise Tasks table
- Update contributing with tooling setup, target revisions, DNS preview
- Remove AI-only sections from contributing and exploring-the-docs
- Add replicator explanation to exploring-the-docs
- Add pre-commit link validation note
- Add Core Services phase to replication roadmap
- Add docs service to services list in replicating-blumeops

New reference cards:
- docs.md - Quartz documentation service
- tailscale-operator.md - Kubernetes ingress operator
- ansible/roles.md - Available ansible roles

Other updates:
- Add mise to Brewfile
- Update docs/index.md to link to exploring-the-docs
- Add notes to update exploring-the-docs in future phases
- Link tailscale-operator from apps.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-02-03 18:50:51 -08:00
commit 1e4e72b923
18 changed files with 620 additions and 120 deletions

View file

@ -2,5 +2,6 @@
brew "actionlint" # GitHub/Forgejo Actions workflow linter
brew "argocd" # ArgoCD CLI for GitOps management
brew "bat" # Syntax-highlighted file concatenation
brew "mise" # Task runner and toolchain manager
brew "tea" # Gitea/Forgejo CLI for forge.ops.eblu.me
brew "podman" # Container CLI (uses VM on macOS, for building/pushing images)

View file

@ -83,16 +83,18 @@ Information-oriented technical descriptions. Built first so other docs can link
Learning-oriented content for getting started. Each tutorial explicitly identifies its target audiences.
- [x] Create `tutorials/` directory with index
- [x] "What is BlumeOps?" - High-level orientation (Reader, AI)
- [x] "Exploring the Docs" - How to navigate documentation (All)
- [x] "AI Assistance Guide" - Context for AI-assisted operations (AI, Owner)
- [x] "Contributing" - Your first contribution (Contributor)
- [x] "Adding a Service" - Deploy a new ArgoCD service (Contributor, Replicator)
- [x] "Replicating BlumeOps" - Overview for building similar setup (Replicator)
- [x] Replication sub-tutorials:
- [x] Tailscale Setup
- [x] Core Services (Forgejo, Zot)
- [x] Kubernetes Bootstrap
- [x] ArgoCD Config
- [x] Observability Stack
- [x] New reference cards: docs service, tailscale-operator, ansible/roles
**Tutorials URL:** https://docs.ops.eblu.me/tutorials/
@ -105,6 +107,7 @@ Task-oriented instructions for specific operations.
- [ ] "How to add a new Ansible role"
- [ ] "How to update Tailscale ACLs"
- [ ] "How to troubleshoot common issues"
- [ ] Update `exploring-the-docs` with How-to section
### Phase 5: Explanation
Understanding-oriented discussion of concepts and decisions.
@ -114,11 +117,13 @@ Understanding-oriented discussion of concepts and decisions.
- [ ] "Architecture Overview" - How everything fits together
- [ ] "Security Model" - Tailscale, secrets management, etc.
- [ ] "Decision Log" - ADRs (Architecture Decision Records)
- [ ] Update `exploring-the-docs` with Explanation section
### Phase 6: Integration & Cleanup
- [ ] Migrate remaining useful content from `docs/zk/`
- [ ] Decide fate of zk cards (archive, delete, or keep as separate knowledge base)
- [ ] Update CLAUDE.md to reference new doc structure
- [ ] Final review of `exploring-the-docs` for completeness
- [ ] Mirror docs to GitHub Pages for public access (optional)
## Current Directory Layout

View file

@ -4,8 +4,13 @@ title: blumeops-documentation
Welcome to the BlumeOps documentation.
[[README | Documentation Home]] - Temporary home while docs are being restructured (see [Diataxis](https://diataxis.fr/) restructuring plan)
**New here?** Start with [[exploring-the-docs]] to find your way around.
## Sections
- [[reference/index | reference]] - Technical reference cards for services, infrastructure, and operations
- [[tutorials/index | Tutorials]] - Learning-oriented guides for getting started
- [[reference/index | Reference]] - Technical reference cards for services, infrastructure, and operations
## About
[[README | Documentation Home]] - Restructuring plan and changelog info

View file

@ -0,0 +1,47 @@
---
title: ansible-roles
tags:
- ansible
- reference
---
# Ansible Roles
Roles for provisioning services on [[indri]]. Run via `mise run provision-indri`.
## Available Roles
| Role | Purpose | Service |
|------|---------|---------|
| **alloy** | Observability collector | [[alloy]] |
| **borgmatic** | Backup automation | [[borgmatic]] |
| **borgmatic_metrics** | Backup metrics exporter | [[borgmatic]] |
| **caddy** | Reverse proxy & TLS | [[routing]] |
| **forgejo** | Git forge | [[forgejo]] |
| **jellyfin** | Media server | [[jellyfin]] |
| **jellyfin_metrics** | Media metrics exporter | [[jellyfin]] |
| **minikube** | Kubernetes cluster | [[cluster]] |
| **minikube_metrics** | Cluster metrics | [[cluster]] |
| **zot** | Container registry | [[zot]] |
| **zot_metrics** | Registry metrics | [[zot]] |
## Role Structure
Each role follows Ansible conventions:
```
ansible/roles/<role>/
├── defaults/main.yml # Default variables
├── tasks/main.yml # Task definitions
├── handlers/main.yml # Handlers (restarts, etc.)
├── templates/ # Jinja2 templates
└── files/ # Static files
```
## Secrets
Roles that need secrets use 1Password via the playbook's `pre_tasks`. Secrets are gathered at playbook start and passed to roles as variables.
## Related
- [[indri]] - Target host
- [[observability]] - Metrics collection

View file

@ -31,6 +31,7 @@ Individual service reference cards with URLs and configuration details.
| [[teslamate]] | Tesla data logger | k8s |
| [[transmission]] | BitTorrent daemon | k8s |
| [[zot]] | Container registry | indri |
| [[docs]] | Documentation site (Quartz) | k8s |
## Infrastructure
@ -48,8 +49,15 @@ Cluster configuration and application registry.
- [[cluster | Cluster]] - Minikube specs, storage, networking
- [[apps | Apps]] - ArgoCD application registry
- [[tailscale-operator]] - Tailscale ingress for k8s services
- [[external-secrets]] - Secrets management
## Ansible
Configuration management for [[indri]]-hosted services.
- [[reference/ansible/roles | Roles]] - Available ansible roles
## Storage
Network storage and backup configuration.

View file

@ -15,7 +15,7 @@ Registry of all applications deployed via [[argocd]].
|-----|-----------|-------------|---------|
| `apps` | argocd | `argocd/apps/` | App-of-apps root |
| `argocd` | argocd | `argocd/manifests/argocd/` | [[argocd]] |
| `tailscale-operator` | tailscale | `argocd/manifests/tailscale-operator/` | Tailscale k8s operator |
| `tailscale-operator` | tailscale | `argocd/manifests/tailscale-operator/` | [[tailscale-operator]] |
| `1password-connect` | 1password | `argocd/manifests/1password-connect/` | [[1password]] |
| `external-secrets` | external-secrets | Helm chart | [[1password]] |
| `external-secrets-config` | external-secrets | `argocd/manifests/external-secrets-config/` | [[1password]] |

View file

@ -0,0 +1,40 @@
---
title: tailscale-operator
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` |
| **Helm Chart** | `tailscale/tailscale-operator` |
| **ArgoCD App** | `tailscale-operator` |
## How It Works
When you create an Ingress with `ingressClassName: tailscale`:
1. Operator provisions a Tailscale node for the service
2. Service becomes accessible at `<hostname>.tail8d86e.ts.net`
3. TLS is handled automatically via Tailscale
## 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

View file

@ -0,0 +1,49 @@
---
title: docs
tags:
- service
- documentation
---
# Docs (Quartz)
Documentation site built with [Quartz](https://quartz.jzhao.xyz/) and served via nginx.
## Quick Reference
| Property | Value |
|----------|-------|
| **URL** | https://docs.ops.eblu.me |
| **Namespace** | `docs` |
| **Container** | `registry.ops.eblu.me/blumeops/quartz:v1.0.0` |
| **Source** | `docs/` directory in blumeops repo |
| **Build** | Forgejo workflow `build-blumeops.yaml` |
## Architecture
1. **Source**: Markdown files in `docs/` with Obsidian-compatible wiki-links
2. **Build**: Forgejo workflow builds Quartz static site on push to main
3. **Release**: Built assets published as Forgejo release attachments
4. **Deploy**: Container downloads release bundle on startup, serves via nginx
## Release Process
Documentation is automatically built and released when changes are pushed to main:
1. Workflow detects changes in `docs/` directory
2. Quartz builds static HTML/CSS/JS
3. Assets uploaded as release attachment
4. ArgoCD deployment updated with new `DOCS_RELEASE_URL`
5. Pod restarts and downloads new bundle
## Configuration
- **Quartz config**: `quartz.config.ts`
- **Layout**: `quartz.layout.ts`
- **ArgoCD app**: `argocd/apps/docs.yaml`
- **Manifests**: `argocd/manifests/docs/`
## Related
- [[argocd]] - Deployment management
- [[forgejo]] - Build workflows

View file

@ -0,0 +1,255 @@
---
title: adding-a-service
tags:
- tutorials
- argocd
- kubernetes
---
# Adding an ArgoCD-Managed Service
> **Audiences:** Contributor, Replicator
This tutorial walks through deploying a new service to BlumeOps via ArgoCD, including ingress configuration, homepage integration, and observability setup.
## Prerequisites
- Access to the [[tailscale | Tailscale]] network
- `kubectl` configured with `minikube-indri` context
- `argocd` CLI installed (via Brewfile: `brew bundle`)
## Overview
Adding a service involves:
1. Creating Kubernetes manifests
2. Creating an ArgoCD Application
3. Configuring Tailscale ingress
4. Adding Homepage dashboard entry
5. Setting up Grafana dashboards (optional)
## Step 1: Create Manifests Directory
Create a directory for your service's Kubernetes manifests:
```
argocd/manifests/<service-name>/
├── deployment.yaml
├── service.yaml
├── ingress-tailscale.yaml
└── configmap.yaml # if needed
```
### Example Deployment
```yaml
# argocd/manifests/myservice/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myservice
namespace: myservice
spec:
replicas: 1
selector:
matchLabels:
app: myservice
template:
metadata:
labels:
app: myservice
spec:
containers:
- name: myservice
image: registry.ops.eblu.me/myservice:v1.0.0
ports:
- containerPort: 8080
```
### Example Service
```yaml
# argocd/manifests/myservice/service.yaml
apiVersion: v1
kind: Service
metadata:
name: myservice
namespace: myservice
spec:
selector:
app: myservice
ports:
- port: 80
targetPort: 8080
```
## Step 2: Configure Tailscale Ingress
Create an Ingress to expose the service via Tailscale. See [[tailscale-operator]] for details.
```yaml
# argocd/manifests/myservice/ingress-tailscale.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myservice
namespace: myservice
spec:
ingressClassName: tailscale
rules:
- host: myservice
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myservice
port:
number: 80
```
This exposes the service at `https://myservice.tail8d86e.ts.net`.
## Step 3: Add Homepage Annotations
Add annotations to the Ingress for automatic Homepage dashboard discovery:
```yaml
metadata:
annotations:
gethomepage.dev/enabled: "true"
gethomepage.dev/name: "My Service"
gethomepage.dev/group: "Apps"
gethomepage.dev/icon: "myservice.png"
gethomepage.dev/description: "Short description"
gethomepage.dev/href: "https://myservice.ops.eblu.me"
gethomepage.dev/pod-selector: "app=myservice"
```
Icons use [Dashboard Icons](https://github.com/walkxcode/dashboard-icons) format.
## Step 4: Create ArgoCD Application
Create an Application manifest to tell ArgoCD about your service:
```yaml
# argocd/apps/myservice.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myservice
namespace: argocd
spec:
project: default
source:
repoURL: ssh://forgejo@indri.tail8d86e.ts.net:2200/eblume/blumeops.git
targetRevision: main
path: argocd/manifests/myservice
destination:
server: https://kubernetes.default.svc
namespace: myservice
syncPolicy:
syncOptions:
- CreateNamespace=true
```
## Step 5: Add Caddy Route (Optional)
If the service needs to be accessible from other pods or containers, add a Caddy route in `ansible/roles/caddy/defaults/main.yml`:
```yaml
caddy_services:
# ... existing services ...
- name: myservice
upstream: "https://myservice.tail8d86e.ts.net"
```
Then run `mise run provision-indri -- --tags caddy` to apply.
This enables access via `https://myservice.ops.eblu.me`. See [[routing]] for details on when this is needed.
## Step 6: Deploy
### Testing on a Feature Branch
For new services, point ArgoCD at your feature branch first:
```bash
# Sync the apps application to pick up your new Application
argocd app sync apps
# Point your app at the feature branch
argocd app set myservice --revision feature/your-branch
argocd app sync myservice
```
### Verify Deployment
```bash
kubectl --context=minikube-indri -n myservice get pods
kubectl --context=minikube-indri -n myservice logs -f deployment/myservice
```
### After PR Merge
Reset to main branch:
```bash
argocd app set myservice --revision main
argocd app sync myservice
```
## Step 7: Add Observability (Optional)
### Prometheus Metrics
If your service exposes Prometheus metrics, add scrape annotations:
```yaml
# In deployment.yaml pod template
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
```
### Grafana Dashboard
Create a ConfigMap in `argocd/manifests/grafana-config/dashboards/`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myservice-dashboard
namespace: monitoring
labels:
grafana_dashboard: "1"
annotations:
grafana_folder: "Services"
data:
myservice.json: |
{ ... dashboard JSON ... }
```
See [[grafana]] for dashboard provisioning details.
## Checklist
- [ ] Manifests created in `argocd/manifests/<service>/`
- [ ] ArgoCD Application created in `argocd/apps/`
- [ ] Tailscale Ingress configured
- [ ] Homepage annotations added
- [ ] Caddy route added (if needed for pod access)
- [ ] Feature branch tested via ArgoCD
- [ ] Metrics/dashboard configured (if applicable)
- [ ] PR created and reviewed
- [ ] Reset to main after merge
## Related
- [[argocd]] - GitOps platform
- [[tailscale-operator]] - Kubernetes ingress
- [[routing]] - Service routing options
- [[grafana]] - Dashboard configuration
- [[apps]] - Application registry

View file

@ -68,26 +68,31 @@ Understanding where services run helps target changes correctly:
| [[indri]] (native) | Forgejo, Zot, Jellyfin, Caddy | Ansible |
| [[cluster | Kubernetes]] | Everything else | ArgoCD |
## Common Operations
## Mise Tasks
### Kubernetes Service Changes
BlumeOps operations are driven by mise tasks. Run `mise tasks` to list all available tasks.
1. Modify manifests in `argocd/manifests/<service>/`
2. Preview with `argocd app diff <service>`
3. Deploy with `argocd app sync <service>`
| Task | When to Use |
|------|-------------|
| `zk-docs` | At session start - review infrastructure documentation |
| `provision-indri` | Deploy changes to [[indri]]-hosted services via Ansible |
| `indri-services-check` | After deployments - verify all services are healthy |
| `pr-comments` | Check unresolved PR comments during review |
| `blumeops-tasks` | Find pending tasks from Todoist |
| `container-list` | View available container images and tags |
| `container-tag-and-release` | Release a new container image version |
| `dns-preview` | Preview DNS changes before applying |
| `dns-up` | Apply DNS changes via Pulumi |
| `tailnet-preview` | Preview Tailscale ACL changes |
| `tailnet-up` | Apply Tailscale ACL changes via Pulumi |
| `doc-links` | Validate wiki-links in documentation |
| `doc-titles` | Check for duplicate doc titles |
| `doc-filenames` | Check for duplicate doc filenames |
| `indri-runner-logs` | View Forgejo workflow logs from local runner |
### Indri Service Changes
1. Modify ansible role in `ansible/roles/<service>/`
2. Dry run: `mise run provision-indri -- --check --diff --tags <service>`
3. Deploy: `mise run provision-indri -- --tags <service>`
### Health Checks
After changes:
```bash
mise run indri-services-check
```
For ArgoCD operations, use the `argocd` CLI directly:
- `argocd app diff <service>` - Preview changes
- `argocd app sync <service>` - Deploy changes
## Reference Navigation

View file

@ -16,7 +16,40 @@ This tutorial walks through making your first contribution to BluemeOps - from u
Before contributing, you'll need:
- Access to the [[tailscale|Tailscale]] network (request from Erich)
- SSH key added to [[forgejo|Forgejo]] (https://forge.ops.eblu.me)
- `tea` CLI installed for PR creation
- Development tools installed (see below)
## Tooling Setup
The repo includes a `Brewfile` and `mise.toml` for easy setup, but these are optional - install the tools however you prefer.
### Required Tools
- `tea` - Gitea/Forgejo CLI for creating PRs
- `argocd` - ArgoCD CLI for deployments
- `pre-commit` - Git hooks for validation
### Using Brewfile (Optional)
```bash
brew bundle # installs tea, argocd, mise, etc.
```
### Using Mise (Optional)
Mise manages language toolchains and runs tasks:
```bash
mise install # installs Python, Node.js, etc. from mise.toml
```
### Pre-commit Hooks
Pre-commit hooks validate changes on `git commit`:
```bash
pre-commit install
pre-commit run --all-files # verify setup
```
All hooks should pass on a fresh clone.
## Understanding the Codebase
@ -47,6 +80,8 @@ Depending on what you're changing:
**For Kubernetes services:**
- Edit manifests in `argocd/manifests/<service>/`
- Or create new Application in `argocd/apps/`
- For new apps, set `targetRevision` to your feature branch for testing
- For existing apps, you'll need to temporarily change the revision via `argocd app set`
**For Indri services:**
- Edit or create roles in `ansible/roles/`
@ -80,10 +115,9 @@ For Kubernetes changes:
argocd app diff <service>
```
For Ansible changes:
For DNS changes:
```bash
# Dry run
mise run provision-indri -- --check --diff --tags <role>
mise run dns-preview
```
### 5. Commit and Push
@ -137,13 +171,7 @@ annotations:
```
3. Create PR and wait for sync
## Getting Help
- Browse [[reference/index|Reference]] for technical details
- Check `CLAUDE.md` in the repo for rules and conventions
- Ask Erich directly (he's friendly)
## Related
- [[ai-assistance-guide]] - If using AI assistance for contributions
- [[adding-a-service]] - Full tutorial on deploying a new service
- [[replicating-blumeops]] - If you want to build your own instead

View file

@ -41,20 +41,20 @@ Context for effective assistance:
### For External Readers
Understanding what this is:
- [[what-is-blumeops]] gives the high-level overview
- [[reference/index|Reference]] shows what's actually running
- Browse service pages to see specific implementations
- The repo's README has project context
### For Contributors
Getting started with changes:
- [[contributing]] walks through the workflow
- [[reference/index|Reference]] tells you where things live
- The `CLAUDE.md` in the repo root has contribution rules
### For Replicators
Building your own:
Replicators are people who want to build their own similar homelab GitOps setup, using BlumeOps as inspiration.
- [[replicating-blumeops]] provides the overview
- The `replication/` tutorials go deep on components
- Reference pages show specific configuration choices
@ -64,10 +64,12 @@ Building your own:
Documentation uses `[[wiki-links]]` for cross-references:
- `[[service-name]]` links to a reference page
- `[[folder/page]]` links to nested pages
- `[[page|Display Text]]` customizes the link text
- `[[page | Display Text]]` customizes the link text
When reading on the web (docs.ops.eblu.me), these render as clickable links. The backlinks panel shows what references each page.
Pre-commit hooks automatically validate that all wiki-links point to existing files and that link targets are unambiguous.
## Legacy Content
The `docs/zk/` directory contains zettelkasten cards from before the restructuring. These are read-only reference - new content goes in the structured sections. The cards will eventually be migrated or archived.

View file

@ -24,7 +24,6 @@ Each tutorial indicates which audiences it serves:
| Tutorial | Audiences | Description |
|----------|-----------|-------------|
| [[what-is-blumeops]] | Reader, AI | High-level orientation to the project |
| [[exploring-the-docs]] | All | How to navigate and use this documentation |
| [[ai-assistance-guide]] | AI, Owner | Context for effective AI-assisted operations |
@ -33,6 +32,7 @@ Each tutorial indicates which audiences it serves:
| Tutorial | Audiences | Description |
|----------|-----------|-------------|
| [[contributing]] | Contributor | Your first contribution to BlumeOps |
| [[adding-a-service]] | Contributor, Replicator | Deploy a new service via ArgoCD |
## Replication
@ -42,6 +42,7 @@ For those building their own homelab GitOps setup.
|----------|-----------|-------------|
| [[replicating-blumeops]] | Replicator | Overview: building a similar environment |
| [[tutorials/replication/tailscale-setup | Tailscale Setup]] | Replicator | Setting up Tailscale networking |
| [[tutorials/replication/core-services | Core Services]] | Replicator | Forgejo and container registry |
| [[tutorials/replication/kubernetes-bootstrap | Kubernetes Bootstrap]] | Replicator | Bootstrapping a Kubernetes cluster |
| [[tutorials/replication/argocd-config | ArgoCD Config]] | Replicator | Configuring GitOps with ArgoCD |
| [[tutorials/replication/observability-stack | Observability Stack]] | Replicator | Metrics, logs, and dashboards |

View file

@ -26,7 +26,7 @@ BluemeOps runs on modest hardware. At minimum:
| Component | BlumeOps Uses | Minimum Alternative |
|-----------|---------------|---------------------|
| **Server** | Mac Mini M1 | Any machine with 16GB RAM |
| **Server** | Mac Mini M1 | Any machine with sufficient RAM (16GB recommended) |
| **NAS** | Synology DS920+ | USB drive or second machine |
| **Workstation** | MacBook Air M4 | Whatever you use daily |
@ -45,7 +45,18 @@ Before deploying services, establish secure connectivity.
This replaces: traditional VPNs, port forwarding, dynamic DNS
### Phase 2: Kubernetes Cluster
### Phase 2: Core Services
Bootstrap the essential services that everything else depends on.
**[[tutorials/replication/core-services | Core Services Setup]]**
- Set up [[forgejo]] for git hosting and CI/CD
- Optionally set up [[zot]] container registry
- Configure SSH access and deploy keys
Forgejo is central to GitOps - it's where your infrastructure definitions live and where CI/CD workflows run.
### Phase 3: Kubernetes Cluster
A cluster for running containerized workloads.
@ -56,7 +67,7 @@ A cluster for running containerized workloads.
BlumeOps uses minikube for simplicity, but the patterns apply to any distribution.
### Phase 3: GitOps with ArgoCD
### Phase 4: GitOps with ArgoCD
Declarative, git-driven deployments.
@ -68,7 +79,7 @@ Declarative, git-driven deployments.
This is the heart of GitOps - changes in git automatically sync to your cluster.
### Phase 4: Observability Stack
### Phase 5: Observability Stack
Know what's happening in your infrastructure.
@ -80,13 +91,14 @@ Know what's happening in your infrastructure.
Without observability, you're flying blind.
### Phase 5: Your First Services
### Phase 6: Your First Services
With the foundation in place, deploy actual workloads. BluemeOps runs:
- [[miniflux]] - RSS reader
- [[jellyfin]] - Media server
- [[immich]] - Photo management
- [[navidrome]] - Music streaming
- [[docs]] - Documentation site (Quartz)
Pick what matters to you. Each service follows similar patterns:
1. Create Kubernetes manifests
@ -94,7 +106,7 @@ Pick what matters to you. Each service follows similar patterns:
3. Configure ingress routing
4. Sync and verify
### Phase 6: Backups and Resilience
### Phase 7: Backups and Resilience
Protect your data.
@ -123,6 +135,5 @@ Begin with [[tutorials/replication/tailscale-setup]] - networking is the foundat
## Related
- [[what-is-blumeops]] - Understand what you're replicating
- [[reference/index]] - See BlumeOps' specific configurations
- [[contributing]] - Help improve BlumeOps instead

View file

@ -49,16 +49,13 @@ 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.
Or create a Tailscale Ingress in Kubernetes (see [[tailscale-operator]]).
Access at `https://your-server.tailnet.ts.net:8443`
### Install the CLI
```bash
brew install argocd # macOS
# or download from GitHub releases
```
BlumeOps includes `argocd` in its Brewfile (`brew bundle`), or install it however you prefer.
Login:
```bash

View file

@ -0,0 +1,113 @@
---
title: core-services
tags:
- tutorials
- replication
- forgejo
---
# Core Services Setup
> **Audiences:** Replicator
This tutorial walks through setting up the foundational services that your GitOps infrastructure depends on: a git forge and optionally a container registry.
## Why Core Services First?
Before Kubernetes and ArgoCD, you need somewhere to store your infrastructure definitions. [[forgejo]] provides:
- Git hosting for your GitOps repository
- CI/CD workflows for building and deploying
- A web interface for code review and PRs
The [[zot]] container registry is optional but useful for hosting your own container images.
## Step 1: Install Forgejo
Forgejo runs directly on your server (not in Kubernetes) because Kubernetes depends on it.
### Using Ansible (BlumeOps Approach)
BlumeOps manages Forgejo via an Ansible role. See [[reference/ansible/roles | Ansible Roles]].
### Manual Installation
1. Download Forgejo from [forgejo.org](https://forgejo.org/download/)
2. Create a service user and directories
3. Configure with `app.ini`
4. Set up as a system service
Key configuration points:
- SSH on a non-standard port (e.g., 2222) to avoid conflicts
- Database (SQLite works fine for personal use)
- Domain and URL settings for your Tailscale hostname
## Step 2: Configure SSH Access
Set up SSH for git operations:
```bash
# Add your SSH key to Forgejo via the web UI
# Then test access:
ssh -T git@your-server.tailnet.ts.net -p 2222
```
## Step 3: Create Your GitOps Repository
1. Create a new repository in Forgejo (e.g., `infrastructure` or `homelab`)
2. Initialize the standard directory structure:
```
your-repo/
├── ansible/ # Host configuration
│ ├── playbooks/
│ └── roles/
├── argocd/ # Kubernetes GitOps
│ ├── apps/ # ArgoCD Applications
│ └── manifests/ # K8s manifests per service
├── pulumi/ # IaC for Tailscale, DNS
└── docs/ # Documentation
```
3. Push your initial commit
## Step 4: Set Up CI/CD Runner (Optional)
Forgejo Actions runs workflows defined in `.forgejo/workflows/`. To use it:
1. Register a runner on your server
2. Configure runner to access your build tools
3. Create workflow files for builds and deployments
BlumeOps runs a Forgejo runner in Kubernetes - see [[forgejo]] for details.
## Step 5: Container Registry (Optional)
If you'll build custom container images, set up [[zot]]:
1. Install Zot on your server
2. Configure authentication
3. Set up TLS (via Caddy or similar)
For getting started, you can skip this and use public registries.
## What You Now Have
- Git hosting for infrastructure code
- SSH access for git operations
- Foundation for CI/CD workflows
- Optionally, a private container registry
## Next Steps
- [[tutorials/replication/kubernetes-bootstrap | Bootstrap Kubernetes]] - Now that you have a git repo, set up your cluster
- Configure Forgejo webhooks for ArgoCD (after ArgoCD is running)
## BlumeOps Specifics
BlumeOps' Forgejo setup includes:
- Ansible role for installation and updates
- SSH on port 2222, proxied via Caddy
- Integration with ArgoCD via deploy keys
- Forgejo runner in Kubernetes for CI/CD
See [[forgejo]] and [[zot]] for full details.

View file

@ -177,7 +177,7 @@ spec:
namespace: monitoring
```
BluemeOps uses Alloy on both [[indri]] (for host metrics) and in the [[cluster]] (for pod logs and service probes).
BluemeOps uses Alloy on both [[indri]] (for host metrics, via [[reference/ansible/roles | Ansible role]]) and in the [[cluster]] (for pod logs and service probes).
## What You Now Have

View file

@ -1,67 +0,0 @@
---
title: what-is-blumeops
tags:
- tutorials
- getting-started
---
# What is BlumeOps?
> **Audiences:** Reader, AI
BlumeOps is Erich Blume's personal infrastructure GitOps repository - a system for managing homelab services and infrastructure through version-controlled configuration.
## The Short Version
BlumeOps runs a collection of self-hosted services (media streaming, git hosting, photo management, RSS feeds, etc.) on home hardware, managed through code rather than manual configuration. Everything is tracked in a git repository, meaning changes are reviewable, reversible, and reproducible.
## Why Does This Exist?
Three motivations:
1. **Learning** - A playground for exploring DevOps, Kubernetes, and infrastructure automation
2. **Privacy** - Self-hosting services keeps data under personal control
3. **Resilience** - Less dependence on cloud providers and their service changes
## What's Running?
BlumeOps consists of:
- **A Mac Mini server** ([[indri]]) running Kubernetes and native services
- **A NAS** ([[sifaka]]) for storage and backups
- **~16 services** ranging from [[jellyfin|media streaming]] to [[grafana|observability dashboards]]
- **A Tailscale network** connecting everything securely
See [[reference/index|Reference]] for the complete service inventory.
## How Is It Organized?
```
blumeops/
├── ansible/ # Configuration for services on indri
├── argocd/ # Kubernetes manifests and ArgoCD apps
├── pulumi/ # Tailscale ACLs and DNS
└── docs/ # This documentation
```
Changes follow a GitOps workflow:
1. Modify configuration in a feature branch
2. Create a pull request for review
3. Deploy via ArgoCD (Kubernetes) or Ansible (indri)
4. Merge to main after verification
## Key Concepts
| Concept | What It Means in BlumeOps |
|---------|---------------------------|
| **GitOps** | All infrastructure defined in git; deploys happen by syncing git state |
| **IaC** | Infrastructure as Code - servers, networks, services defined in files |
| **Homelab** | Personal server infrastructure at home, not in a datacenter |
| **Tailscale** | VPN mesh network connecting all devices securely |
## Where to Go Next
- **Want to understand the architecture?** See [[reference/index|Reference]]
- **Want to help with BlumeOps?** See [[contributing]]
- **Want to build something similar?** See [[replicating-blumeops]]
- **Working with AI assistance?** See [[ai-assistance-guide]]