Claus Strasburger

Python-Skripte als systemd-user-service

Development | Ops

Wer kennt das nicht, da hat man ein Python-Skript geschrieben, zum Beispiel einen kleinen Webserver in Flask, oder irgendein Test-Protokoll-Server mit Twisted.

Diesen will man nun schnell auf einem Server oder Raspberry Pi starten, und ist durch unseren Post Systemctl Services unter Ubuntu auf den systemd-Geschmack gekommen.

Das Python-Skript

Folgendes schreibt man an den Anfang seines Python-Skripts. Wir nennen es hier jetzt mal main.py.

#!/bin/sh -e
"exec" "`dirname $0`/.env/bin/python" "$0" "$@"

def start_server():
    # ...
    print("Hello, World!")

if __name__ == "__main__":
    start_server()

Das führt dazu, dass der Prozess immer mit dem Virtualenv gestartet wird, welches wir gleich erzeugen.

Nicht vergessen, die Datei als ausführbar zu markieren: chmod a+x main.py

Unsere Abhängigkeiten schreiben wir in Python-typischer Manier in eine Datei namens requirements.txt:

flask
Twisted
...

Falls wir schon ein Virtualenv haben, können wir sie auch generieren: pip freeze > requirements.txt

Das Unit-File

In eine Datei mein-server.service schreiben wir folgendes:

[Unit]
Description=Mein-Server
After=network.target

[Service]
WorkingDirectory=DIR
ExecStart=DIR/main.py
SyslogIdentifier=mein-server
Restart=on-failure
RestartSec=2
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=default.target

Das Installier-Skript

Das untere Skript erledigt folgende Aufgaben:

  • erstellt automatisch ein Virtualenv
  • installiert die Abhängigkeiten aus der requirements.txt
  • erstellt ein Unit-File für systemd
  • startet und aktiviert den Dienst als User-Dienst

Ganz ohne root!

install.sh:

#!/bin/bash
set -euxo pipefail

SERVICE_PATH=$HOME/.config/systemd/user/
SERVICE=mein-server.service
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

ENV=.env
PIP=$ENV/bin/pip

make_venv() {
    [[ -x $PIP ]] || python3 -m venv $ENV
    $PIP install -r requirements.txt
}

install_service() {
    mkdir -p "$SERVICE_PATH"

    sed "s#DIR#${DIR}#g" "$SERVICE" > "$SERVICE_PATH/$SERVICE"
    loginctl enable-linger # allow our user to start permanent services
    systemctl --user daemon-reload
    systemctl --user enable --now "$SERVICE"
}

make_venv
install_service

Starten

Jetzt kopieren wir alle nötigen Dateien auf unseren Server, Pi, oder wohin auch immer, und starten die “Installation”:

rsync -avP * pi@mein-pi.local:mein-server/
ssh pi@mein-pi.local

cd mein-server
./install.sh

Fertig!

11 Mar 2019 #Ubuntu #Service #systemctl #Python #systemd #user #venv #virtualenv