Seitdem ich meinen eigenen Root-Server betreibe, habe ich diverse verschiedene Tools installiert, die mir im Software-Entwicklungsprozess helfen. Würde ich heute eine Firma für Software-Entwicklung oder -Beratung gründen, müsste ich für die Firma viele dieser Tools einrichten.

Auch für meine Hobbyprojekte sind sie so praktisch, dass ich an dieser Stelle für eine eventuell spätere Konsolidierung (d.h. unnötige Tools werden deinstalliert, wichtige sauberer strukturiert) festhalten möchte, welche Tools ich verwende.

Sowohl beruflich als auch in meinen Hobby-Projekten bin ich in einer DevOps-Rolle (ohne dieses als Berufsbezeichnung zu tragen). Das heißt ich entwickle die Software, deploye sie und verwalte den Server-Betrieb und kümmere mich um Fehlermeldungen der Kunden. Deshalb ist diese Liste sehr auf meine Entwicklungsprozesse im DevOps-Bereich ausgelegt.

Versionskontrolle und Continuous Integration

Versionskontrolle ist absolut notwendig, das dürfte jeden klar sein. Stand der Technik hierfür ist derzeit git. Allerdings möchte ich inzwischen auch nicht mehr ohne Continuous Integration (CI) arbeiten. CI hat nicht nur den Vorteil, dass meine Unit Tests automatisch bei jedem Commit ausgeführt werden, sondern es zwingt mich auch dazu, dass meine Software einfach genug strukturiert ist, dass sie jederzeit in einem Docker-Container auf dem Testsystem gestartet werden kann.

Ich verwende Gitlab für beide Aufgaben. Wer sich keinen Monolith mit mehr als 4GB RAM-Verbrauch im Single-User-Betrieb installieren will (laut docker stats), kann für CI auch Jenkins verwenden. Seit einiger Zeit bietet Jenkins mit Jenkins Pipeline ebenfalls CI über eine Konfigurationsdatei, die direkt im Repository gespeichert ist.

Statische Code Analyse

Statische Code-Analyse ist ein Punkt, den ich bisher leider sehr wenig betrieben habe. Da ich sehr viele kleine Einzelprojekte verwalte, habe ich mir inzwischen eine SonarQube-Instanz installiert, in die ich nach und nach alle Projekte einbinde. SonarQube ist ein Dienst, der die Log-Daten von externen Analyzern auswertet (die Standard-Tools, die man in der jeweiligen Sprache sowieso verwendet) und die Ergebnisse grafisch aufbereitet.

Es gibt auch ein Host-Angebot namens sonarcloud, dieses kann ich für Python-Projekte allerdings nicht empfehlen. Zumindest für meine Open-Source-Projekte habe ich keine Möglichkeit gefunden, die Standard Quality Profiles zu ändern und das Standard-Profil für Python hat leider viel zu wenige Regeln und findet damit keine Probleme im Code. Das Standard-Profil Sonay Way für Python hat 32 Regeln aktiviert, während ich in meinem derzeitigen Profil Python with Pylint 208 Regeln aktiviert habe.

SonarQube finde ich persönlich empfehlenswert, wenn man sehr viele Projekte verwaltet. Hat man nur ein einzelnes Repository, lohnt sich der Mehraufwand meines Erachtens nicht. In diesem Fall kann man die statische Analyse auch lokal ausführen.

In meinem Fall habe ich es direkt mit Continuous Integration auf Gitlab verbunden. Sind die Tests für ein Projekt erfolgreich durchgelaufen, startet als nächster Pipeline-Step die statische Code-Analyse und die Ergebnisse in SonarQube werden aktualisiert.

Deployment

Ich verwende derzeit noch kein Continuous Deployment. Allerdings habe ich für jedes Projekt ansible-Rollen, um die Projekte leicht deployen und aktualisieren zu können.

Auch beim Deployment ist meines Erachtens der Gewinn von ansible dann am höchsten, wenn man sehr viele Projekte verwaltet. In diesem Fall vergisst man nämlich sehr schnell für einzelne Projekte, welche Abhängigkeiten diese haben und wie man sie einrichtet. Mit ansible ist das alles in einer Konfigurationsdatei kodiert und kann mit einem Befehl wieder ausgeführt werden. Und wenn man auf einen neuen Server umzieht, muss man - wenn die ansible-Rollen gut definiert sind - nur noch die Ansible-Skripts ausführen. In der Realität fehlt hier und da leider doch ein Befehl im Ansible-Skript.

Für ein einzelnes Projekt könnte auch eine Make-Datei mit dem Befehl make deploy zum Deployment ausreichen. ansible bringt seine Vorteile dann ins Spiel, wenn man Abhängigkeiten zwischen mehreren Projekten hat. Ein weiterer Vorteil von ansible gegenüber Makefiles zum Deployment ist, dass man mit ansible den Zielzustand beschreibt, während man bei Makefiles die durchzuführenden Aktionen angibt. Bei einem zweiten Durchlauf führt ansible nur noch notwendige Änderungen durch (also im Normalfall gar keine), während ein Makefile nochmal alles ausführen würde.

Erfolgreich setze ich Makefiles zum Deployment von Websites ein, die mit Static HTML Generatoren generiert werden.

Alternativen zu ansible für größere Projekte sind Puppet und Chef, mit diesen habe ich allerdings noch überhaupt keine Erfahrungen gemacht.

Datenbanken

Ich bin kein Fan davon, alles in Container zu packen. Manche Dinge machen meines Erachtens Sinn in Containern und andere nicht. Containerize everything ist für mich nicht die Antwort, stattdessen sollte man lieber nach der jeweiligen Situation entscheiden.

Datenbanken installiere ich lieber direkt auf dem Host und halte dann eine zentrale Instanz für alle meine Projekte vor. Das vereinfacht die Administration. Letztlich möchte ich nicht für jedes meiner Programme (oder für jeden meiner Microservices) ein komplett eigenes DBMS-System aufsetzen, sondern sie sollen sich ein DBMS teilen. Und wenn ich sowieso nur ein zentrales DBMS verwalte, dann lohnt sich der Aufwand oder das zusätzliche Abstraktionslevel nicht (jede weitere Abstraktion ist eine weitere Fehlerquelle und in diesem Fall dann eine unnötige).

Nur weil die Programme sich ein DBMS teilen, heißt das ja nicht, dass sie sich eine Datenbank teilen. Ich lege trotzdem für jedes Programm eine eigene Datenbank und einen eigenen User an. Sie teilen sich meines Erachtens nur die Performance und die Lokalität der Datenbank kann nicht geändert werden. Letzteres ist in meiner Situation aber vollkommen egal, weil ich keine Dienste global an verschiedene Rechenzentren verteile und vermutlich auch auf absehbare Sicht nicht in diese Größenordnung wachsen werde.

Wenn man den Begriff Datenbanken weit auslegt, verwende ich im Moment diese:

Hiervon installiere ich Redis tatsächlich lokal auf jedem Host, weil ich es lediglich als Cache für temporäre Daten verwende.

Backups

Man sollte auch nicht vergessen, Backups anzulegen. Ich habe hierzu auch einige Ansible-Rollen, die mir die entsprechenden Skripts auf allen Servern anlegen. Diese Skripts kopieren anschließend meine Daten täglich oder wöchentlich in einen Bucket bei Amazon S3. Dort habe ich eine Regel eingerichtet, dass Daten nach einer bestimmten Zeit automatisch gelöscht werden.

Monitoring

Sobald man irgendwelche Dienste betreibt und irgendein Ziel für Uptime hat (und sei es nur 95%) wird Monitoring zur absoluten Pflicht. Andernfalls verliert man den Dienst aus den Augen und kriegt eventuell nicht mit, dass er bereits seit mehreren Tagen außer Betrieb ist.

Ich verwende hierfür im Moment eine eigene Lösung namens PiDAR, allerdings können je nach Anwendungsfall ebenfalls andere Dienste wie Pingdom, UptimeRobot und Healthchecks verwendet werden. Als self-hosted Alternative, die es schon seit viel Jahren gibt, kommt auch Nagios in Betracht.

Diese Angebote prüfen alle lediglich, ob ein Dienst aktiv oder inaktiv ist. Betreibt man sehr viele Dienste, wird eventuell auch Metrik-Analyse interessant. Hierzu könnte man Prometheus oder Graphite verwenden.

Log-Monitoring und -Analyse

Betreibt man viele Dienste, wird auch Log-Monitoring interessant. Hat man nur eine Firmen-Website, die potentiellen Kunden als Anlaufspunkt dient, und verkauft ansonsten Desktop-Software an die Kunden, kann man sich diesen Punkt meines Erachtens eher sparen. Außer natürlich man plant, direkt Log-Daten von den Kundenrechnern auszuwerten - dies muss dann aber natürlich mit den Kunden abgesprochen sein.

Standard-Werkzeug zum Log-Monitoring ist derzeit der ELK-Stack (Elasticsearch, Logstash, Kibana). Nun sind dies allerdings drei weitere Komponenten, die man ihrerseits warten und monitoren muss. Deshalb finde ich, dass an dieser Stelle ebenfalls andere Tools, auch Eigenentwicklungen, erlaubt sind.

Beim Log-Monitoring kommt es meines Erachtens sehr stark auf die Anforderungen an, die man hat. Will man einfach nur bei ERROR-Events benachrichtigt werden? Will man für Post-Mortem-Auswertungen alle Logs von allen Systemen in einer Ansicht vereinigt haben?

Letztlich hat es bei mir bisher immer besser funktioniert, eine dedizierte Ansicht mit aggregierten Werten (OK, Fehler, Fehlermeldung, beteiligter Host) zu erstellen und anschließend von Hand in den Log-Dateien nach den letzten Aktionen und dem exakten Grund für den Fehler zu schauen. Allerdings sprechen wir hier von Systemen mit maximal 5 beteiligten Hosts. Bei drei- oder vierstelligen Host-Anzahlen ist dann wahrscheinlich eine Sammlung aller Logs sinnvoller.

I do not maintain a comments section. If you have any questions or comments regarding my posts, please do not hesitate to send me an e-mail to blog@stefan-koch.name.