fboës - Der Blog

Schnelle Deployments mit Gitlab

Ihr habt eine Gitlab-Instanz in eurer Firma stehen? Ihr wollt mit Deployments anfangen, habt aber keine Lust auf Jenkins? Überraschung: Mit Gitlab könnt ihr auch Deployments durchführen!

Schon lange sind die Zeiten vorbei, in denen man einfach via FTP Dateien vom heimischen Rechner auf den Kundenserver hochschieben sollte. Wenn ihr händisch mittels rsync oder git Quellcode auf Develop-, Staging- oder Produktiv-System schiebt, ist der Sprung zu einem automatischen Deployment gar nicht mehr so weit, wenn ihr Gitlab verwendet.

Warum solltet ihr automatische Deployments verwenden?

  • Ihr benötigt keine SSH-Zugangsdaten mehr
  • Ihr vergesst nie wieder, vor dem Deployment ein Backup zu machen
  • Ihr vergesst nie wieder, nach erfolgtem Deployment den Cache zu leeren
  • Ihr vergesst nie wieder, nach dem Deployment zu überprüfen, ob die Seite noch funktioniert 😉

Nachfolgend findet ihr ein Deployment via git, ohne weitere Zusätze. Nachdem das Prinzip verstanden ist, kann das Rezept auch für rsync, npm, composer oder jede andere Form von Transportmethode angepasst werden, und um beliebige andere schlaue Handgriffe erweitert werden.

Vorbereitung

Ein Git-Deployment sieht für euch normalerweise wie folgt aus:

  1. Ihr wechselt per SSH auf den Zielhost.
  2. Dort wechselt ihr in das Projektverzeichnis, in der per git clone das Projekt ausgecheckt war.
  3. Ihr führt ein git pull (plus ggf. weitere Kommandos durch).
  4. Ihr beendet die SSH-Verbindung.

Genau diese Handgriffe führt ein Gitlab-Deployment für euch automatisch durch, wenn bestimmte Bedingungen im Git erfüllt sind. In der Regel ist diese Bedingung ein Commit in einen bestimmten Branch, oder das Auftauchen eines neuen Tags.

Falls ihr der ganzen Automatik nicht traut, könnt ihr auch festlegen, dass das Deployment mit einem Knopf aus dem Webfrontend von Gitlab gestartet wird.

Auftritt Gitlab

Dreh- und Angelpunkt ist das installierte Gitlab-CI-Modul von Gitlab. Dies wird eurer lokale Gitlab-Installation hinzugefügt. Danach könnt ihr jedes eurer Projekt mit einer Datei namens gitlab-ci.yml ausstatten, in der ihr das Deployment beschreibt.

Meine Vorlage dafür sieht inzwischen wie folgt aus:

before_script:
  - apt-get update -y
  - apt-get install openssh-client -y
  - eval $(ssh-agent -s)
  - mkdir -p ~/.ssh
  - echo "$SSH_CONFIG" > ~/.ssh/config
  - echo "$SSH_KNOWNHOSTS" > ~/.ssh/known_hosts

# test:
#   Hier könnte Testing durchgeführt werden.
#   Das Deployment wird nur durchgeführt, wenn der Test erfolgreich ist.

deploy_production:
  stage: deploy
  environment:
    name: production
    url: ${PRODUCTION_URL}
  variables:
    ENVIRONMENT_PRIVATEKEY: ${PRODUCTION_PRIVATEKEY}
    ENVIRONMENT_HOST: ${CI_ENVIRONMENT_NAME}
    ENVIRONMENT_DIR: ${PRODUCTION_DIR}
    ENVIRONMENT_URL: ${PRODUCTION_URL}
  only:
    - master
    # - tags
  # when: manual
  script:
    - ssh-add <(echo "$ENVIRONMENT_PRIVATEKEY")
    - ssh $ENVIRONMENT_HOST "cd $ENVIRONMENT_DIR && git fetch && git checkout $CI_COMMIT_SHA ."

# deploy_staging:
# deploy_develop:
#   Hier könnten weitere Deployments für andere Zielsysteme stehen,
#   die man einfach von "deploy_production" kopieren kann

In dem Skript sind die Schritte für Building und Testing aktuell ausgeklammert, können von euch aber einfach aktiviert werden. Der eigentliche Clou ist hier, dass Gitlab mit einigen von euch hinterlegten Variablen in der letzten Zeile der Datei aufgefordert wird, eine SSH-Verbindung zu dem Zielhost aufzumachen und dort ein git checkout durchzuführen.

Die eigentliche Magie ist dabei, dass Gitlab exakt den aktuellen ausgewählten Commit auf dem betreffenden Zielsystem auscheckt. Mit der direktive only legt ihr z.B. einen bestimmten Branch oder ein Tag fest, mit when: manual eine manuelle Ausführung. Und im Falle eines verpfuschten Deployments, könnt ihr aus dem Gitlab-Webfrontend auch einen älteren Commit deployen lassen!

Das Deployment-Skript lässt sich natürlich um weitere Kommandos erweitern, die man auf dem Zielsystem ausführen möchte. Caches leeren, Composer ausführen oder Backups anlegen – all dies kann man hier problemlos hinzufügen. Und außerdem sehr ihr bereits, wie man z.B. für ein Develop- oder Staging-System das Skript erweitern könnt. Mehr Informationen über das Thema findet ihr in der offizielen Gitlab-CI-Dokumentation.

Variablen

Das obige Deployment-Skript ist ohne große Änderungen für viele Projekte verwendbar. Pro Projekt hinterlegt man in Gitlab nur noch ein paar Pipeline-Settings:

Variable Inhalt
SSH_CONFIG Hier muss eine SSH-Config z.B. für production hinterlegt werden. Siehe unten.
SSH_KNOWNHOSTS Hier muss das Ergebnis von ssh-keyscan [-p PORT] HOSTNAME für jeden der Hosts in SSH_CONFIG hinterlegt werden.
PRODUCTION_URL Die URL, unter der das Produktions-System erreichbar ist.
PRODUCTION_PRIVATEKEY Der SSH-Key, mit dem sich Gitlab zum Produktions-System verbinden darf.
PRODUCTION_DIR Der Pfad, in dem die Produktions-Installation liegt.

Die letzten drei Variablen kann man ggf. noch für DEVELOP_ und STAGING_ ausführen.

SSH-Config

Die Variable SSH_CONFIG benutzt einen kleinen Trick, um die für das Deployment notwendigen SSH-Zugangsdaten zu speichern: Eine sehr kompakte Art und Weise, um Serverdaten inklusive Ports, Benutzernamen und IPs aufzulisten, ist die SSH-Config. Für Gitlab kann man dieses Format ganz wunderbar verwenden, um die Server-Konfiguration für die Deployment-Server in einer Pipeline-Variable zu hinterlegen.

Host production
  Hostname 192.168.178.12
  Port 22
  User www-data

Zu beachten ist dabei, dass in der SSH-Config keine Passwörter gespeichert werden können. Das ist aber auch in Ordnung, da man sinnigerweise die Authentifizierung des Zugangs über einen SSH-Schlüssel durchführt.

Fazit

Nachdem all diese Handgriffe vollbracht sind, könnt ihr im Idealfall 30 Sekunden nach eurem Commit bereits euren Quellcode auf der jeweiligen Zielumgebung bewundern. Projektmanager und Tester werden es euch danken, jederzeit den aktuellsten Stand auf dem Entwicklungssystem vorzufinden – und ihr werdet es euch selber danken, beim Deployment nicht das Backup vergessen zu haben. 😉

Außerdem müsst ihr dem Rest des Teams nicht großartig erklären, wie Deployments jetzt funktionieren: Jedes Teammitglied, dass Git benutzt, kann ohne weiteres Vorwissen mustergültige Deployments hinlegen.