Blog von Obi Madu
Zurück zu allen Artikeln
InfrastructureDevOpsProjects

Self-Hosting-Projekt (DevOps-Infra from Scratch)

Ein umfassender Leitfaden zum Aufbau einer selbstgehosteten DevOps-Infrastruktur von Grund auf mit Terraform, Ansible und Docker.

Self-Hosting-Projekt (DevOps-Infra from Scratch)

Über dieses Projekt

Eine Hintergrundgeschichte

Also, bevor ich meine Seele endgültig an Kubernetes verkauft habe, beschloss ich, dass ein einigermaßen umfassendes IaaS-Projekt angebracht wäre. Ich wollte grundlegende Dinge wie Netzwerke, Sicherheit, Scripting, dann Terraform, Ansible, Docker, Traefik und Wireguard (und alle Konzepte, für die sie stehen) für ein komplettes Projekt sinnvoll nutzen. Da Kubernetes schon eine Weile das wichtigste Werkzeug auf meiner "Zu-lernen"-Liste war, dachte ich mir, warum nicht alle notwendigen Werkzeuge, die ich für den Umstieg darauf brauche, in einem Vorläuferprojekt bereitstellen? Das schien eine großartige Idee zu sein!

Der kleine Clou war, dass ich diese Idee schon eine Weile hatte, bis ich einen Grund hatte, schnell eine Infrastruktur zum Laufen zu bringen, die es mir ermöglichen würde, meinen eigenen Vaultwarden-Passwort-Manager zu hosten, da mein damaliges Bitwarden-Abonnement kurz vor dem Ablauf stand. Bitwarden online ist kostengünstig, aber ich hatte zu diesem Zeitpunkt nicht die 10 Dollar für eine Verlängerung. Was ich jedoch hatte, waren einige Cloud-Guthaben bei DigitalOcean, ein Domainname, kostenloses Cloudflare, die Idee für dieses Projekt und vernünftige IT-Infrastruktur-Fähigkeiten.

Es könnte Sie interessieren, dass ich bei der Umsetzung dieses Projekts jede Datei mit Neovim (LazyVIM) erstellt habe, was ich Ende August angefangen hatte zu lernen. Insgesamt glaube ich, dass es den gesamten Prozess noch unterhaltsamer und lohnender gemacht hat.

Für dieses Projekt gab es also 5 überaus wichtige Ziele (und ein 6tes):-

  1. VOLLSTÄNDIGE AUTOMATISIERUNG (End-to-End-Einrichtung und sich zurücklehnen können)
  2. VOLLSTÄNDIGE SICHTBARKEIT (Nichts bewegt sich in der Umgebung auch nur einen Zentimeter, ohne entdeckt und protokolliert zu werden)
  3. VOLLSTÄNDIGE REPRODUZIERBARKEIT (Alle wichtigen Daten vollständig gesichert. Begleitet von einer Restore-Richtlinie auf Datumsbasis)
  4. GUTE SICHERHEIT (Privates VPN und nur SSH-Schlüssel zugänglich. Komplette Firewall-Abriegelung, sichere Kommunikation zwischen Docker und Host)
  5. Mache es so GÜNSTIG, SELBSTGEHOSTET, OPEN-SOURCE wie möglich (Auf einem einzigen VPS, der in mein Budget passt)
  6. Mache es von GRUND AUF neu

Bevor Sie weiterlesen, muss ich anmerken, dass dieses Projekt NICHT für hochverfügbare Umgebungen geeignet ist. Trotz der hochgradig wiederholbaren Natur seiner Umgebungen bedeutet ein einzelner Server eine gewisse betriebliche Ausfallzeit (jedoch nicht für den Workload) für Wiederherstellungsoperationen. Dennoch könnten kleine, aufstrebende, budgetbeschränkte Organisationen, die eine blitzschnelle Infrastruktur-Bootstrapping benötigen, damit völlig durchkommen.

In diesem Projekt habe ich die 5 gängigsten Dienste bereitgestellt, die man typischerweise benötigen würde, um eine k8s-Umgebung zu betreiben (und ein paar zusätzliche, persönliche Dinge, einschließlich eines LLM-Frontends, das ich Jarvis nenne 😉).

  1. Einen privaten Git-Hosting-Dienst (Gitea)
  2. Ein CI/CD-Tool (Jenkins)
  3. Ein Tool zur Verwaltung von Geheimnissen (Harshicorp Vault)
  4. Eine private Artifactory (JFrog Container Registry)
  5. Ein Tool zum Scannen von Schwachstellen (SonarQube)

Mit diesen könnten Sie privaten Code auf Gitea hosten, mit Jenkins bauen, (Code und Images) mit SonarQube und Trivy scannen, in die selbstgehostete Artifactory releasen und nach Kubernetes oder in eine beliebige andere Umgebung deployen. All dies, während Sie Ihre Geheimnisse sowohl innerhalb Ihrer Pipelines als auch Ihrer Kubernetes-Umgebung(en) durch eine zentrale Vault-Instanz sichern.

Um das zweite Ziel zu erreichen, habe ich einen Monitoring- und Observability-Stack bereitgestellt, der vollständigen Einblick in den Host-Server und alle Container-Umgebungen bietet.

  1. Prometheus und cAdvisor für die Metrik-Erfassung
  2. Loki und Promtail für die Protokollaggregation
  3. Grafana zur Visualisierung von Metriken und Protokollen

Was die Sicherheit betrifft, da diese Infrastruktur das Rückgrat der DevOps-Operationen für eine Organisation sein soll und daher intern ist, ist ihre Umgebung vollständig vom öffentlichen Internet abgeschottet und nur über ein VPN zugänglich. Das Projekt implementiert auch einen benutzerdefinierten SSH-Port und schützt die Umgebung effektiv vor den meisten automatisierten, zufälligen Internetangriffen. Zusätzlich ist eine sichere Kommunikation zwischen Docker und Host über geeignete IPTables-Regeln implementiert, wodurch sichergestellt wird, dass eine ordnungsgemäße Isolierung zwischen Container- und Host-Umgebung aufrechterhalten wird.

Wo ist der Quellcode?

Ich bin sehr gerne bereit (äußerst begierig), Ihrer Organisation dabei zu helfen, diese Infrastruktur oder etwas Ähnliches in Betrieb zu nehmen. Ich werde dies in jede Umgebung (Cloud oder On-Premise) portieren, mit der Garantie, dass keine der oben aufgeführten Kernfunktionen fehlen oder unvollständig sein wird. Bringt die Aufträge rein :cool:

Wie geht es für mich weiter?

Mit der mir (von jemandem) verliehenen Macht erkläre ich mich hiermit offiziell zum Kubestronaut. Von nun an werde ich Kubernetes leben und atmen, lol. Als Nächstes werde ich mit einigen saftigen k8s-Projekten fortfahren, die ich mit ein paar Freunden aushecke. Wir werden eine ziemlich komplizierte Microservices-Anwendung von Grund auf (über DevSecOps) auf k8s portieren. Wir erstellen k8s-Cluster, statten sie mit ArgoCD aus und werden im November mit GitOps richtig loslegen.

Wenn Ihnen dieses Projekt gefallen hat, vergessen Sie nicht, ein Like dazulassen und für mehr "Inhalte" wie diesen zu folgen. Lassen Sie mich auch in den Kommentaren wissen, was Sie von dem Projekt halten und wie ich es Ihrer Meinung nach hätte besser machen können.

WENN Sie dieses Projekt wiederholen möchten

  1. Seien Sie gewarnt, ich habe keine Anweisungen geschrieben, wie man etwas macht.
  2. Alles, was Sie finden werden, sind Anweisungen, was zu tun ist. Ich habe diese Schritte aufgeschrieben, während ich mit Freunden an diesem Projekt gearbeitet habe. Idealerweise sollten diese Anweisungen Ihnen helfen, dies auf eine vernünftige Weise zu erledigen.
  3. Der ganze Spaß besteht darin, das Wie für jeden Teil des Projekts herauszufinden, mit dem Sie nicht vertraut sind.

Projektvoraussetzungen

  1. Ein Domainname
  2. Zugang zu Cloud-Hosting
  3. Ein Cloud-Key-Store
  4. Ein (oder mehrere) Cloud-Storage-Bucket(s)
  5. Etwas IT-Know-how

Wichtige Hinweise zur Struktur und Organisation des Projekts

Die Kontroll- und Ziel-Cloud-Konten

Dieses Projekt geht von der Existenz zweier verschiedener Cloud-Plattform-Konten aus. Eines für die Zielressourcen und das andere für den ultimativen Admin-Zugriff auf die Ressourcen, die auf dem Zielkonto bereitgestellt werden.

Die wichtigsten Teile dieses Projekts sind nämlich:

  1. Der Terraform State (aus offensichtlichen Gründen)
  2. Server SSH Keys, die Ansible oder eine andere Person benötigt, um sich mit dem Server zu verbinden.
  3. Die Backup-Archive
  4. Die Hashicorp Vault Auto-Unseal-Schlüssel

Mit diesen vier Dingen und der Code-Implementierung könnte das gesamte System von Grund auf komplett reproduziert werden.

Infolgedessen bin ich während dieses Projekts davon ausgegangen, dass es eine Person (oder eine Gruppe von Personen) mit Super-Admin-Zugriff auf die gesamte grundlegende (operative) Infrastruktur des Unternehmens geben würde. Dies wären (idealerweise) wichtige Stakeholder wie der CEO oder der Head of Engineering. Sie wären die Personen mit den ultimativen (sprichwörtlichen) Schlüsseln zum Königreich.

In der Praxis können die "kontrollierenden" und "ressourcenbezogenen" Konten je nach Ihren spezifischen Einstellungen und Anforderungen verschiedene Formen und Konfigurationen annehmen. Diese Konten könnten verschiedene Entitäten über mehrere Aspekte Ihrer Cloud-Infrastruktur hinweg darstellen. Hier sind einige mögliche Szenarien:

1. Multi-Cloud: Die Konten könnten zu völlig unterschiedlichen Cloud-Plattformen gehören. Sie könnten beispielsweise Ihr kontrollierendes Konto auf Azure hosten, während Ihre Ressourcen bei einem anderen Cloud-Anbieter wie Digital Ocean bereitgestellt werden. Dadurch können Sie die einzigartigen Funktionen und Dienste jeder Plattform nutzen.

2. Gleiche Cloud-Plattform, verschiedene Konten: Die Konten könnten separate Konten innerhalb desselben Cloud-Anbieters sein. Diese Einrichtung ist üblich, wenn Sie eine Isolation zwischen verschiedenen Umgebungen (wie Produktion und Entwicklung) oder zwischen verschiedenen Abteilungen oder Projekten innerhalb Ihrer Organisation aufrechterhalten möchten.

3. Gleiche Cloud-Plattform, verschiedene Organisationseinheiten: Auf einigen Cloud-Plattformen, wie Azure mit seinen Ressourcengruppen oder Google Cloud mit seinen Projekten, könnten die Konten verschiedene logische Gruppierungen innerhalb desselben Cloud-Kontos darstellen. Dadurch können Sie Ressourcen anhand bestimmter Kriterien wie Projekt, Umgebung oder Anwendung organisieren und verwalten.

Ich habe den Multi-Cloud-Ansatz gewählt; meine Ressourcen werden bei Digital Ocean bereitgestellt, während sich mein kontrollierendes Konto bei Azure befindet.

Über das Bereitstellen anderer (zusätzlicher) Dienste

Wie Sie wahrscheinlich bemerkt haben, habe ich zusätzlich zu den Kern-Tools die VaultWarden-Passwort-Manager- und AnythingLLM-Anwendungen bereitgestellt. Diese Tools wurden für mich bereitgestellt. Es steht Ihnen frei, sie loszuwerden und jedes andere Tool Ihrer Wahl bereitzustellen.

Allgemeiner Überblick

Im Sinne eines allgemeinen Überblicks sind unten die Funktionen jeder der drei Kernkomponenten dieses Projekts aufgeführt;

Terraform zur Bereitstellung von;

  • Server-Ressourcen (VPC, Firewall/SG)
  • Server bei DO/AWS/etc, mit Userdata-Skript
  • DNS-Einträge bei Cloudflare/etc
  • Ansible Playbook

Ansible Playbook für;

  • Serverkonfiguration (Hostname, Netzwerk/Sicherheitsregeln)
  • Installation von Dienstprogrammen (s3cmd, prometheus-node-exporter)
  • Installation & Konfiguration von Docker
  • Installation & Konfiguration von WireGuard VPN
  • Bereitstellung von Docker Compose (Dienste und Monitoring-Stacks)
  • Skripte und Jobs für Docker-Volume-Backups
  • Skripte für Docker-Volume-Wiederherstellung

Docker Compose zur Bereitstellung von;

  • Traefik-Gateway (HTTP, SSL, HTTP-HTTPS-Redirects, IP-Whitelist)
  • Gitea
  • Jenkins
  • Hashicorp Vault
  • JFrog Container Registry
  • SonarQube OSS
  • Prometheus
  • Loki & Promtail
  • Grafana
  • Vaultwarden
  • AnythingLLM

Aufgabengruppierungen

Diese Aufgabengruppierungen haben sehr wesentlich dazu beigetragen, dass ich dieses Projekt beendet habe. Ich habe sie jeden Tag erstellt, an dem ich mit meinen Freunden an dem Projekt gearbeitet habe. Sie sind ein großer Grund dafür, dass ich nicht aufgegeben habe. In den meisten (wenn nicht allen) Fällen repräsentieren sie Tagesziele. Führen Sie sie der Reihe nach aus, und Sie erhalten eine voll funktionsfähige Infrastruktur.

Aufgabe 1

Ziel: Bootstrapping der Infrastruktur über Terraform

  1. Einzelner Server bei DO/AWS/etc über lokalen State
  2. Firewall/Security Group
  3. DNS-Einträge bei Cloudflare/Route53 etc. für zukünftige Dienste (Jenkins etc.)

Aufgabe 2

Ziel: Einrichten eines Remote States für Infra. Stellen Sie sicher, dass Ansible zugreifen und auf der Serverressource bereitstellen kann.

  1. Remote State für Terraform konfigurieren
  2. Terraform so konfigurieren, dass ein Dummy-Ansible-Playbook bereitgestellt wird
    2.1 Dummy-Ansible-Playbook erstellen
    2.2 SSH-Schlüsselpaar für den Serverzugriff erstellen
    2.2 Ansible-Benutzerkonto auf dem Server über Cloud-Init Userdata-Skript konfigurieren. Das Userdata-Skript erstellt ein "ansible"-Benutzerkonto und konfiguriert einen known-host-Schlüssel (mit dem in Schritt 2.2 generierten öffentlichen Schlüssel).
    2.3 Unseren privaten Schlüssel verwenden, um das Dummy-Playbook über einen lokalen Terraform-Provisioner auf dem Server auszuführen.

Aufgabe 3

Ziel: Lernen, Docker Compose über Ansible bereitzustellen. Traefik-Grundlagen lernen.

  1. Eine docker-compose-Datei erstellen, die eine temporäre Jenkins-Instanz über einen Traefik-Reverse-Proxy-Container unter der URL jenkins.your-domain.com bereitstellt. Nur auf HTTP bereitstellen. Vorerst keine Persistenz über Docker-Volumes erforderlich.
  2. docker-compose-Datei über eine Ansible-Rolle bereitstellen. Die Bereitstellung über eine Rolle ist obligatorisch. Denken Sie daran, das vorherige Dummy-Deployment jetzt zu entfernen, es wird nicht mehr benötigt.

Aufgabe 4

Ziel: Grundlegende Systemsicherheit implementieren.

  1. Unseren Server so konfigurieren, dass er einen anderen SSH-Port verwendet.
  2. SSH-Passwort-Login für alle Benutzer deaktivieren
  3. SSH-Root-Login deaktivieren
  4. Unsere Firewall-Regeln ändern, um Port 22 zu schließen und den neuen SSH-Port zu öffnen.
  5. Ansible für die Verbindung über den neuen SSH-Port konfigurieren.
  6. HTTPS zu unserem Docker-Compose-Deployment hinzufügen.

Aufgabe 5

Ziel: Host-Server-Monitoring konfigurieren. Die Workload-Umgebung unserer Container aktualisieren.

  1. Einen Prometheus Node Exporter über Ansible auf dem Host-Server installieren.
  2. Prometheus und Grafana in unseren Container-Workloads installieren.
  3. Ein neues Docker-Netzwerk mit dem Bridge-Treiber erstellen, eine beliebige private /24-Adresse als Subnetz zuweisen. Alle Container-Workloads diesem Netzwerk zuweisen.
    (Wenn Sie möchten, erstellen Sie verschiedene Compose-Dateien für den Monitoring-Stack und den Service-Stack. Dies wird sogar empfohlen, da all diese Dienste in einer einzigen Compose-Datei am Ende vielleicht etwas unordentlich aussehen).
  4. Entsprechende Docker-Volumes für jeden Compose-Dienst erstellen und diese Volumes den Diensten zuweisen.
  5. Unseren Host-Rechner als Metrikziel im Prometheus-Dienst über Ansible hinzufügen.
  6. Grafana konfigurieren, um unsere Prometheus-Metriken abzurufen.
  7. Ein Grafana-Dashboard hinzufügen, um unseren Host-Server zu überwachen. Dies dient vorerst nur dazu, sicherzustellen, dass das Setup funktioniert. Es wird temporär sein.

Aufgabe 6

Ziel: Backups implementieren.

  1. Ein Skript schreiben, um alle Docker-Volumes zu sichern und sie in einen Remote-Bucket hochzuladen.
    1.1 Das Skript sollte jedes Volume in einen temporären Container einhängen
    1.2 Seinen Inhalt per Tar und Gzip komprimieren. Alle Datei- und Verzeichnisbesitzinformationen intakt lassen.
    1.3 Archiv in einem Ordner 'backups' speichern. Eine Dateinamenskonvention 'volume-name-timestamp.tar.gz' verwenden.
    1.4 Wenn alle Volumes archiviert sind. Alles im Ordner 'backups' in den Cloud-Storage-Bucket hochladen, den Sie für Backups vorgesehen haben.
  2. Einen Cronjob verwenden, um dieses Backup-Skript über Ansible zweimal täglich zu zwei beliebigen Zeiten Ihrer Wahl auszuführen.

Aufgabe 7

Ziel: Eine Backup-Aufbewahrungsrichtlinie erstellen.

  1. Ein Skript schreiben, um alle Backups zu löschen, die älter als eine angegebene Anzahl von Tagen sind. Die Anzahl der Tage sollte ein Parameter sein, der dem Skript beim Aufruf übergeben wird.
    1.1 Wenn das Skript beispielsweise mit dem Parameter '5' aufgerufen wird, sollte es alle Backups löschen, die nicht innerhalb des Zeitrahmens der letzten 5 Tage liegen. Es sollte nur die Backups der letzten 5 Tage aufbewahren.
    Optional können Sie sich dafür entscheiden, immer die neuesten Backups jedes Volumes aufzubewahren.
  2. Über Ansible einen Cronjob erstellen, um dieses 'Cleanup'-Skript einmal täglich auszuführen. Die Backups der letzten 7 Tage aufbewahren.

Aufgabe 8

Ziel: Eine Protokollierungsinfrastruktur einrichten.

  1. Ihre Backup- und Cleanup-Skripte ändern, um relevante Aktionen auf stdout zu protokollieren.
  2. Ihre Backup- und Cleanup-Cronjobs ändern, um alle Ausgaben und Fehler mit relevanten Tags in das Syslog weiterzuleiten.
  3. Promtail und Grafana Loki über Docker Compose bereitstellen. Das Verzeichnis '/var/log' schreibgeschützt in den Promtail-Container einhängen.
  4. Mit Ansible eine Promtail-Konfigurationsdatei schreiben, um Protokolle aus dem Verzeichnis /var/log abzugreifen und an den Loki-Dienst zu senden.
  5. Das Loki-Docker-Plugin mit Ansible auf dem Host-Server installieren. Den Docker-Daemon so konfigurieren, dass Loki als Standard-Protokolltreiber verwendet wird, indem die Datei /etc/docker/daemon.json entsprechend bearbeitet wird. Denken Sie daran, den Docker-Dienst neu zu starten und alle Container nach diesem Schritt neu zu erstellen.
  6. Loki als Datenquelle zu Grafana hinzufügen. Bestätigen Sie, dass Sie Protokolle aus dem /var/log-Verzeichnis und von allen auf dem Host laufenden Docker-Containern über die Grafana-Registerkarte 'Explore' visualisieren können.

Aufgabe 9

Ziel: Bereitstellung der Dienste abschließen.

  1. Gitea über docker-compose bereitstellen
  2. Hashicorp Vault über docker-compose bereitstellen
  3. JFrog Container Registry OSS docker-compose bereitstellen
  4. SonarQube über docker-compose bereitstellen
  5. cAdvisor bereitstellen, um die Ressourcennutzung des Hosts pro Container-Dienst zu überwachen
  6. Prometheus-Metriken aus dem Traefik-Dienst bereitstellen
  7. Grafana-Dashboards für Traefik und cAdvisor erstellen
  8. Jeden anderen Dienst Ihrer Wahl bereitstellen!

Aufgabe 10

Ziel: Eine Richtlinie zur Wiederherstellung von Backups implementieren.

  1. Ein Backup-Wiederherstellungsskript erstellen, das nur ausgeführt wird, wenn der Wert einer Variablen 'restore' gleich 'true' ist. Das Skript sollte den Bucket-Namen, das Datum für das spezifisch wiederherzustellende Backup und einen Wert '1' oder '2' aufnehmen, der angibt, ob das erste oder zweite Backup des Tages wiederhergestellt werden soll.

Aufgabe 11

Ziel: Zugriff auf die Infrastruktur über WireGuard VPN privatisieren.

  1. Wireguard über Ansible auf dem Host-Server installieren.
  2. Durch eine Kombination von Ansible- und Terraform-Schritten eine Wireguard-Schnittstelle auf dem Server einrichten und konfigurieren, eine entsprechende Konfigurationsdatei für diese Schnittstelle generieren, die Schnittstelle mit der Konfigurationsdatei konfigurieren und dann entsprechende Client-Konfigurationsdateien für die Verbindung mit dieser Schnittstelle generieren.
  3. Traefik über eine IP-Whitelist so konfigurieren, dass Datenverkehr zu allen Diensten nur für Verbindungen zugelassen wird, die über das Wireguard-VPN-Subnetz initiiert wurden.

Aufgabe 12

Ziel: Einen Jenkins-Agenten-VPS über Terraform und Ansible bereitstellen und konfigurieren.

  1. Mit Terraform einen zusätzlichen VPS-Server beliebiger Größe bereitstellen, der als Build-Agent für Ihre Jenkins-Instanz fungiert.
  2. Ihren Agenten mit Ansible konfigurieren und alle Tools installieren, die Jenkins benötigen würde, z. B. ein JDK-Paket und Trivy für das Container Image Scanning.
  3. Mit Ansible Wireguard auf Ihrem Agenten installieren und ihn als Peer in Ihrem privaten VPN einrichten.
  4. (Optional) Wenn Sie von dem Agenten aus über ihre FQDNs auf Ihre Dienste in Traefik zugreifen möchten, richten Sie mit Ansible entsprechende DNS-Einträge auf dem Agenten ein.

Fazit

Voila! Wenn Ihre Fähigkeiten Sie so weit gebracht haben 😉 Dann haben Sie mittlerweile eine funktionierende Kopie dieser Infrastruktur. Wenn Ihnen dieses Projekt gefallen hat, vergessen Sie nicht, ein Like dazulassen. Lassen Sie mich auch in den Kommentaren wissen, was Sie von dem Projekt halten und wie ich es Ihrer Meinung nach hätte besser machen können.