Zum Hauptinhalt springen

PHP-Anwendungen mit Deployer deployen

Deployer ist ein Deployment-Tool für PHP-Anwendungen. Diese Anleitung zeigt dir, wie du eine PHP-Anwendung in ein mittwald Cloud-Projekt mit Deployer deployen kannst.

Voraussetzungen

Für diese Anleitung gehen wir davon aus, dass du bereits ein PHP/Composer-Projekt in einem Git-Repository hast, das du deployen möchtest, und dass du mit den Grundlagen von Deployer vertraut bist (ansonsten sei auf die Getting Started-Anleitung verwiesen).

Eine Anwendung mit Deployer deployen

Die Anwendung auf der mittwald-Plattform erstellen

Zunächst musst du eine neue benutzerdefinierte Anwendung in einem mittwald Cloud-Projekt deiner Wahl erstellen. Dies kannst du über die mittwald mStudio-UI tun, oder alternativ über die CLI. In jedem Fall solltest du den Document Root der Anwendung auf den /current-Symlink (oder ein Unterverzeichnis davon) setzen, der von Deployer erstellt wird.

$ # use one of these:
$ mw app create php --document-root /current/public
$ mw app create node --document-root /current
$ mw app create static --document-root /current/public

Merke dir die ID der installierten Anwendung, da du sie später benötigen wirst. In den folgenden Beispielen werden wir uns auf diese Anwendungs-ID als <app-id> beziehen.

Das Deployment konfigurieren

Vollständig verwaltet: Das mittwald Deployer-Rezept verwenden

Der einfachste Weg, deine Anwendung in ein mittwald Cloud-Projekt zu deployen, ist die Verwendung des mittwald Deployer-Rezepts. Installiere das Rezept über Composer:

$ composer require --dev mittwald/deployer-recipes

Um ein Deployment-Ziel in deiner Anwendung zu definieren, füge das Rezept in deiner deploy.php-Datei ein, und verwende die mittwald_app-Funktion, um einen Host zu definieren:

require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/vendor/mittwald/deployer-recipes/recipes/deploy.php';

mittwald_app('<app-id>')
->set('public_path', '/');

Wenn du dep deploy ausführst, stelle sicher, dass eine MITTWALD_API_TOKEN-Umgebungsvariable gesetzt ist, die einen gültigen API-Token für die mittwald-API enthält.

Das Rezept wird automatisch die folgenden Dinge konfigurieren:

  • Der deploy_path wird auf den Installationspfad der Anwendung gesetzt.
  • Ein SSH-Benutzer wird für die Anwendung erstellt, und der remote_user wird auf diesen Benutzer gesetzt. Standardmäßig wird der in der ssh_copy_id-Variable konfigurierte SSH-Schlüssel für die Authentifizierung verwendet. Um ein anderes SSH-Schlüsselpaar zu verwenden, setze die mittwald_ssh_public_key- und mittwald_ssh_private_key-Variablen (alternativ setze die mittwald_ssh_public_key_file- und mittwald_ssh_private_key_file-Variablen auf den Pfad der entsprechenden Dateien).
  • Der PHP OPcache wird automatisch nach dem Deployment geleert.

Alternative: Ohne das mittwald Deployer-Rezept

Nachdem du die Anwendung erstellt hast, musst du den Installationspfad der Anwendung aus der mittwald Studio-UI oder über die CLI abrufen (in den folgenden Beispielen werden wir uns auf diesen Installationspfad als <app-installation-path> beziehen).

$ mw app get <app-id>

Verwende das Installationsverzeichnis der Anwendung als deploy_path in deiner deploy.php-Datei. Zum Beispiel:

host('ssh.fiestel.project.host') // you can determine your SSH host via the "mw project get" command
->set('remote_user', 'ssh-XXXXXX@<app-id>')
->set('deploy_path', '/html/<app-installation-path>');

Um den OPcache zu leeren, kannst du deine eigene Task-Definition zu deiner deploy.php-Datei hinzufügen, die nach der deploy:symlink-Phase ausgeführt werden soll. Das folgende Beispiel verwendet das CacheTool, um den OPcache für die Anwendung selektiv zu leeren:

task("opcache:flush", function (): void {
if (!test("[ -x cachetool.phar ]")) {
run("curl -sLO https://github.com/gordalina/cachetool/releases/latest/download/cachetool.phar");
run("chmod +x cachetool.phar");
}

run('./cachetool.phar opcache:invalidate:scripts --fcgi=127.0.0.1:9000 {{ deploy_path }}');
});

after("deploy:symlink", "opcache:flush");

Der Rest deiner Deployer-Konfiguration hängt von deinem Projekt ab und wird daher nicht von dieser Anleitung abgedeckt. Wenn du beispielsweise ein TYPO3-Projekt deployen möchtest, könntest du das TYPO3 Deployer-Rezept verwenden.

Fortgeschrittene Anleitungen

Das mittwald Deployer-Rezept bietet einige zusätzliche Funktionen, die für dein Deployment nützlich sein könnten.

In mehrere Umgebungen deployen

Womöglich möchtest du deine Anwendung in mehrere Umgebungen deployen, z.B. eine Staging- und eine Produktionsumgebung. Dazu kannst du mehrere Anwendungen auf der mittwald-Plattform erstellen:

$ mw app create php \
--document-root /current/public \
--site-title "My project (PROD)"
$ mw app create php \
--document-root /current/public \
--site-title "My project (STAGING)"

Im Anschluss kannst du mehrere Hosts in deiner deploy.php-Datei definieren, und die mittwald_app_id-Variable für jeden Host setzen:

mittwald_app('<prod-app-id>', hostname: 'mittwald-prod')
->set('branch', 'main');

mittwald_app('<staging-app-id>', hostname: 'mittwald-staging')
->set('branch', 'develop');

Domains konfigurieren

Das Rezept berücksichtigt die domain-Einstellung deiner Anwendung, und sucht automatisch nach einem passenden virtuellen Host, der für dein Projekt konfiguriert ist. Wenn ein passender virtueller Host gefunden wird, verlinkt das Rezept automatisch den virtuellen Host mit deiner Anwendung und ihrem Document Root. Du kannst die Domainnamen auch überschreiben, indem du die mittwald_domains-Variable setzt:

// default:
// set('mittwald_domains', ['{{domain}}']);
set('mittwald_domains', ['mittwald.example', 'www.mittwald.example']);

PHP-Version und andere Abhängigkeiten konfigurieren

Weiterhin kannst du die mittwald_app_dependencies-Variable setzen. Dieser Wert kann eine assoziative Liste von Systemsoftware-Namen und -Versionen enthalten, von denen deine Anwendung abhängt. Das Rezept installiert automatisch die erforderlichen Softwarepakete in der Laufzeitumgebung deiner Anwendung. Zum Beispiel:

set('mittwald_app_dependencies', [
'php' => '~8.2',
'composer' => '>=2.0',
]);

CI-Integration

Github Actions

Um dieses Rezept in einem Github-Actions-Workflow zu verwenden, solltest du zunächst die folgenden Secrets in den Einstellungen deines Repositorys konfigurieren:

  • MITTWALD_API_TOKEN sollte dein mittwald API-Token enthalten
  • MITTWALD_APP_ID sollte die ID der mittwald-Anwendung enthalten, in die du deployen möchtest.
  • MITTWALD_SSH_PRIVATE_KEY sollte den privaten Schlüssel des SSH-Schlüsselpaares enthalten, das für das Deployment verwendet werden soll.
  • MITTWALD_SSH_PUBLIC_KEY sollte den öffentlichen Schlüssel des SSH-Schlüsselpaares enthalten, das für das Deployment verwendet werden soll.

Im Anschluss kannst du den folgenden Workflow verwenden, um deine Anwendung zu deployen:

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2

- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest

- name: Deploy SSH keys
env:
MITTWALD_SSH_PRIVATE_KEY: ${{ secrets.MITTWALD_SSH_PRIVATE_KEY }}
MITTWALD_SSH_PUBLIC_KEY: ${{ secrets.MITTWALD_SSH_PUBLIC_KEY }}
run: |
mkdir -p .mw-deploy
echo "${MITTWALD_SSH_PRIVATE_KEY}" > .mw-deploy/id_rsa
echo "${MITTWALD_SSH_PUBLIC_KEY}" > .mw-deploy/id_rsa.pub
chmod 600 .mw-deploy/id_rsa*

# HINWEIS: Wenn du das mittwald deployer-Rezept NICHT verwendest, musst du hier
# den SSH-Hostschlüssel zur known_hosts-Datei hinzufügen.
# Siehe Abschnitt "Host key verification failed" weiter unten für weitere Informationen.

- name: Run deployer
run: |
./vendor/bin/dep deploy \
-o mittwald_app_id={{ secrets.MITTWALD_APP_ID }} \
-o mittwald_ssh_public_key_file=.mw-deploy/id_rsa.pub \
-o mittwald_ssh_private_key_file=.mw-deploy/id_rsa
env:
MITTWALD_API_TOKEN: ${{ secrets.MITTWALD_API_TOKEN }}

Gitlab CI

Dieser Gitlab-CI-Workflow verwendet dieselben Repository-Variablen wie das obige Github-Actions-Beispiel:

deploy:
image: php:8.2-cli
stage: deploy
before_script:
- wget https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer -O - -q | php -- --quiet
- apt-get update && apt-get install -y git openssh-client
- mkdir -p .mw-deploy
- echo "$MITTWALD_SSH_PRIVATE_KEY" > .mw-deploy/id_rsa
- echo "$MITTWALD_SSH_PUBLIC_KEY" > .mw-deploy/id_rsa.pub
- chmod 600 .mw-deploy/id_rsa*

# HINWEIS: Wenn du das mittwald deployer-Rezept NICHT verwendest, musst du hier
# den SSH-Hostschlüssel zur known_hosts-Datei hinzufügen.
# Siehe Abschnitt "Host key verification failed" weiter unten für weitere Informationen.

script:
- ./vendor/bin/dep deploy \ -o mittwald_app_id=$MITTWALD_APP_ID \ -o mittwald_ssh_public_key_file=.mw-deploy/id_rsa.pub \ -o mittwald_ssh_private_key_file=.mw-deploy/id_rsa
environment:
name: production

Häufige Probleme

unix_listener: path "[...]" too long for Unix domain socket.

Dieses Problem wird durch das SSH-Multiplexing-Feature von Deployer verursacht - oder genauer gesagt, durch den Namen des generierten UNIX-Sockets, der auf dem Hostnamen und dem Benutzernamen basiert und in einigen Fällen zu lang sein könnte. Es gibt verschiedene Workarounds für dieses Problem:

  • Deaktiviere das SSH-Multiplexing, indem du ssh_multiplexing in deiner deploy.php-Datei auf false setzt.

  • Definiere einen kürzeren Hostnamen in deiner SSH-Konfiguration (normalerweise ~/.ssh/config). Eine solche Konfiguration könnte so aussehen:

    Host fiestel
    Hostname ssh.fiestel.project.host
    User ssh-XXXXXX@<app-id>

Host key verification failed

Dieser Fehler wird dadurch verursacht, dass der SSH-Client den Hostschlüssel der mittwald-Plattform nicht verifizieren kann. Um dieses Problem zu beheben, kannst du den Hostschlüssel der mittwald-Plattform zu deiner known_hosts-Datei hinzufügen. Führe dazu den folgenden Befehl auf deinem lokalen Rechner aus (ersetze [hostname] durch den tatsächlichen SSH-Hostnamen):

$ ssh-keyscan [hostname] >> ~/.ssh/known-hosts

Alternativ kannst du deinen SSH-Client so konfigurieren, dass er unbekannte Hostschlüssel automatisch akzeptiert, indem du die StrictHostKeyChecking-Option in deiner SSH-Konfigurationsdatei auf accept-new setzt (normalerweise ~/.ssh/config).

$ echo "StrictHostKeyChecking accept-new" >> ~/.ssh/config

Aus dem Security-Blickwinkel ist es empfehlenswert, den Hostschlüssel im Voraus hinzuzufügen, wie im ersten Lösungsvorschlag beschrieben. In einer CI-Umgebung kannst du den Hostschlüssel statisch als Secret oder Umgebungsvariable hinzufügen, und dann vor dem Deployment in die known_hosts-Datei schreiben:

Konfiguriere zuerst den SSH-Hostschlüssel als Secret für dein Repository. Mit der GitHub CLI kannst du das mit dem folgenden Befehl tun (ersetze [hostname] durch deinen tatsächlichen SSH-Hostnamen):

$ ssh-keyscan [hostname] | gh secret set MITTWALD_SSH_HOST_KEY -a actions

Füge anschließend den folgenden Schritt zu deiner GitHub Actions-Pipeline hinzu:

- name: Deploy SSH host key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.MITTWALD_SSH_HOST_KEY }}" > ~/.ssh/known-hosts