Skip to content

Overview

Components

+--------------+
|    ./apps    |
|--------------|
|  ./platform  |
|--------------|       +------------+
|   ./system   |- - - -| ./external |
|--------------|       +------------+
| ./bootstrap  |
|--------------|
|   ./metal    |
|--------------|
|   HARDWARE   |
+--------------+

Main components:

  • ./metal: bare metal management, install Linux and Kubernetes
  • ./bootstrap: GitOps bootstrap with ArgoCD
  • ./system: critical system components for the cluster (load balancer, storage, ingress, operation tools...)
  • ./platform: essential components for service hosting platform (git, build runners, dashboards...)
  • ./apps: user facing applications
  • ./external (optional): externally managed services

Support components:

  • ./tools: tools container, includes all the tools you'll need
  • ./docs: all documentation go here, this will generate a searchable web UI
  • ./scripts: scripts to automate common tasks

Provisioning flow

Everything is automated, after you edit the configuration files, you just need to run a single make command and it will:

  • (1) Build the ./metal layer:
    • Create an ephemeral, stateless PXE server
    • Install Linux on all servers in parallel
    • Build a Kubernetes cluster (based on k3s)
  • (2) Build the ./bootstrap layer:
    • Install ArgoCD
    • Configure the root app to manage other layers (and also manage itself)

From now on, ArgoCD will do the rest:

  • (3) Build the ./system layer (storage, networking, monitoring, etc)
  • (4) Build the ./platform layer (Gitea, Grafana, SSO, etc)
  • (5) Build the ./apps layer: (Syncthing, Jellyfin, etc)
flowchart TD
  subgraph metal[./metal]
    pxe[PXE Server] -.-> linux[Fedora Server] --> k3s
  end

  subgraph bootstrap[./bootstrap]
    argocd[ArgoCD] --> rootapp[Root app]
  end

  subgraph system[./system]
    metallb[MetalLB]
    nginx[NGINX]
    longhorn[Longhorn]
    cert-manager
    external-dns[External DNS]
    cloudflared
  end

  subgraph external[./external]
    letsencrypt[Let's Encrypt]
    cloudflare[Cloudflare]
  end

  letsencrypt -.-> cert-manager
  cloudflare -.-> cert-manager
  cloudflare -.-> external-dns
  cloudflare -.-> cloudflared

  subgraph platform
    Gitea
    Tekton
    Grafana
  end

  subgraph apps
    jellyfin[Jellyfin]
    matrix[Matrix]
    paperless[Paperless]
    seafile[Seafile]
  end

  make[Run make] -- 1 --> metal -- 2 --> bootstrap -. 3 .-> system -. 4 .-> platform -. 5 .-> apps

Below is the pseudo code for the entire process, you don't have to read it right now, but it will be handy for debugging.

Detailed provisioning flow
Human run make:
    build ./metal:
        install the OS:
            download the installer image and extract it
            create a PXE server on the controller using Docker Compose:
                DHCP server
                TFTP server
                HTTP server
            create init config for each machine
            turn the machines on via WoL
            the machines boot:
                select network boot automatically
                broadcast DHCP request
                DHCP server reply:
                    machine IP
                    TFTP server (next-server) IP
                get boot files from TFTP server
                    GRUB
                    GRUB config with URL to init config based on MAC address
                    kernel
                    initrd
                boot to the kernel
                download from HTTP server:
                    init config from the URL in GRUB config
                    remaining files required to boot
                install the OS based on the init config:
                    configure the system
                    remaining files required to install
                reboot to the new OS
            controller see the machines are ready
        build a Kubernetes cluster:
            download k3s binary
            generate cluster token
            copy k3s config files
            enable k3s service and form a cluster
            create KUBECONFIG file
            create MetalLB config:
                use the last /27 subnet of the network
                apply the config
    build ./bootstrap:
        install ArgoCD:
            apply helm chart
            wait for status
        install root app:
            select values file:
                if Gitea unreachable (first install):
                    get data from GitHub
                else:
                    get data from Gitea
            apply helm chart
            wait for status
ArgoCD apply the rest:
    clone git repo
    install components based on directories:
        ./bootstrap (it manages itself):
            argocd
            root
        ./system:
            storage
            loadbalancer
            ingress
            etc
        ./platform (depends on ./system):
            git:
                migrate the homelab repository from GitHub
                ArgoCD switch the source from GitHub to Gitea
            ci
            dashboards
            etc
        ./apps (depends on ./system and ./platform):
            homepage
            jellyfin
            etc