Mit GitLab CI automatisch auf Staging- und Produktiv-Server deployen

Ich habe kürzlich angefangen, mich mit Continuous Integration (CI) zu beschäftigen. Damit sind unterschiedliche automatische Aktionen nach einem Push in ein Versionsverwaltungs-Repo möglich, wie etwa das Testen des Codes oder auch das Deployment auf einen Server. Hier zeige ich euch, wie ein Deployment-Prozess von Gitlab.com auf einen Staging- und Produktiv-Server aussehen kann.

Im Gegensatz zu GitHub hat GitLab die Möglichkeit zur CI direkt integriert, die sogar im kostenlosen Plan genutzt werden kann. Das Theme meiner Website wird mit Git versioniert. Es gibt eine lokale Version, eine auf einem Staging-Server und die hier auf dem Prodkutiv-Server. Über GitLab CI kann ich das Theme durch Pushen eines Commits automatisch auf den Staging- oder Produktiv-Server übertragen – je nachdem, ob der Push an den staging– oder master-Branch geht. So muss ich keine Dateien per SFTP auf unterschiedliche Server laden, sondern kann alles über Git regeln.

Um in einem kostenlosen GitLab-Account die CI zu nutzen, müsst ihr eigentlich nur eine .gitlab-ci.yml erstellen und auf die oberste Ebene des Git-Repos legen (bei einer eigenen GitLab-Instanz müsst ihr vielleicht erst Runner installieren). Darin steht dann, was GitLab CI machen soll, wenn ein Push ankommt. Wir möchten folgende Dinge umsetzen:

Bei einem Push im staging-Branch

  1. Verbinde dich mit dem Staging-Server.
  2. Erstelle einen temporären Theme-Ordner.
  3. Kopiere die Theme-Dateien aus dem Git-Repo in den temporären Ordner auf dem Staging-System.
  4. Verschiebe das bis dahin aktuelle Theme in einen weiteren temporären Ordner.
  5. Verschiebe den neuen aktuellen Stand in den Theme-Ordner.
  6. Lösche den temporären Ordner mit den alten Theme-Dateien.

Dieser Umweg über temporäre Ordner ist aus der GitLab-Dokumentation entnommen und sorgt dafür, dass immer ein funktionierendes Theme auf dem Server ist. Andernfalls wäre für eine kurze Zeit der Theme-Ordner nicht vorhanden.

Bei einem Push im master-Branch

Hier sieht der Vorgang gleich aus wie bei dem Staging-Server, nur dass sich mit dem Produktiv-Server verbunden wird.

Die .gitlab-ci.yml für das Deployment erstellen

In der .gitlab-ci.yml stehen wie bereits erwähnt die Schritte, die von der CI ausgeführt werden. Die Aufgaben können in unterschiedliche Jobs aufgeteilt werden, die in unterschiedlichen Stages laufen können. Wir haben nur eine deploy-Stage und die beiden Jobs deploy_staging und deploy_production. Der Anfang der Datei sieht so aus:

stages:
  - deploy

deploy_staging:
  stage: deploy
  image: tetraweb/php:7.1
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - mkdir -p ~/.ssh
    - eval $(ssh-agent -s)
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
    - ssh-add <(echo "$STAGING_PRIVATE_KEY")
    - apt-get install rsync
  script:
    - ssh -p22 user@staging.example.com "mkdir -p /html/wp-content/themes/_tmp"
    - rsync -rav -e ssh --exclude='.git/' --exclude='.gitlab-ci.yml' --delete-excluded ./ user@staging.example.com:/html/wp-content/themes/_tmp
    - ssh -p22 user@staging.example.com "mv /html/wp-content/themes/fbn /html/wp-content/themes/_old && mv /html/wp-content/themes/_tmp /html/wp-content/themes/fbn"
    - ssh -p22 user@staging.example.com "rm -rf /html/wp-content/themes/_old"
  only:
    - staging

Zunächst wird die deploy-Stage definiert und anschließend der Job deploy_staging, der sich um das Deployment auf den Staging-Server kümmert. Dieser Job gehört zu deploy und wir nutzen zum Ausführen das Docker-Image tetraweb/php:7.1. Über before_script können wir Aufgaben vor Durchführung des Skripts ausführen – in unserem Fall die Vorbereitung für eine SSH-Verbindung und die Installation des rsync-Pakets. Die Schritte für SSH sind wieder aus der GitLab-Doku. Damit es funktioniert, müsst ihr in GitLab eine Variable STAGING_PRIVATE_KEY anlegen, die den privaten Key des SSH-Schlüssels enthält.

Im script-Teil des Jobs verbinden wir uns per SSH mit dem Staging-Server und erstellen den Ordner _tmp im Theme-Verzeichnis, falls noch nicht vorhanden. Danach übertragen wir per rsync die Daten aus dem Git-Repo in diesen Ordner. Im Anschluss wird das Verschieben der Ordner vorgenommen. Über only können wir einen Branch angeben, für den dieser Job gelten soll – andernfalls würde der Job bei jedem Push ausgeführt, da die Datei ja auch im master-Branch liegt.

Letztlich sieht der Job für das Deployment zum Produktiv-Server fast genauso aus (der Code wird einfach unter dem anderen Job eingefügt):

deploy_production:
  stage: deploy
  image: tetraweb/php:7.1
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - mkdir -p ~/.ssh
    - eval $(ssh-agent -s)
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
    - ssh-add <(echo "$STAGING_PRIVATE_KEY")
    - apt-get install rsync
  script:
    - ssh -p22 user@example.com "mkdir -p /html/wp-content/themes/_tmp"
    - rsync -rav -e ssh --exclude='.git/' --exclude='.gitlab-ci.yml' --delete-excluded ./ user@example.com:/html/wp-content/themes/_tmp
    - ssh -p22 user@example.com "mv /html/wp-content/themes/fbn /html/wp-content/themes/_old && mv /html/wp-content/themes/_tmp /html/wp-content/themes/fbn"
    - ssh -p22 user@example.com "rm -rf /html/wp-content/themes/_old"
  only:
    - master

Da der before_script-Teil in diesem Beispiel für beide Jobs genau gleich ist, könnte er auch aus den Jobs rausgezogen und global eingefügt werden (auf dieselbe Ebene wie die Angabe von stages).

Und damit wären wir auch schon am Ende und können in Zukunft das Deployment mit Git-Aktionen vornehmen.

Schreib einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.