j4n
j4n.e7h.eu
e7h

2024-11-30 17:40:00

jubliogo – ein Blick hinter die Kulissen (Teil 1)

Mein kleiner Wissenspeicher j4n.e7h.eu ist für mich ein Hobby-Projekt, mit dem ich mich genauer mit der Programmiersprache Go und dem Web-Framework Gin-Gonic befasse. Traditionell lerne ich dann am besten, wenn ich gleich irgendetwas umsetzen kann. Der interne Name für diese Spielwiese: jubliogo.

Die Grundarchitektur

Die Grundarchitektur ist denkbar einfach. jubliogo kommt ohne Datenbank aus. Die Konfiguration ist in einer einfachen YAML-Datei hinterlegt. Die Inhalte (Seiten und Posts/Artikel) liegen als Markdown-Dateien in einem Verzeichnis vor.

jubliogo scannt regelmäßig dieses Verzeichnis, rendert bei Änderungen die Markdown-Dateien neu und hält die Ergebnisse im Speicher für einen schnellen Zugriff. Bei meiner geringen Frequenz an Posts und den überschaubaren Längen der Texte kann ich mir das leisten. Alternativ bietet sich die Verwendung eines Caches an, z. B. mit Redis. Zusätzliche Datenstrukturen, wie Navigation, Rubriken (Tags) werden während des regelmäßigen Scans aufgebaut. Als Markdown-Renderer kommt Goldmark zum Einsatz.

Mediendateien liegen ebenfalls in einem benannten Verzeichnis und werden von da aus direkt bereitgestellt. Wichtige Assets, wie Skripte, Stylesheets, etc. sind ins Zielbinary embedded. Gleiches gilt für die Templates. So ist ein einfaches Deployment mit nur einer Datei möglich.

Für das Seiten-Grundgerüst wird eine Django-kompatible Template-Engine (Pongo2) genutzt. Sie gefällt mir besser als die Go Standard-Template-Engine und ich kann sie für meine Zwecke besser erweitern.

Die Entwicklungsumgebung

Mit all den positiven Erfahrungen rund um Devcontainer1,2 hat sich bei mir eine gewisse Faulheit eingestellt, Toolchains auf meinem Entwicklungsrechner aufzusetzen. Die Nutzung von passend ausgestatteten Containern ist so viel komfortabler und reproduzierbarer, außerdem kann man viel leichter zwischen verschiedenen Projekten mit unterschiedlichen Anforderungen hin- und herwechseln. Es gibt nur minimale Abhängigkeiten zum Hostsystem.

Daher setze ich auch für dieses Projekt auf Devcontainer.

Da hier keine große und komplexe Architektur erforderlich ist, reicht ein sehr einfach ausgestatteter Container, definiert in der Datei .devcontainer/devcontainer.json:

 1{
 2    "name": "jubliogo",
 3    "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
 4    "customizations": {
 5        "vscode": {
 6            "extensions": [
 7                "ms-azuretools.vscode-docker",
 8                "golang.Go",
 9                "premparihar.gotestexplorer",
10                "wholroyd.jinja",
11                "yzhang.markdown-all-in-one",
12                "ms-vscode.makefile-tools",
13                "mutantdino.resourcemonitor"
14            ]
15        }
16    },
17    "build": {
18        "dockerfile": "Dockerfile"
19    },
20    "forwardPorts": [8122]
21}

Keine Überraschungen hier: Der Container wird benannt (Zeile 2), der Workspace ist am Standard-Ort (Zeile 3), für den Containeraufbau wird ein Dockerfile verwendet (Zeilen 17/18). Auf Port 8122 wird die Applikation später hören, also wird es in Zeile 20 »weitergeleitet«.

Wie man sieht, versuche ich auch mit diesem Projekt, mich weiter in die Nutzung von VS Code einzuarbeiten, daher erhält der Container ab der Zeile 6 eine Liste an Extensions, die ich für nützlich erachtet habe.

Es wird mir jedoch von Tag zu Tag klarer, dass ich auf absehbare Zeit bei GoLand als IDE bleibe. Sie ist wesentlich komfortabler und wirkt weit ausgereifter. Und es ist meine Freizeit. 🤣

Das .devcontainer/Dockerfile für den Containeraufbau sieht jetzt so aus:

 1FROM golang:alpine
 2
 3RUN apk update && apk upgrade
 4RUN apk add make file git gpg yq wget curl bash bash-completion shadow nano starship openssh-client openssh-sftp-server mailcap
 5
 6RUN chsh -s /bin/bash
 7RUN echo 'eval "$(starship init bash)"' >> ~/.bashrc
 8
 9RUN go install -v github.com/go-delve/delve/cmd/dlv@latest
10RUN go install -v honnef.co/go/tools/cmd/staticcheck@latest
11RUN go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@latest
12RUN wget -O - -q https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(go env GOPATH)/bin

Ich verwende stets das aktuelle offizielle Go-Image3 als Basis (Zeile 1). Dazu werden ein paar Pakete nachinstalliert, die bei der Entwicklung noch hilfreich sein werden (Zeile 4). Wie schon in anderen Containern, installiere ich auch diesmal die Shell-Erweiterung starship für die Bash (Zeilen 6/7), ein reines Komfortthema.

Im Folgenden (Zeilen 9 ff.) werden noch verschiedene Go-Entwicklungstools und Code-Checker installiert. Wir brauchen sie später noch.

Der Buildprozess

Ich bin ein großer Fan von gut gestalteten und effektiven CI/CD-Pipelines, mit sinnvollen Teststufen und einer so hohen Konfidenz, dass das Ziel das direkte Deployment in Produktion ist. Aber ich bin auch pragmatisch, insbesondere bei einem Hobby-Projekt. Hier tut es für mich ein einfaches Makefile für die Durchführung von Tests, Analysen und Builds.

Schauen wir rein:

 1.DEFAULT_GOAL := ci
 2
 3update-version:
 4	bash update-version.sh
 5
 6format:
 7	go fmt ./...
 8
 9vet:
10	go vet ./...
11
12staticcheck:
13	staticcheck ./...
14
15golangci-lint:
16	golangci-lint run ./...
17
18sast:
19	gosec ./...
20
21analyze: vet staticcheck golangci-lint sast
22
23update-mod:
24	go get -u
25
26tidy-mod:
27	go mod tidy
28
29mod: update-mod tidy-mod
30
31test:
32	go test -v ./...
33
34build:
35	go build -v -ldflags "-s -w"
36	
37build-linux:
38	GOOS=linux GOARCH=amd64 ${MAKE} build
39
40go-clean:
41	go clean
42
43clean: go-clean
44	rm -f jubliogo
45
46ci: clean update-version format mod analyze test build-linux
47
48.PHONY: update-version test clean ci format sast vet staticcheck golangci-lint go-clean build build-linux mod tidy-mod update-mod analyze

Im Wesentlichen ist der Inhalt selbsterklärend. Interessant ist ggf. das Goal update-version: Hier wird ein Skript aufgerufen, welches die Versionsnummer für den Build hochzählt. Ich werde darauf zu einem späteren Zeitpunkt noch genauer auf die Nutzung eingehen, insbesondere dann, wenn klar ist, wie die Version entsteht.

Wie geht es weiter?

Die Grundlagen sind nun gelegt und der Spaß kann losgehen. Im nächsten Teil geht es dann mit dem eigentlichen Code los.


  1. siehe Artikel Typst im Devcontainer ↩︎

  2. siehe Artikel Django im Devcontainer mit PostgreSQL-Datenbank und Redis ↩︎

  3. Offizieller Go (golang)-Container im Docker Hub: https://hub.docker.com/_/golang ↩︎




Zuletzt geändert: 2024-12-01 12:59:34