PHP-Anwendungen bestehen normalerweise aus einem Webserver, einem relationalen Datenbanksystem und dem Sprachinterpreter selbst. In diesem Tutorial werden wir einen vollständigen PHP-Anwendungsstapel mit Docker nutzen. Dies ist ein ausführliches Tutorial, in dem wir Container für Nginx (den Webserver), MySQL (das Datenbanksystem) und PHP erstellen und orchestrieren.
In diesem Tutorial schreiben wir eine einfache Anwendung, die eine Liste von Städten aus einer Datenbank liest und auf einer Webseite anzeigt. Auf diese Weise demonstrieren wir eine grundlegende, aber funktionierende PHP-Anwendung.
In diesem Handbuch wird davon ausgegangen, dass Docker-CE bereits installiert ist und mindestens über minimale Docker-Kenntnisse verfügt. In diesem Fall können Sie die folgenden Tutorials lesen:
Konfiguration unserer Arbeitsumgebung
Eine Docker-basierte Anwendung im realen Leben besteht normalerweise aus mehreren Containern. Die manuelle Verwaltung kann leicht unübersichtlich und umständlich werden. Hier kommt Docker-Compose ins Spiel. Es hilft Ihnen, eine Reihe von Containern über eine einfache yamlKonfigurationsdatei zu verwalten .
Installieren Sie Docker-Compose.
curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
Erstellen Sie einen Ordner, in dem alle erforderlichen Dateien dieses Beispiels gespeichert sind cd. Von nun an ist dies unser Arbeitsverzeichnis und jeder Befehl wird in diesem Ordner ausgeführt und jeder Pfad wird relativ dazu referenziert. Auf diesen Ordner kann später als verwiesen werden WORKING_DIR.
mkdir ~/docker
cd ~/docker
Erstellen Sie nun drei weitere Ordner.
mkdir php nginx app
In dem phpOrdner erstellen wir unser benutzerdefiniertes PHP-Image, in dem nginxOrdner befinden sich die erforderlichen Dateien für unser benutzerdefiniertes Nginx-Image und in dem appOrdner werden der Quellcode und die Konfiguration unserer Beispielanwendung abgelegt.
Konfigurieren des PHP-Containers
In diesem Beispiel stellen wir php-fpmeine Verbindung zum Nginx-Webserver her. Wir werden das offizielle PHP-Basis-Image verwenden. Wir müssen jedoch auch einige Erweiterungen installieren und aktivieren, damit wir auf die Datenbank zugreifen können. phpErstellen Sie im Ordner eine Datei mit dem Namen Dockerfileund fügen Sie den folgenden Inhalt hinzu.
FROM php:7.1-fpm-alpine3.4
RUN apk update --no-cache \
    && apk add --no-cache $PHPIZE_DEPS \
    && apk add --no-cache mysql-dev \
    && docker-php-ext-install pdo pdo_mysql
Beachten Sie, dass wir die alpine Version des offiziellen PHP-Images verwenden. Alpine ist eine sehr kleine Verbreitung, die auf Container ausgerichtet ist, indem sie viel kleinere Stellflächen bietet. Beachten Sie auch die Verwendung des Befehls docker-php-ext-install. Das offizielle PHP-Image bietet diesen Befehl, um die Installation und Konfiguration von PHP-Erweiterungen zu vereinfachen.
Lassen Sie uns nun dieses Docker-Image erstellen, indem Sie Folgendes (in unserem WORKING_DIR) ausgeben :
docker build -t vultr-php php/
Die docker-compose.ymlDatei
Wie bereits erwähnt, docker-composekönnen Sie eine Reihe von Containern über eine einfache Konfigurationsdatei verwalten. Diese Konfigurationsdatei wird normalerweise benannt docker-compose.yml. Erstellen Sie diese Datei im appOrdner.
touch app/docker-compose.yml
Fügen Sie nun den folgenden Inhalt in diese Datei ein.
version: '2'
services:
  php:
    image: vultr-php
    volumes:
      - ./:/app
    working_dir: /app
Wir werden diese Syntax erklären. Beachten Sie zuerst die erste Zeile.
version: '2'
Dies gibt die Version der verwendeten docker-compose.ymlKonfigurationsdatei an. In der nächsten Zeile werden die Dienste oder mit anderen Worten die zu bereitstellenden Container angegeben.
services:
  php:
    image: vultr-php
    volumes:
      - ./:/app
    working_dir: /app
Beachten Sie, dass jeder Dienst einen bestimmten Schlüssel im servicesBlock hat. Der hier angegebene Name wird später verwendet, um auf diesen bestimmten Container zu verweisen. Beachten Sie auch, dass phpwir in der Konfiguration das Image definieren, das zum Ausführen des Containers verwendet wird (dies ist das Image, das wir zuvor erstellt haben). Wir definieren auch eine Volumenzuordnung.
volumes:
  - ./:/app
Dies weist docker-composean, das aktuelle Verzeichnis ( ./) dem /appVerzeichnis im Container zuzuordnen . In der letzten Zeile wird der /appOrdner im Container als Arbeitsverzeichnis festgelegt. Dies bedeutet, dass in diesem Ordner standardmäßig alle zukünftigen Befehle in einem Container ausgeführt werden.
Wir können jetzt unsere Container orchestrieren.
cd ~/docker/app
docker-compose up -d
Sie können den folgenden Befehl ausführen, um sicherzustellen, dass der PHP-Container ausgeführt wurde:
docker ps
So führen Sie Befehle in den Containern aus
Noch im appOrdner können wir mit Hilfe des docker-composeBefehls jeden Befehl in einem definierten Service-Container ausführen .
docker-compose exec [service] [command]
Der [service]Platzhalter bezieht sich auf den Serviceschlüssel. In unserem Fall war dies php. Lassen Sie uns einen Befehl im Container ausführen, um unsere PHP-Version zu überprüfen.
docker-compose exec php php -v
Sie sehen die folgende Ausgabe.
PHP 7.1.14 (cli) (built: Feb  7 2018 00:40:45) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
Konfigurieren des Nginx-Containers
Genau wie beim PHP-Container müssen wir ein benutzerdefiniertes Image für den Webserver erstellen. In diesem Fall müssen wir jedoch nur eine Konfiguration für unsere bereitstellen virtual host. Stellen Sie sicher , Sie sind in unseren WORKING_DIRund erstellen Dockerfileinnerhalb des nginxOrdners:
cd ~/docker
touch nginx/Dockerfile
Fügen Sie nun folgenden Inhalt ein Dockerfile:
FROM nginx:1.13.8-alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf
Wir verwenden das Standard-Nginx-Bild, das auf Alpine basiert. In diese Docker-Datei kopieren wir einfach eine Konfigurationsdatei in unser Anwendungssetup. Erstellen Sie vor dem Erstellen dieses Images eine Konfigurationsdatei.
touch nginx/default.conf
Füllen Sie es nun mit diesem Inhalt.
server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    root /app;
    index index.php;
    #server_name server_domain_or_IP;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}
Beachten Sie, dass fastcgi_pass php:9000wir in der Zeile den PHP-Container anhand seines Namens im serviceBlock der docker-compose.ymlKonfigurationsdatei referenzieren . Erstellt intern docker-composeein Netzwerk und weist jedem der definierten Dienste den Dienstnamen als Hostnamen zu. Wir können jetzt das Nginx-Image erstellen.
docker build -t vultr-nginx nginx/
Aktualisierung docker-compose.yml
Aktualisieren Sie nun die app/docker-compose.ymlDatei.
version: '2'
services:
  php:
    image: vultr-php
    volumes:
      - ./:/app
    working_dir: /app
  web:
    image: vultr-nginx
    volumes:
      - ./:/app
    depends_on:
      - php
    ports:
      - 80:80
Wir haben nur einen neuen Service hinzugefügt. Die Konfiguration ist bis auf die folgenden nahezu identisch.
depends_on:
  - php
ports:
  - 80:80
Sobald der Nginx-Container eine vollständige Initialisierung des PHP-Dienstes benötigt, erzwingen wir diese Anforderung in der depends_onOption. Der portsKonfigurationsschlüssel ordnet einen Host-Port einem Container-Port zu. Hier ordnen wir den Port 80im Host dem Port 80im Container zu.
Erstellen Sie nun eine Datei mit dem Namen index.phpim appOrdner und fügen Sie Folgendes ein.
<?php phpinfo();
Stellen Sie sicher, dass der Port 80über Ihre Firewall zugänglich ist, und führen Sie die folgenden Schritte aus.
cd ~/docker/app
docker-compose up -d
Überprüfen Sie erneut, ob der Dienst aktiv ist.
docker ps
Öffnen Sie einen Browser und greifen Sie zu [vultr-instance-ip]. Sie können die IP-Adresse Ihrer Vultr-Instanz ermitteln, indem Sie Folgendes ausführen.
hostname -I
Sie sehen die PHP-Infoseite.
Konfigurieren des MySQL-Containers
Mit dem offiziellen MySQL-Image können Sie den Container über einfache Umgebungsvariablen konfigurieren. Dies kann mit einer environmentOption innerhalb der Serviceblockdefinition erfolgen. Aktualisieren Sie die ~/docker/app/docker-compose.ymlDatei wie folgt.
version: '2'
services:
  php:
    image: vultr-php
    volumes:
      - ./:/app
    working_dir: /app
  web:
    image: vultr-nginx
    volumes:
      - ./:/app
    depends_on:
      - php
    ports:
      - 80:80
  mysql:
    image: mysql:5.7.21
    volumes:
      - ./:/app
      - dbdata:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=world
      - MYSQL_ROOT_PASSWORD=root
    working_dir: /app
volumes:
  dbdata:
Jetzt haben wir einen neuen Dienst für die Datenbank definiert. Beachten Sie die Linie dbdata:/var/lib/mysql. Dadurch wird der Pfad auf dem Container /var/lib/mysqlauf einem von Docker verwalteten persistenten Volume bereitgestellt. Auf diese Weise bleiben die Datenbankdaten bestehen, nachdem der Container entfernt wurde. Dieses Volume muss in einem Block der obersten Ebene definiert werden, wie Sie am Ende der Datei sehen können.
Laden Sie vor dem Orchestrieren unserer neuen Konfiguration eine MySQL-Beispieldatenbank herunter. Die offizielle MySQL-Dokumentation enthält einige Beispieldatenbanken. Wir werden die bekannte Weltdatenbank verwenden. Diese Datenbank enthält eine Liste der Länder und Städte. Führen Sie die folgenden Schritte in unserem App-Ordner aus, um dieses Beispiel herunterzuladen.
curl -L http://downloads.mysql.com/docs/world.sql.gz -o world.sql.gz
gunzip world.sql.gz
Jetzt können wir unsere Container orchestrieren.
docker-compose up -d
Wie Sie vielleicht bereits bemerkt haben, docker-compose upstartet der Befehl nur die Container, die noch nicht gestartet wurden. Es überprüft die Unterschiede zwischen Ihrer docker-compose.ymlDatei und der aktuellen Konfiguration der ausgeführten Container.
Überprüfen Sie noch einmal, ob der MySQL-Container gestartet wurde.
docker ps
Füllen Sie nun die Weltdatenbank.
docker-compose exec -T mysql mysql -uroot -proot world < world.sql
Sie können überprüfen, ob die Datenbank gefüllt wurde, indem Sie Daten direkt aus der Datenbank auswählen. Greifen Sie zuerst auf die MySQL-Eingabeaufforderung im Container zu.
docker-compose exec mysql mysql -uroot -proot world
Führen Sie in der MySQL-Eingabeaufforderung Folgendes aus.
select * from city limit 10;
Sie sehen eine Liste der Städte. Beenden Sie nun die MySQL-Eingabeaufforderung.
mysql> exit
Erstellen unserer Anwendung
Nachdem alle erforderlichen Container betriebsbereit sind, können wir uns auf unsere Beispielanwendung konzentrieren. Aktualisieren Sie die app/index.phpDatei wie folgt.
<?php
$pdo = new PDO('mysql:host=mysql;dbname=world;charset=utf8', 'root', 'root');
$stmt = $pdo->prepare("
    select city.Name, city.District, country.Name as Country, city.Population
    from city
    left join country on city.CountryCode = country.Code
    order by Population desc
    limit 10
");
$stmt->execute();
$cities = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Vultr Rocks!</title>
</head>
<body>
    <h2>Most Populous Cities In The World</h2>
    <table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Country</th>
            <th>District</th>
            <th>Population</th>
        </tr>
    </thead>
    <tbody>
        <?php foreach($cities as $city): ?>
            <tr>
                <td><?=$city['Name']?></td>
                <td><?=$city['Country']?></td>
                <td><?=$city['District']?></td>
                <td><?=number_format($city['Population'], 0)?></td>
            </tr>
        <?php endforeach ?>
    </tbody>
    </table>
</body>
</html>
Wenn Sie [vultr-instance-ip]über einen Webbrowser darauf zugreifen , wird eine Liste der bevölkerungsreichsten Städte der Welt angezeigt. Herzlichen Glückwunsch, Sie haben eine voll funktionsfähige PHP-Anwendung mit Docker bereitgestellt.
Fazit
In diesem Tutorial habe ich Schritt für Schritt gezeigt, wie eine voll funktionsfähige PHP-Anwendung konfiguriert wird. Wir haben benutzerdefinierte Images für PHP und Nginx erstellt und Docker-Compose so konfiguriert, dass unsere Container orchestriert werden. Obwohl dieses Setup sehr einfach und einfach ist, spiegelt es ein reales Szenario wider.
In diesem Handbuch haben wir unsere Bilder lokal erstellt und markiert. Für eine flexiblere Einrichtung können Sie diese Images in eine Docker-Registrierung übertragen . Sie können auf die offizielle Docker-Registrierung zugreifen oder sogar Ihre eigene Docker-Registrierung einrichten. In jedem Fall können Sie so Ihre Bilder auf einem Host erstellen und auf einem anderen verwenden.
Für eine detailliertere Verwendung von docker-composesollten Sie sich auf die offizielle Dokumentation beziehen .
Abhängig von Ihren Anwendungsanforderungen und dem von Ihnen verwendeten PHP-Framework möchten Sie möglicherweise weitere Erweiterungen hinzufügen. Dies kann einfach durch Ändern des Dockerfilezum Erstellen unseres benutzerdefinierten PHP-Images verwendeten Bilds erfolgen. Bei einigen Erweiterungen müssen jedoch zusätzliche Abhängigkeiten im Container installiert werden. Sie sollten sich auf die Liste der Erweiterungen in der offiziellen PHP-Dokumentation beziehen, um die grundlegenden Anforderungen jeder Erweiterung zu überprüfen.