3 Minuten
Go Dockerless
Ich bin ein riesiger Freund der Idee, Deployments mittels infrastructure as code wiederholbar zu machen.
Trotzdem suche ich auch immer wieder nach Möglichkeiten die Dinge noch einfacher zu gestalten.
Als ich zuletzt auf Go als Programmiersprache gestossen bin, konnte das experimentieren beginnen. Die Sprache hat einiges was Spaß macht: Sie kompiliert zu nativen Binaries, erzeugt per default statisch gelinkte executables und hat cross compiling und paket management gleich eingebaut.
Dadurch sind auf einmal ganz viele Probleme verschwunden, die ich eigentlich mit Docker gelöst hatte.
Würde ich in einer klassischen Sprache wie C/C++ schreiben, dann müsste ich jetzt den Kompiliervorgang von meinem Mac auf das Linux im Docker container übertragen.
Bei Go reicht dieses nette alias
alias golinux="GOOS=linux GOARCH=amd64 go build"
Und schon kann ich einem Go Modulverzeichnis sowas hier machen
golinux -o app_linux
Und heraus fällt eine ELF Binary, fertig für die Ausführung auf meinem Server.
Das Deployment einer Go Application beschränkt sich darauf eine einzige ausführbare Datei auf den Server zu kopieren.
Geradezu ideal z.B. für kleine Kommandozeilen Applikationen. Die schiebt bei mir dann folgende BASH Funktion auf den Server
cmd2server() {
if [ -n "$1" ]; then
NAME="$1"
LINUXNAME=${NAME}_linux64
golinux -o "$LINUXNAME" && \
scp "$LINUXNAME" textzentrisch.de:/tmp/$NAME && \
rm "$LINUXNAME" && \
ssh textzentrisch.de -C "sudo mv /tmp/$NAME /usr/local/bin/"
else
echo "Please supply the command name as argument!"
fi
}
Aber was wenn ich jetzt eine Go Applikation auf den Server geschoben habe, die als Deamon laufen soll? Docker hat sich ja auch darum gekümmert, dass der Prozess beim Neustart mitgestartet wird und falls er abstürzt auch neustartet.
Ich dachte mir: Let’s go old-school..
systemd2server() {
NAME="$1"
scp "$NAME.service" textzentrisch.de:/tmp/$NAME.service && \
ssh textzentrisch.de -C "sudo mv /tmp/$NAME.service /etc/systemd/system/ && \
sudo systemctl daemon-reload && \
sudo service $NAME start"
}
Und so sieht eine passende .service Datei aus, die ich dann einfach im Hauptverzeichnis meiner App ablege.
[Unit]
Description="Test the service"
[Service]
User=memmaker
WorkingDirectory=/tmp/test
ExecStart=devhttp 8000
Restart=always
[Install]
WantedBy=multi-user.target
Da ich auch häufiger Projekte habe die kleine statische Seiten auswerfen, dachte ich mir ich könnte auch was gebrauchen um solche Verzeichnisse auf den Server zu deployen.
dir2server() {
SOURCEDIR="$1"
TARGETDIR="$2"
cd $SOURCEDIR && \
tar czvf ../$SOURCEDIR.tgz ./* && \
cd .. && \
scp $SOURCEDIR.tgz textzentrisch.de:/tmp/ && \
rm $SOURCEDIR.tgz && \
ssh textzentrisch.de -C "sudo mkdir -p $TARGETDIR && cd $TARGETDIR && sudo mv /tmp/$SOURCEDIR.tgz . && sudo tar xzvf $SOURCEDIR.tgz && sudo rm $SOURCEDIR.tgz"
}
Zusammen mit dieser kleinen Shell Funktion hat man dann eine bequeme Schaltzentrale.
rservice() {
ssh textzentrisch.de -C "sudo service $*"
}
Das ganze sieht dann im Einsatz etwa so aus:
cmd2server ngman # deployen der neuesten version eines kommandozeilen tools
cmd2server devhttp # deployen eines services
systemd2server devhttp # als service eintragen und starten
dir2server ./html /var/www/html