Smart Green Home: Die Monitoring-Entwicklungsumgebung
Nachdem nun die Hardware steht und erste Daten in Experimenten »angezapft« werden konnten, ist es nun an der Zeit, in die Entwicklung eines lokalen Monitorings einzusteigen. Dazu braucht es eine verlässliche und reproduzierbare Entwicklungsumgebung.
In der Vergangenheit habe ich bereits gute Erfahrungen mit Devcontainern gemacht. Sie bieten konsistente und reproduzierbare Entwicklungsumgebungen auf allen gängigen Betriebssystemen und können gleich ganze Tech Stacks abbilden. Teilweise habe ich davon in diesem Blog geschrieben.
Mit diesem Teil wird es für mehrere Teile super technisch und möglicherweise etwas zu »trocken« für den einen oder anderen Leser. Aber irgendwann kommen noch weitere Erfahrungsberichte – denn in der Zwischenzeit ist viel passiert.
Was wird gebraucht?
Ich habe mir vorgenommen, Daten mit einem oder mehreren in Go geschriebenen Programmen zu erfassen und in eine InfluxDB zu schreiben. Grafana möchte ich dazu nutzen, die gesammelten Daten zu visualisieren, Alarme zu definieren und Benachrichtigungen zu versenden.
»Go« ist aktuell neben Python eine meiner Lieblingsprogrammiersprachen. Sie ist ähnlich universell einsetzbar wie Python und verfügt über ein ausgezeichnetes Ökosystem. Außerdem lassen sich fertig kompilierte Go-Programme mit sehr wenig Aufwand und sehr überschaubaren Abhängigkeiten in der späteren Betriebsumgebung ausführen.
Alle Aufgaben zur Sammlung von Daten hätten sich genauso gut mit Python oder anderen Sprachen realisieren lassen.
In unserem Devcontainer-Setup sollte im Optimalfall der gesamte Stack aus einem Container
für die Go-Entwicklung, Grafana und InfluxDB enthalten sein. Dies kann erreicht werden, indem eine
docker-compose.yml für den Devcontainer hinterlegt wird.
Konkreter Aufbau der Entwicklungsumgebung
Beginnen wir mit wichtigen Dateien für den Aufbau der Devcontainer-basierten Entwicklungsumgebung.
Zur Übersicht organisiere ich meine Devcontainer-Setups in der Regel im Verzeichnis
.devcontainer/ direkt unterhalb des Projekt-Roots, statt alle Dateien (inklusive einer
.devcontainer.json) im Projekt-Root zu haben. Gängige IDEs, aber auch Helfer-Tools wie
beispielsweise DevPod und GitHub Codespaces können problemlos damit
umgehen.
Die Basis: .devcontainer/devcontainer.json
Ausgangspunkt ist diese .devcontainer/devcontainer.json, die die Docker-Compose-Datei
referenziert und den darin enthaltenen Service devcontainer als primären Entwicklungscontainer
ausweist.
1{
2 "name": "energy-monitor",
3 "dockerComposeFile": "docker-compose.yml",
4 "service": "devcontainer",
5 "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
6 "forwardPorts": [
7 "influx:8086",
8 "grafana:3000"
9 ]
10}
Zusätzlich werden bereits hier die weiterleiteten Ports für die InfluxDB-Datenbank und die Grafana-Instanz definiert, damit auf diese Dienste auch von außerhalb des Containers zugegriffen werden kann.
Außerdem wäre es möglich, hier bereits Anpassungen für die IDE vorzunehmen. Ich verwende
GoLand als IDE – die Anpassungen werden jedoch im
.idea-Ordner im Projekt gespeichert und mit eingecheckt.
Der Stack: .devcontainer/docker-compose.yml
Hier finden sich nun die drei besprochenen Komponenten devcontainer, grafana und influx
des Stacks wieder:
1services:
2
3 devcontainer:
4 container_name: em-devcontainer
5 build:
6 context: .
7 dockerfile: Dockerfile
8 volumes:
9 - ../..:/workspaces:cached
10 depends_on:
11 - influx
12 networks:
13 - em-net
14 environment:
15 EM_INFLUXDB_HOST: http://influx:8086
16 EM_INFLUXDB_ORG: developer
17 EM_INFLUXDB_BUCKET: energy
18 EM_INFLUXDB_TOKEN: DeveloperInfluxAdminToken==
19 command: sleep infinity
20
21 grafana:
22 container_name: em-grafana
23 image: grafana/grafana-oss
24 restart: unless-stopped
25 ports:
26 - "3000:3000"
27 networks:
28 - em-net
29 depends_on:
30 - influx
31 environment:
32 GF_DATABASE_TYPE: sqlite3
33 INFLUXDB_HOST: http://influx:8086
34 INFLUXDB_ORG: developer
35 INFLUXDB_BUCKET: energy
36 INFLUXDB_TOKEN_FILE: /run/secrets/influxdb2-admin-token
37 secrets:
38 - influxdb2-admin-token
39
40 influx:
41 container_name: em-influx
42 image: influxdb:2
43 restart: unless-stopped
44 networks:
45 - em-net
46 environment:
47 DOCKER_INFLUXDB_INIT_MODE: setup
48 DOCKER_INFLUXDB_INIT_ORG: developer
49 DOCKER_INFLUXDB_INIT_BUCKET: energy
50 DOCKER_INFLUXDB_INIT_USERNAME_FILE: /run/secrets/influxdb2-admin-username
51 DOCKER_INFLUXDB_INIT_PASSWORD_FILE: /run/secrets/influxdb2-admin-password
52 DOCKER_INFLUXDB_INIT_ADMIN_TOKEN_FILE: /run/secrets/influxdb2-admin-token
53 secrets:
54 - influxdb2-admin-username
55 - influxdb2-admin-password
56 - influxdb2-admin-token
57 ports:
58 - "8086:8086"
59
60secrets:
61 influxdb2-admin-username:
62 file: .env.influxdb2-admin-username
63 influxdb2-admin-password:
64 file: .env.influxdb2-admin-password
65 influxdb2-admin-token:
66 file: .env.influxdb2-admin-token
67
68networks:
69 em-net:
70 name: em-net
Hier ergeben sich eine kleine Reihe an Besonderheiten:
- Verwendung von InfluxDB Version 2: Ich bin persönlich ein großer Fan der Flux-Abfragesprache für die Zeitreihen-Datenbank, da man mit den Abfragen gleich bestimmte Datenaufbereitungen verbinden kann. Leider steht »Flux« ab Version 3 nicht mehr zur Verfügung1.
- Verwendung von Docker Secrets in einem lokalen Entwicklungscontainer: Die Standard-Images von Grafana2 und InfluxDB3 verwenden Docker Secrets
- Referenz auf
Dockerfilefür Hauptentwicklungscontainer: Der Container braucht einige Anpassungen, weswegen ich auf einen eigenenDockerfilestatt auf ein fertiges Image setze.
In der Tat baue ich hier direkt von Anfang an bewusst technische Schulden auf. Zu dem Zeitpunkt, zu dem ich das Monitoring an den Start bringen wollte, hatte ich mich noch nicht in die Alternativen zu »Flux« eingearbeitet und mir gedacht, dass eine Migration auf InfluxDB 3 im Nachgang noch machbar wird, möglicherweise sogar mit der Hilfe von KI (Looking at you, JetBrains AI).
Klassische Trade-Off-Betrachtung: »Neuester Tech Stack« versus »mit bekanntem Tech Stack (vermeintlich) schneller zum Release kommen«.
Was daraus geworden ist und welche Herausforderungen damit verbunden waren und es noch sind, werde ich in einem späteren Artikel beschreiben.
Soviel vorweg: Die beste Entscheidung war das sicher nicht.
Secrets in den .devcontainer/.env.influxdb2-admin-*-Dateien
Einfache Antwort: Nein, nicht einchecken, niemals. Und schon gar nicht ungeschützt bzw. unverschlüsselt.
Doch für diesen Devcontainer ist es eine komfortable Lösung, zumal die Credentials sowieso an
anderer Stelle der docker-compose.yml-Datei vorhanden sind und es sich um reine Dev-Instanzen
handelt.
Hier gibt es auf jeden Fall Potenzial für Optimierungen. Für das heimische Entwicklungssetup ist das jedoch ausreichend.
Die drei Dateien enthalten einfach nur die Entwicklungs-Credentials:
Datei im Ordner .devcontainer/ |
Inhalt |
|---|---|
.env.influxdb2-admin-username |
developer |
.env.influxdb2-admin-password |
developer |
.env.influxdb2-admin-token |
DeveloperInfluxAdminToken== |
Der Hauptentwicklungscontainer: .devcontainer/Dockerfile
Den eigentlichen Entwicklungscontainer, also den Container, in dem die Entwicklung des Go-Codes stattfindet, wird
als Dockerfile auf Basis des Standard-golang-Containers definiert, um die
für mich erwünschten Anpassungen durchführen zu können. Ich verwende die bookworm-Variante4.
1FROM golang:1.25-bookworm
2
3ENV DEBIAN_FRONTEND=noninteractive
4
5RUN apt-get -y update && apt-get -y upgrade
6RUN apt-get -y install make build-essential crossbuild-essential-amd64 wget curl bash jq less
7
8RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
9RUN (. "$HOME/.cargo/env" && cargo install just)
10RUN (. "$HOME/.cargo/env" && cargo install starship)
11RUN echo 'eval "$(starship init bash)"' >> "$HOME/.bashrc"
12
13RUN go install github.com/go-delve/delve/cmd/dlv@latest
14RUN go install github.com/segmentio/golines@latest
15RUN go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
16RUN go install golang.org/x/vuln/cmd/govulncheck@latest
Neben einigen Build-Tools wird im Container noch eine Rust-Umgebung installiert. Ursprünglich hatte ich geplant, einige Teile in Rust umzusetzen, mich aber im Verlauf der Entwicklung dagegen entschieden. Sie bleibt trotzdem Bestandteil des Containers, da ich so noch zwei Tools bereitstellen kann, die ich sehr gerne nutze:
starship5: Ein sehr hilfreiches Prompt für die Shell (hier für die Bash)just6: Ein Command Runner, ähnlichmake, jedoch etwas einfacher in der Handhabung und meiner Meinung nach praktischer in der Anwendung
Die übrigen go install-Aufrufe installieren den Debugger und ein paar Tools für statische Codeanalyse.
Deren Einsatz erläutere ich zu einem späteren Zeitpunkt.
Der größte Vorteil an diesem Container-Setup für mich: In diesem Container kann ich auf meinem MacBook problemlos eine Version kompilieren, die besonders gut zur Zielbetriebsumgebung passt. Mehr dazu zu einem späteren Zeitpunkt.
Den Container-Stack hochfahren
Persönlich bevorzuge ich bei der Entwicklung mit Devcontainern auf meinem MacBook die Kombination von Podman und DevPod. Als IDE setze ich – wie oben schon beschrieben – auf JetBrains GoLand. DevPod startet den Container direkt auf Basis des Projektverzeichnisses und konfiguriert alles, damit über das JetBrains Gateway GoLand verwendet werden kann. Sehr praktisch!
Nach kurzer Zeit sollte die IDE geöffnet sein, mit einem noch leeren Projekt.
Ein schneller Check
Mit dem Start des Devcontainers kann es endlich losgehen. Der beste Zeitpunkt, den Stack auf grundlegende Funktion zu prüfen:
| InfluxDB | Grafana | |
|---|---|---|
![]() |
![]() |
|
| URL: | http://localhost:8086/ | http://localhost:3000/ |
| Benutzername: | developer |
admin |
| Passwort: | developer |
admin7 |
Hello World!
Auch die eigentliche Umgebung im Devcontainer wollen wir jetzt testen. Dazu nutzen wir das Terminal der IDE und erstellen eine neue Go-Mod-Konfiguration:
1go mod init j4n.e7h.eu/dev/energy/em-collect
Anschließend erzeugen wir im Projekt-Root eine Datei main.go mit diesem Inhalt:
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 fmt.Println("hello, world!")
9}
Neben der main-Funktion erscheint direkt ein »Play«-Button. Wir klicken einmal darauf, und in der Konsole
sollte fröhlich »hello, world!« erscheinen:

Nun ist alles vorbereitet.
Ein kleiner Ausblick auf das Betriebskonzept
Es werden eine Menge an Daten erfasst werden, und ich möchte diese Daten wenigstens zwei Jahre speichern können. Ich habe mich dazu entschieden, ein preiswertes 2-Platten-NAS-System zu erwerben, welches nicht nur die Festplatten im RAID1-Modus betreiben kann, sondern auch in der Lage ist, Docker-Container auszuführen.
So kann ich auf diesem NAS Grafana und InfluxDB als Container betreiben, und das Go-Programm zur Datensammlung
in einem Photon-Container laufen lassen. So muss ich keine eigenen Container
bauen, sondern kann den bestehenden minimalistischen Photon-Container verwenden. Es wird dazu ein Verzeichnis in
den Container als /em gemountet, welches neben der Executable auch die passenden Konfigurationsdateien und ein
Startskript enthält. Als Ausführungsbefehl wird dann /bin/bash /em/startup.sh für den Container konfiguriert.
Das Startup-Skript wird dann in etwa so aussehen, wenn unser Programm em-collect heißt:
1#!/bin/bash
2
3cd /em || exit 1
4chmod +x em-collect
5
6./em-collect
Und so geht es weiter
Im nächsten Artikel werde ich dann konkret in der Implementierung des Go-Programms em-collect beginnen: Eine erste
Datenquelle, der Smart Meter vom Netzbetreiber, frisch gesetzt im Zuge der Inbetriebnahme der PV-Anlage, wird
periodisch abgefragt und die Messwerte in der InfluxDB gespeichert. Mit einem
Tasmota-betriebenen Infrarot-Tastkopf
sollte das eigentlich ein Kinderspiel werden.
Welche Hürden dennoch zu überwinden waren und warum gerade diese Daten so echtzeitnah wie möglich wichtig sind, um erste Steuerungsaufgaben umzusetzen, wird ebenfalls Bestandteil des nächsten Teils.
Interessant?
Ich freue mich, per E-Mail von Dir zu hören, wenn Du eigene Erfahrungen diskutieren möchtest oder gerade selbst ein ähnliches Projekt planst.
Dieser Artikel wurde von einem Menschen geschrieben, anschließend mit Hilfe von KI korrigiert und teilweise umformuliert.
KI hat keinerlei Inhalte selbst erzeugt oder Fakten beigetragen.
-
Die Abfragesprache »Flux« befindet sich offiziell im »Maintenance Mode«, siehe The future of Flux ↩︎
-
Das offizielle Docker-Go-Image in der Variante
bookwormbasiert auf Debian 12 (Codenamebookworm). Zum Zeitpunkt dieses Artikels ist das die »oldstable« Version von Debian. ↩︎ -
Offizielle Starship-Website: https://starship.rs/ ↩︎
-
Offizielle Just-Website: https://just.systems/ ↩︎
-
Grafana verlangt bei der ersten Anmeldung die Änderung des Passworts. Es ist jedoch möglich, das neue Passwort wieder auf
adminzu setzen – jedoch wird beim nächsten Login erneut die Änderung verlangt. Daher bietet sich an, etwas anderes, z. B.developerzu verwenden. ↩︎
Smart Green Home Go Entwicklung Devcontainer Monitoring Linux
Zuletzt geändert: 2025-12-11 21:11:48


