diff --git a/docker/guidelines.md b/docker/guidelines.md new file mode 100644 index 00000000..5d2e22dc --- /dev/null +++ b/docker/guidelines.md @@ -0,0 +1,198 @@ +# Docker Compose Architecture and Patterns + +This document outlines the common architecture and patterns used in Docker Compose files for the homelab infrastructure. + +## File Structure and Naming Conventions + +Each Docker service is defined in its own YAML file with the following structure: + +```yaml +--- +name: service-name +services: + main-service: + image: vendor/image:tag + container_name: service-name + restart: unless-stopped + # other configuration... + + # Optional supporting services + supporting-service: + # configuration... + +networks: + proxy: + external: true +``` + +**Common Practices:** +- Service metadata at the top with comments for documentation +- Links to official sites, source repositories, and helpful guides +- Service-specific subdirectories for configuration files +- Consistent naming conventions for container names + +## Core Infrastructure Components + +### Networking + +All services use a shared external `proxy` network for communication: + +```yaml +networks: + proxy: + external: true +``` + +### Traefik Reverse Proxy + +Traefik serves as the central reverse proxy for all services with the following features: + +- HTTPS with Let's Encrypt automation via Cloudflare DNS +- HTTP to HTTPS redirection +- HTTP/3 support +- Access control via middleware chains +- Integration with Authelia for SSO +- Integration with CrowdSec for security +- Docker provider for automatic service discovery + +#### Traefik Labels Pattern + +Services expose themselves to Traefik using labels: + +```yaml +labels: + traefik.enable: true + traefik.http.routers.service-name.rule: Host(`service.${MYDOMAIN}`) + traefik.http.routers.service-name.middlewares: middleware-name@file + traefik.http.services.service-name.loadbalancer.server.port: 8080 +``` + +### Authentication & Security + +#### Authelia SSO Integration + +Services requiring authentication use Authelia middleware: + +```yaml +traefik.http.routers.service-name.middlewares: localaccess-sso@file +``` + +#### Access Control Patterns + +- `localaccess`: Restricts access to local networks only, default option +- `localaccess-sso`: Restricts access to local networks and requires authentication +- `publicaccess`: Available externally with CrowdSec protection + +#### Cloudflare Tunnel + +External access is provided securely via Cloudflare Tunnel, avoiding direct port exposure. + +### Homepage Dashboard Integration + +Services are integrated into the Homepage dashboard using labels: + +```yaml +labels: + homepage.group: Category + homepage.name: Service Name + homepage.icon: icon-name.png + homepage.href: https://service.${MYDOMAIN}/ + homepage.description: "Service description" + homepage.widget.type: widget-type # Optional + homepage.widget.url: https://service.${MYDOMAIN}/ # Optional +``` + +## Environment Variables Management + +Environment variables are managed through `.env` files in a cascading priority: + +1. Common environment variables: `config/docker/.env` +2. Host-specific variables: `config/docker//.env` +3. Service-specific variables: `config/docker/.env.` +4. Host and service-specific variables: `config/docker//.env.` + +Common environment variables include: + +- `MYDOMAIN`: Base domain for all services +- `TIMEZONE`: Timezone setting +- `DOCKER_VOLUMES`: Base path for persistent volumes +- Service-specific credentials and API keys + +## Volume Management + +Persistent data is stored in volumes following this pattern: + +```yaml +volumes: + - ${DOCKER_VOLUMES}/service-name:/data # Volumes for data storage, not part of the repository + - ./service-name/config:/config # Local configuration files, committed to the repository +``` + +## Deployment Workflow + +Services are deployed using the Taskfile system: + +``` +task docker:apply # Deploy all containers +task docker:update # Update and restart containers +task docker:pull # Pull latest container images +task docker:stop # Stop configured containers +``` + +Under the hood, these tasks use the `docker compose` command with the following pattern: + +```bash +docker compose -f "$yaml_file" --env-file "$env_file" up --detach +``` + +## Service Categories + +Services are organized into logical categories: + +- **Security**: Traefik, Authelia, Cloudflared, CrowdSec, ... +- **Monitoring**: Prometheus, Grafana, Node-exporter, Uptime-kuma, ... +- **Media**: Jellyfin, Metube, Navidrome, Calibre, ... +- **Storage**: MinIO, Syncthing, FileSharing, ... +- **AI Tools**: Ollama, Open-WebUI, LiteLLM, AutogenStudio, ... +- **Tools**: Guacamole, Vaultwarden, SearXNG, ... + +## Template for New Services + +When creating a new service, use this template: + +```yaml +# Brief description of the service +# +# 🏠 Home: https://service-homepage.com/ +# 📜 Source: https://github.com/vendor/service +# Documentation: https://docs.service.com/ +--- +name: service-name +services: + service: + image: vendor/service:tag + container_name: service-name + restart: unless-stopped + environment: + TZ: ${TIMEZONE} + # Service-specific variables + volumes: + - ${DOCKER_VOLUMES}/service-name:/data + - ./service-name/config:/config # If needed + networks: + - proxy + labels: + traefik.enable: true + traefik.http.routers.service-name.rule: Host(`service.${MYDOMAIN}`) + traefik.http.routers.service-name.middlewares: middleware-name@file + traefik.http.services.service-name.loadbalancer.server.port: PORT + homepage.group: Category + homepage.name: Service Name + homepage.icon: service-icon.png + homepage.href: https://service.${MYDOMAIN}/ + homepage.description: "Service description" + +networks: + proxy: + external: true +``` diff --git a/docker/tools/homelab-docs.yaml b/docker/tools/homelab-docs.yaml index 88f41d5b..14ac8de9 100644 --- a/docker/tools/homelab-docs.yaml +++ b/docker/tools/homelab-docs.yaml @@ -4,7 +4,7 @@ name: homelab-docs services: homelab-docs: - image: docs.${MYDOMAIN}:latest + image: local/docs.${MYDOMAIN}:latest container_name: homelab-docs restart: unless-stopped networks: diff --git a/docs/learning.md b/docs/learning.md index 6b24c3a8..ab770273 100644 --- a/docs/learning.md +++ b/docs/learning.md @@ -11,6 +11,7 @@ Some good sources of learning materials and inspiration in the area of DevOps, H | YouTube | [TechWorld with Nana](https://youtube.com/@TechWorldwithNana) | "Some topics covered: Docker, Kubernetes, CI/CD - GitLab CI, GitHub Actions, Jenkins, Python, Ansible, Prometheus Monitoring, Terraform, YAML" | | YouTube | [Two Minute Papers](https://youtube.com/@TwoMinutePapers) | "What a time to be alive!" | | YouTube | [David Shapiro](https://youtube.com/@DaveShap) | "Navigating the Fourth Industrial Revolution! The future is incredibly bright, but the journey is fraught with risks." | +| YouTube | [Cole Medin](https://www.youtube.com/@ColeMedin) | "I'm your guy for learning how to make a big impact with Artificial Intelligence. AI is no doubt the future of not just software development but the whole world." | | Reddit | [r/selfhosted](https://www.reddit.com/r/selfhosted/) | "A place to share, discuss, discover, assist with, gain assistance for, and critique self-hosted alternatives to our favorite web apps, web services, and online tools." | | Reddit | [r/homelab](https://www.reddit.com/r/homelab/) | "Welcome to your friendly /r/homelab, where techies and sysadmin from everywhere are welcome to share their labs, projects, builds, etc." | | Reddit | [r/LocalLLaMA](https://www.reddit.com/r/LocalLLaMA/) | "Subreddit to discuss about Llama, the large language model created by Meta AI." | diff --git a/docs/runbooks.md b/docs/runbooks.md index 460d4da7..32152ce6 100644 --- a/docs/runbooks.md +++ b/docs/runbooks.md @@ -3,7 +3,7 @@ ## Reinstall a Docker host Note: This method is a bit unconventional but simplifies the deployment (and possible rollback) procedure a lot. -A new VM is used to deploy the OS, then the new system disk is attached to the old VM, which is already configured. +A new VM is used to deploy the OS, then the new system disk is attached to the old VM, which is already configured (MAC address, start at boot, start order, protection, USB devices...) Hosts involved: - `OLD`: perform on the old host @@ -14,7 +14,7 @@ Steps: - OLD: Install the new host using `proxmox/create-ubuntu-server-vm.sh` - OLD: Apply ansible using `ansible/apply-homelab.sh` -- OLD: Transfer container images to save bandwidth (Optional, see: [Docker](docker)) +- OLD: Transfer container images to save bandwidth (Optional, see: [Docker](../docker/README.md)) Optional: copy **Server Host Key**, an RSA, ED25519, or ECDSA private key diff --git a/docs/web/Taskfile.web.yaml b/docs/web/Taskfile.web.yaml index 1c8c5dd5..d04ce52c 100644 --- a/docs/web/Taskfile.web.yaml +++ b/docs/web/Taskfile.web.yaml @@ -13,7 +13,7 @@ tasks: - | # build SITE_DOMAIN=docs.${MYDOMAIN} - TAG=${SITE_DOMAIN}:collect + TAG=local/${SITE_DOMAIN}:collect docker build -f docs/web/Dockerfile -t "${TAG}" --target collect --progress=plain --no-cache . # export site_container_id=$(docker create "${TAG}") @@ -29,7 +29,7 @@ tasks: - | SITE_DOMAIN=docs.${MYDOMAIN} HUGO_BASEURL=https://${SITE_DOMAIN} - TAG=${SITE_DOMAIN}:latest + TAG=local/${SITE_DOMAIN}:latest docker build -f docs/web/Dockerfile -t "${TAG}" --build-arg HUGO_BASEURL="${HUGO_BASEURL}" . export: