Repository Structure and Conventions

Relevant source files

This page details the organizational hierarchy and technical standards of the home-ops repository. It covers the directory layout, the GitOps entry points for Flux CD, and the standardized patterns used for deploying applications and cross-cutting infrastructure components.

Top-Level Directory Layout

The repository is organized into distinct functional areas to separate infrastructure provisioning, cluster manifests, and operational tooling.

DirectoryPurpose
kubernetes/Contains all Kubernetes manifests, organized by namespace and application.
infrastructure/Holds IaC (Terraform) and configuration management (Ansible) for the underlying nodes.
.taskfiles/Modular Taskfile definitions for the task runner.
scripts/Utility scripts for maintenance, such as schema migration or secret generation.
docs/Technical documentation and architectural context.

Kubernetes Directory Structure

The kubernetes/ directory is the heart of the GitOps workflow. It follows a strict hierarchy:

  1. kubernetes/apps/: Applications organized by namespace (e.g., media/, network/, storage/).
  2. kubernetes/components/: Reusable Kustomize components for shared logic (e.g., Backups, OIDC).
  3. kubernetes/flux/: Core Flux CD configuration and bootstrap manifests.

Sources:kubernetes/apps/kube-system/kustomization.yaml1-17kubernetes/apps/network/kustomization.yaml1-16


Standard App Deployment Pattern

The repository enforces a “Standard App Pattern” to ensure consistency across dozens of services. This pattern relies on the bjw-s/app-template Helm chart and a specific directory layout.

Capsule: StandardAppPattern

Every standard application MUST use the bjw-s/app-template OCI repository. This encapsulates Deployment, Service, and Ingress/Route resources into a single values object.

Applications are also required to include specific annotations for discovery:

  • Homepage: gethomepage.dev annotations for the dashboard.
  • Gatus: gatus.home-operations.com annotations on Envoy Gateway routes for uptime monitoring.

Sources:docs/ai-context/CONVENTIONS.md14-43

Flux Kustomization Wrappers (ks.yaml)

Apps are not pointed to directly by the root Flux configuration. Instead, they use a ks.yaml wrapper. This file serves as the entry point and allows for dependency management.

[Flowchart Diagram]

Sources:docs/ai-context/CONVENTIONS.md50-68kubernetes/apps/kube-system/kustomization.yaml9-16


Shared Library: Components

The kubernetes/components/ directory contains shared Kustomize logic that is “injected” into applications via their ks.yaml. This avoids manual duplication of complex resources like backup jobs or authentication filters.

Component Injection

Instead of manually defining a ReplicationSource for backups, an app’s ks.yaml includes the volsync component. Configuration is passed via postBuild.substitute variables.

ComponentFunction
commonBasic alerts and standard repository references.
volsyncKopia-based volume backups to S3/NFS.
envoy-oidcNative OIDC authentication via Envoy Gateway.
ext-authGeneric ForwardAuth protection using Authentik.

Sources:kubernetes/components/common/kustomization.yaml1-8docs/ai-context/CONVENTIONS.md126-148


Dependency Management and Reconciliation

To ensure the cluster starts correctly after a cold boot, explicit dependencies are defined using Flux’s dependsOn field.

Dependency Flow

The following diagram illustrates the boot order requirements for a typical application:

[Flowchart Diagram]

Sources:docs/ai-context/CONVENTIONS.md71-96


Technical Conventions

YAML and Metadata

  • Schema Validation: All YAML files should include a # yaml-language-server: $schema=... header to enable IDE validation.
  • Namespace Immutability: Critical namespaces (e.g., flux-system, storage, security) have kustomize.toolkit.fluxcd.io/prune: disabled to prevent accidental deletion of the entire cluster state.

Sources:kubernetes/apps/flux-system/namespace.yaml1-11kubernetes/apps/storage/namespace.yaml1-11

Security and Immutability

  1. Image Pinning: All container images MUST be pinned using their @sha256: digest. Tags are insufficient as they are mutable.
  2. Secret Encryption: All secrets are stored as .sops.yaml files, encrypted with sops using the Age algorithm before being committed to Git.
  3. Makejinja Delimiters: When using Jinja2 templates for infrastructure, the syntax #{var}# is used to avoid conflicts with Helm’s {{var}} syntax.

Sources:docs/ai-context/CONVENTIONS.md153-206

Common Components in Namespaces

Each namespace typically includes a common component that provides standard Alert resources for Flux reconciliation failures, ensuring that any sync error is reported to Alertmanager or GitHub Status.

Sources:kubernetes/components/common/alerts/alertmanager/alert.yaml1-28kubernetes/components/common/alerts/github-status/alert.yaml1-13