Wie man Laravel mit Docker Compose auf Ubuntu 22.04 installiert und einrichtet
Einführung
Eine Anwendung zu containerisieren bezieht sich auf den Prozess, eine Anwendung und ihre Komponenten so anzupassen, dass sie in leichten Umgebungen, die als Container bekannt sind, ausgeführt werden kann. Solche Umgebungen sind isoliert und austauschbar und können für die Entwicklung, das Testen und die Bereitstellung von Anwendungen in der Produktion genutzt werden.
In diesem Leitfaden verwenden wir Docker Compose, um eine Laravel-Anwendung für die Entwicklung zu containerisieren. Nach Abschluss haben Sie eine Demo-Laravel-Anwendung, die auf drei separaten Service-Containern läuft:
- Ein
app-Dienst, der PHP7.4-FPM ausführt; - Ein
db-Dienst, der MySQL 8.0 ausführt; - Ein
nginx-Dienst, der denapp-Dienst verwendet, um PHP-Code zu parsen, bevor die Laravel-Anwendung dem Endbenutzer bereitgestellt wird.
Um einen reibungslosen Entwicklungsprozess zu ermöglichen und das Debuggen von Anwendungen zu erleichtern, werden wir die Anwendungsdateien mithilfe gemeinsamer Volumes synchron halten. Außerdem werden wir sehen, wie man docker compose exec-Befehle verwendet, um Composer und Artisan im app-Container auszuführen.
Stellen Sie Ihre Frontend-Anwendungen von GitHub mit der App-Plattform von Linux-Console.net bereit. Lassen Sie Linux-Console.net die Skalierung Ihrer App übernehmen.
Wichtige Erkenntnisse:
- Containerisierung macht die Entwicklung vorhersehbar: Das Ausführen von Laravel in Docker sorgt für konsistente Umgebungen auf verschiedenen Rechnern, beseitigt das Problem "Es funktioniert auf meinem Computer" und erleichtert die Zusammenarbeit.
- Die Trennung von Diensten verbessert die Wartbarkeit: Das Aufteilen von PHP, MySQL und Nginx in separate Container hilft, Probleme zu isolieren, vereinfacht Updates und spiegelt reale Produktionsumgebungen wider.
- Umgebungsvariablen sind zentral für eine flexible Konfiguration: Die Verwendung einer
.env-Datei ermöglicht es Entwicklern, Datenbankanmeldeinformationen und andere Einstellungen zu ändern, ohne den Anwendungscode zu berühren. - Benutzerdefinierte Docker-Images verbessern Kontrolle und Sicherheit: Wenn Sie Ihr eigenes PHP-Image erstellen, stellen Sie sicher, dass Sie nur das installieren, was Ihr Projekt benötigt, und halten die Umgebung leichtgewichtig und sicher.
- Dateiberechtigungen müssen mit den Container-Benutzern übereinstimmen: Das Festlegen der richtigen Eigentumsrechte und Berechtigungen für Laravels beschreibbare Verzeichnisse verhindert Laufzeitfehler und unterstützt eine reibungslose lokale Entwicklung.
- Die Verwendung von Override-Dateien unterstützt mehrere Umgebungen:
docker-compose.override.ymlermöglicht lokale Anpassungen – wie Live-Reloading – ohne die Produktionskonfigurationen zu verändern. Dies hält Entwicklung und Deployment sauber getrennt. - Fehlerbehebung beginnt mit dem Verständnis des Containerverhaltens: Zu wissen, wie man Protokolle einsehen, laufende Dienste überprüfen und die Konnektivität testen kann, ist entscheidend, um die meisten Probleme in containerisierten Umgebungen schnell zu lösen.
- Ein Docker-basiertes Setup passt sich Ihrem Workflow an: Sobald es erstellt ist, kann dieselbe Konfiguration lokale, Staging- oder Produktionsumgebungen unterstützen und schafft eine stabile, wiederverwendbare Grundlage für zukünftige Laravel-Projekte.
Voraussetzungen
- Zugang zu einer lokalen Ubuntu-Maschine oder einem Entwicklungsserver als Nicht-Root-Benutzer mit Sudo-Rechten. Wenn Sie einen Remote-Server verwenden, wird empfohlen, eine aktive Firewall zu installieren. Um diese einzurichten, lesen Sie bitte unseren Leitfaden zur Ersteinrichtung eines Servers für Ubuntu.
- Docker auf Ihrem Server installiert, nach den Schritten 1 und 2 von 'So installieren und verwenden Sie Docker auf Ubuntu'.
- Docker Compose auf Ihrem Server installiert, gemäß Schritt 1 von Wie man Docker Compose auf Ubuntu installiert und verwendet.
Schritt 1 — Die Demoanwendung erhalten
Um loszulegen, werden wir die Demo-Laravel-Anwendung aus ihrem Github-Repository abrufen. Wir interessieren uns für den tutorial-01-Branch, der die grundlegende Laravel-Anwendung enthält, die wir im Leitfaden "So installieren und konfigurieren Sie Laravel mit Nginx auf Ubuntu 22.04 (LEMP)" erstellt haben.
Um den Anwendungscode zu erhalten, der mit diesem Tutorial kompatibel ist, laden Sie die Version tutorial-1.0.1 in Ihr Home-Verzeichnis herunter mit:
cd ~
curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-1.0.1.zip -o travellist.zipWir benötigen den Befehl unzip, um den Anwendungscode zu entpacken. Falls Sie dieses Paket bisher nicht installiert haben, tun Sie dies jetzt mit:
sudo apt update
sudo apt install unzipEntpacken Sie nun den Inhalt der Anwendung und benennen Sie das entpackte Verzeichnis für einen einfacheren Zugriff um:
unzip travellist.zip
mv travellist-laravel-demo-tutorial-1.0.1 travellist-demoNavigieren Sie zum Verzeichnis travellist-demo:
cd travellist-demoIm nächsten Schritt erstellen wir eine .env-Konfigurationsdatei, um die Anwendung einzurichten.
Schritt 2 — Einrichten der .env-Datei der Anwendung
Die Laravel-Konfigurationsdateien befinden sich in einem Verzeichnis namens config im Stammverzeichnis der Anwendung. Zusätzlich wird eine .env-Datei verwendet, um umgebungsabhängige Konfigurationen festzulegen, wie Zugangsdaten und alle Informationen, die zwischen den Deployments variieren könnten. Diese Datei ist nicht in der Versionskontrolle enthalten.
Warnung: Die Konfigurationsdatei der Umgebung enthält sensible Informationen über Ihren Server, einschließlich Datenbankzugangsdaten und Sicherheitsschlüsseln. Aus diesem Grund sollten Sie diese Datei niemals öffentlich teilen.
Die in der .env-Datei enthaltenen Werte haben Vorrang vor den Werten, die in den regulären Konfigurationsdateien im config-Verzeichnis festgelegt sind. Jede Installation in einer neuen Umgebung erfordert eine maßgeschneiderte Umgebungsdatei, um Dinge wie Datenbankverbindungseinstellungen, Debug-Optionen, die Anwendungs-URL und andere Punkte zu definieren, die je nach Umgebung, in der die Anwendung läuft, variieren können.
Wir werden nun eine neue .env-Datei erstellen, um die Konfigurationsoptionen für die Entwicklungsumgebung, die wir einrichten, anzupassen. Laravel wird mit einer Beispiel-.env-Datei geliefert, die wir kopieren können, um unsere eigene zu erstellen:
cp .env.example .envÖffnen Sie diese Datei mit nano oder dem Texteditor Ihrer Wahl:
nano .envDie aktuelle .env-Datei der travellist-Demoanwendung enthält Einstellungen zur Verwendung einer lokalen MySQL-Datenbank, mit 127.0.0.1 als Datenbankhost. Wir müssen die Variable DB_HOST aktualisieren, damit sie auf den Datenbankdienst zeigt, den wir in unserer Docker-Umgebung erstellen werden. In diesem Leitfaden nennen wir unseren Datenbankdienst db. Ersetzen Sie den angegebenen Wert von DB_HOST durch den Namen des Datenbankdienstes:
APP_NAME=Travellist
APP_ENV=dev
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=travellist
DB_USERNAME=travellist_user
DB_PASSWORD=password
...Du kannst auch gerne den Datenbanknamen, Benutzernamen und das Passwort ändern, wenn du möchtest. Diese Variablen werden in einem späteren Schritt verwendet, wenn wir die docker-compose.yml-Datei einrichten, um unsere Dienste zu konfigurieren.
Speichere die Datei, wenn du mit dem Bearbeiten fertig bist. Wenn du nano verwendet hast, kannst du das tun, indem du Ctrl+x drückst, dann Y und Enter, um zu bestätigen.
Schritt 3 – Einrichten der Dockerfile der Anwendung
Obwohl sowohl unsere MySQL- als auch unsere Nginx-Dienste auf Standard-Images aus dem Docker Hub basieren werden, müssen wir trotzdem ein eigenes Image für den Anwendungs-Container erstellen. Dafür werden wir ein neues Dockerfile erstellen.
Unser Travellist-Image wird auf dem offiziellen PHP-Image php:7.4-fpm von Docker Hub basieren. Auf dieser grundlegenden PHP-FPM-Umgebung werden wir einige zusätzliche PHP-Module und das Abhängigkeitsverwaltungstool Composer installieren.
Wir werden auch einen neuen Systembenutzer erstellen; dies ist notwendig, um artisan und composer-Befehle während der Anwendungsentwicklung auszuführen. Die Einstellung uid stellt sicher, dass der Benutzer im Container dieselbe UID wie Ihr Systembenutzer auf Ihrem Host-Rechner, auf dem Docker läuft, hat. Auf diese Weise werden alle von diesen Befehlen erstellten Dateien mit den richtigen Berechtigungen auf dem Host repliziert. Das bedeutet auch, dass Sie Ihren bevorzugten Code-Editor auf dem Host-Rechner verwenden können, um die Anwendung zu entwickeln, die innerhalb der Container läuft.
Erstelle eine neue Dockerfile mit:
nano DockerfileKopieren Sie die folgenden Inhalte in Ihre Dockerfile:
FROM php:7.4-fpm
# Arguments defined in docker-compose.yml
ARG user
ARG uid
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
chown -R $user:$user /home/$user
# Set working directory
WORKDIR /var/www
USER $user
Vergiss nicht, die Datei zu speichern, wenn du fertig bist.
Unser Dockerfile beginnt damit, dass wir das Basis-Image definieren, das wir verwenden: php:7.4-fpm.
Nach der Installation von Systempaketen und PHP-Erweiterungen installieren wir Composer, indem wir die composer-Executable aus dem neuesten offiziellen Image in unser eigenes Anwendungs-Image kopieren.
Ein neuer Systembenutzer wird dann erstellt und eingerichtet, wobei die am Anfang des Dockerfiles deklarierten Argumente user und uid verwendet werden. Diese Werte werden während des Build-Vorgangs von Docker Compose eingefügt.
Schließlich setzen wir das Standardarbeitsverzeichnis auf /var/www und wechseln zu dem neu erstellten Benutzer. Dadurch wird sichergestellt, dass Sie sich als regulärer Benutzer anmelden und sich im richtigen Verzeichnis befinden, wenn Sie composer- und artisan-Befehle im Anwendungscontainer ausführen.
Schritt 4 — Einrichten der Nginx-Konfiguration und der Datenbank-Dump-Dateien
Beim Erstellen von Entwicklungsumgebungen mit Docker Compose ist es oft notwendig, Konfigurations- oder Initialisierungsdateien mit Service-Containern zu teilen, um diese Dienste einzurichten oder zu starten. Diese Vorgehensweise erleichtert es, Änderungen an Konfigurationsdateien vorzunehmen, um Ihre Umgebung während der Entwicklung der Anwendung zu optimieren.
Wir werden nun einen Ordner mit Dateien einrichten, die zur Konfiguration und Initialisierung unserer Service-Container verwendet werden.
Um Nginx einzurichten, teilen wir eine travellist.conf-Datei, die konfiguriert, wie die Anwendung bereitgestellt wird. Erstellen Sie den Ordner docker-compose/nginx mit:
mkdir -p docker-compose/nginxÖffnen Sie eine neue Datei mit dem Namen travellist.conf in diesem Verzeichnis:
nano docker-compose/nginx/travellist.confKopiere die folgende Nginx-Konfiguration in diese Datei:
server {
listen 80;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}Diese Datei konfiguriert Nginx so, dass es auf Port 80 hört und index.php als Standardindexseite verwendet. Sie setzt das Dokumentenverzeichnis auf /var/www/public und konfiguriert dann Nginx so, dass es den app-Dienst auf Port 9000 verwendet, um *.php-Dateien zu verarbeiten.
Speichern Sie die Datei und schließen Sie sie, wenn Sie mit der Bearbeitung fertig sind.
Um die MySQL-Datenbank einzurichten, werden wir einen Datenbank-Dump bereitstellen, der beim Starten des Containers importiert wird. Dies ist eine Funktion, die das MySQL 8.0-Image bietet, das wir in diesem Container verwenden werden.
Erstellen Sie einen neuen Ordner für Ihre MySQL-Initialisierungsdateien innerhalb des docker-compose-Ordners:
mkdir docker-compose/mysqlÖffnen Sie eine neue .sql-Datei:
nano docker-compose/mysql/init_db.sqlDer folgende MySQL-Dump basiert auf der Datenbank, die wir in unserem Laravel-auf-LEMP-Guide eingerichtet haben. Er wird eine neue Tabelle mit dem Namen places erstellen. Anschließend wird die Tabelle mit einer Reihe von Beispielorten gefüllt.
Fügen Sie den folgenden Code in die Datei ein:
DROP TABLE IF EXISTS `places`;
CREATE TABLE `places` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`visited` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `places` (name, visited) VALUES ('Berlin',0),('Budapest',0),('Cincinnati',1),('Denver',0),('Helsinki',0),('Lisbon',0),('Moscow',1),('Nairobi',0),('Oslo',1),('Rio',0),('Tokyo',0);Die places-Tabelle enthält drei Felder: id, name und visited. Das visited-Feld ist ein Kennzeichen, das verwendet wird, um die Orte zu identifizieren, die noch besucht werden müssen. Du kannst die Beispielorte gerne ändern oder neue hinzufügen. Speichere die Datei und schließe sie, wenn du fertig bist.
Wir haben die Einrichtung der Dockerfile der Anwendung und der Konfigurationsdateien für die Dienste abgeschlossen. Als Nächstes richten wir Docker Compose ein, um diese Dateien beim Erstellen unserer Dienste zu verwenden.
Schritt 5 — Erstellen einer Multi-Container-Umgebung mit Docker Compose
Docker Compose ermöglicht es Ihnen, Multi-Container-Umgebungen für Anwendungen, die auf Docker laufen, zu erstellen. Es verwendet Servicedefinitionen, um vollständig anpassbare Umgebungen mit mehreren Containern zu erstellen, die Netzwerke und Datenträger gemeinsam nutzen können. Dies ermöglicht eine nahtlose Integration zwischen den Anwendungskomponenten.
Um unsere Dienstdefinitionen einzurichten, erstellen wir eine neue Datei mit dem Namen docker-compose.yml. Üblicherweise befindet sich diese Datei im Stammverzeichnis des Anwendungsordners und definiert Ihre containerisierte Umgebung, einschließlich der Basis-Images, die Sie zum Erstellen Ihrer Container verwenden werden, und wie Ihre Dienste miteinander interagieren.
Wir werden drei verschiedene Dienste in unserer docker-compose.yml-Datei definieren: app, db und nginx.
Der app-Dienst erstellt ein Image namens travellist, basierend auf dem Dockerfile, das wir zuvor erstellt haben. Der von diesem Dienst definierte Container wird einen php-fpm-Server ausführen, um PHP-Code zu verarbeiten und die Ergebnisse an den nginx-Dienst zurückzusenden, der in einem separaten Container läuft. Der mysql-Dienst definiert einen Container, der einen MySQL-8.0-Server ausführt. Unsere Dienste werden ein Bridge-Netzwerk mit dem Namen travellist teilen.
Die Anwendungsdateien werden auf beiden Diensten app und nginx über Bind-Mounts synchronisiert. Bind-Mounts sind in Entwicklungsumgebungen nützlich, da sie eine leistungsstarke bidirektionale Synchronisation zwischen Host-Rechner und Containern ermöglichen.
Erstellen Sie eine neue docker-compose.yml-Datei im Stammverzeichnis des Anwendungsordners:
nano docker-compose.ymlEine typische docker-compose.yml-Datei beginnt mit einer Versionsdefinition, gefolgt von einem services-Knoten, unter dem alle Dienste definiert werden. Gemeinsame Netzwerke werden normalerweise am Ende dieser Datei definiert.
Um zu beginnen, kopieren Sie diesen Boilerplate-Code in Ihre docker-compose.yml-Datei:
version: "3.9"
services:
networks:
travellist:
driver: bridgeWir werden nun den services-Knoten bearbeiten, um die app-, db- und nginx-Dienste einzuschließen.
Der app-Dienst
Der app-Dienst richtet einen Container mit dem Namen travellist-app ein. Er erstellt ein neues Docker-Image basierend auf einer Dockerfile, die sich im gleichen Verzeichnis wie die docker-compose.yml-Datei befindet. Das neue Image wird lokal unter dem Namen travellist gespeichert.
Obwohl sich das als Anwendung bereitgestellte Dokumenten-Root im nginx-Container befindet, benötigen wir die Anwendungsdateien auch irgendwo im app-Container, damit wir Befehlszeilenaufgaben mit dem Laravel Artisan-Tool ausführen können.
Kopieren Sie die folgende Service-Definition unter Ihrem services-Knoten in der docker-compose.yml-Datei:
app:
build:
args:
user: sammy
uid: 1000
context: ./
dockerfile: Dockerfile
image: travellist
container_name: travellist-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./:/var/www
networks:
- travellistDiese Einstellungen bewirken Folgendes:
build: Diese Konfiguration weist Docker Compose an, ein lokales Image für denapp-Dienst zu erstellen, wobei der angegebene Pfad (Context) und das Dockerfile als Anweisungen verwendet werden. Die Argumenteuserunduidwerden in das Dockerfile eingefügt, um die Benutzererstellungsbefehle zur Build-Zeit anzupassen.image: Der Name, der für das zu erstellende Image verwendet wird.container_name: Legt den Containernamen für diesen Dienst fest.restart: Immer neu starten, außer der Dienst ist gestoppt.working_dir: Legt das Standardverzeichnis für diesen Dienst auf/var/wwwfest.volumes: Erstellt ein geteiltes Volume, das Inhalte vom aktuellen Verzeichnis mit/var/wwwim Container synchronisiert. Beachten Sie, dass dies nicht Ihr Dokumentenstamm ist, da dieser imnginx-Container gespeichert wird.networks: Richtet diesen Dienst so ein, dass er ein Netzwerk mit dem Namentravellistverwendet.
Der db-Dienst
Der db-Dienst verwendet ein vorgefertigtes MySQL 8.0-Image von Docker Hub. Da Docker Compose automatisch .env-Variablendateien lädt, die sich im selben Verzeichnis wie die docker-compose.yml-Datei befinden, können wir unsere Datenbankeinstellungen aus der Laravel-.env-Datei beziehen, die wir in einem vorherigen Schritt erstellt haben.
Fügen Sie die folgende Service-Definition in Ihren services-Knoten direkt nach dem app-Service ein:
db:
image: mysql:8.0
container_name: travellist-db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- travellistDiese Einstellungen bewirken Folgendes:
image: Definiert das Docker-Image, das für diesen Container verwendet werden soll. In diesem Fall verwenden wir ein MySQL-8.0-Image von Docker Hub.container_name: Legt den Containernamen für diesen Dienst fest:travellist-db.restart: Starten Sie diesen Dienst immer neu, es sei denn, er wurde ausdrücklich gestoppt.environment: Definiert Umgebungsvariablen im neuen Container. Wir verwenden Werte, die aus der Laravel.env-Datei stammen, um unseren MySQL-Dienst einzurichten, der automatisch eine neue Datenbank und einen neuen Benutzer basierend auf den bereitgestellten Umgebungsvariablen erstellt.volumes: Erstellt ein Volume, um ein.sql-Datenbank-Dump zu teilen, das zur Initialisierung der Anwendungsdatenbank verwendet wird. Das MySQL-Image importiert automatisch.sql-Dateien, die im Verzeichnis/docker-entrypoint-initdb.dim Container abgelegt werden.networks: Richtet diesen Dienst so ein, dass er ein Netzwerk mit dem Namentravellistverwendet.
Der nginx-Dienst
Der nginx-Dienst verwendet ein vorgefertigtes Nginx-Image auf Basis von Alpine, einer leichtgewichtigen Linux-Distribution. Er erstellt einen Container mit dem Namen travellist-nginx und verwendet die ports-Definition, um eine Weiterleitung von Port 8000 auf dem Host-System zu Port 80 im Container einzurichten.
Fügen Sie die folgende Service-Definition in Ihren services-Knoten direkt nach dem db-Service ein:
nginx:
image: nginx:1.17-alpine
container_name: travellist-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./:/var/www
- ./docker-compose/nginx:/etc/nginx/conf.d
networks:
- travellistDiese Einstellungen bewirken Folgendes:
image: Definiert das Docker-Image, das für diesen Container verwendet werden soll. In diesem Fall verwenden wir das Alpine Nginx 1.17-Image.container_name: Legt den Container-Namen für diesen Dienst fest: travellist-nginx.restart: Starten Sie diesen Dienst immer neu, es sei denn, er wurde ausdrücklich gestoppt.ports: Richtet eine Portweiterleitung ein, die den externen Zugriff über Port8000auf den Webserver ermöglicht, der im Container auf Port80läuft.volumes: Erstellt zwei geteilte Volumes. Das erste synchronisiert Inhalte vom aktuellen Verzeichnis nach/var/wwwinnerhalb des Containers. Auf diese Weise werden Änderungen an den Anwendungsdateien lokal schnell in der von Nginx im Container bereitgestellten Anwendung angezeigt. Das zweite Volume stellt sicher, dass unsere Nginx-Konfigurationsdatei, die sich unterdocker-compose/nginx/travellist.confbefindet, in den Nginx-Konfigurationsordner des Containers kopiert wird.networks: Richtet diesen Dienst so ein, dass er ein Netzwerk namenstravellistverwendet.
Fertige docker-compose.yml-Datei
So sieht unsere fertige docker-compose.yml-Datei aus:
version: "3.9"
services:
app:
build:
args:
user: sammy
uid: 1000
context: ./
dockerfile: Dockerfile
image: travellist
container_name: travellist-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./:/var/www
networks:
- travellist
db:
image: mysql:8.0
container_name: travellist-db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- travellist
nginx:
image: nginx:1.17-alpine
container_name: travellist-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./:/var/www
- ./docker-compose/nginx:/etc/nginx/conf.d/
networks:
- travellist
networks:
travellist:
driver: bridgeStelle sicher, dass du die Datei speicherst, wenn du fertig bist.
Schritt 6 — Die Anwendung mit Docker Compose ausführen
Wir werden nun docker compose-Befehle verwenden, um das Anwendungsimage zu erstellen und die Dienste auszuführen, die wir in unserer Einrichtung angegeben haben.
Erstellen Sie das app-Image mit folgendem Befehl:
docker compose build appDieser Befehl kann einige Minuten dauern. Sie werden eine Ausgabe ähnlich der folgenden sehen:
Building app
Sending build context to Docker daemon 377.3kB
Step 1/11 : FROM php:7.4-fpm
---> 8c08d993542f
Step 2/11 : ARG user
---> e3ce3af04d87
Step 3/11 : ARG uid
---> 30cb921ef7df
Step 4/11 : RUN apt-get update && apt-get install -y git curl libpng-dev libonig-dev libxml2-dev zip unzip
. . .
---> b6dbc7a02e95
Step 5/11 : RUN apt-get clean && rm -rf /var/lib/apt/lists/*
---> 10ef9dde45ad
. . .
Step 6/11 : RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
. . .
---> 920e4f09ec75
Step 7/11 : COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
---> dbbcd44e44af
Step 8/11 : RUN useradd -G www-data,root -u $uid -d /home/$user $user
---> db98e899a69a
Step 9/11 : RUN mkdir -p /home/$user/.composer && chown -R $user:$user /home/$user
---> 5119e26ebfea
Step 10/11 : WORKDIR /var/www
---> 699c491611c0
Step 11/11 : USER $user
---> cf250fe8f1af
Successfully built cf250fe8f1af
Successfully tagged travellist:latestWenn der Build abgeschlossen ist, können Sie die Umgebung im Hintergrundmodus ausführen mit:
docker compose up -dCreating travellist-db ... done
Creating travellist-app ... done
Creating travellist-nginx ... doneDies wird Ihre Container im Hintergrund ausführen. Um Informationen über den Status Ihrer aktiven Dienste anzuzeigen, führen Sie aus:
docker compose psSie werden eine Ausgabe wie diese sehen:
Name Command State Ports
-----------------------------------------------------------------------------------------------
travellist-app docker-php-entrypoint php-fpm Up 9000/tcp
travellist-db docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
travellist-nginx nginx -g daemon off; Up 0.0.0.0:8000->80/tcp,:::8000->80/tcpIhre Umgebung ist jetzt einsatzbereit.
Sie können nun überprüfen, ob jeder containerisierte Dienst korrekt reagiert, indem Sie einfache curl-Befehle verwenden.
Um den Nginx-Webdienst zu testen:
curl -I http://localhost:8000Erwartete Ausgabe:
HTTP/1.1 200 OK Server: nginx/1.17.10 Content-Type: text/html; charset=UTF-8Dies bestätigt, dass der Nginx-Container läuft und Antworten von Ihrer Laravel-Anwendung liefert.
Um PHP-FPM über Nginx zu testen:
curl -s http://localhost:8000 | grep "Berlin"Wenn die Anwendung korrekt läuft, gibt dieser Befehl die HTML der Willkommensseite zurück, die das Wort Berlin enthält.
Wir müssen noch ein paar Befehle ausführen, um die Einrichtung der Anwendung abzuschließen. Sie können den Befehl docker compose exec verwenden, um Befehle in den Service-Containern auszuführen, zum Beispiel ls -l, um detaillierte Informationen über die Dateien im Anwendungsverzeichnis anzuzeigen:
docker compose exec app ls -ltotal 256
-rw-r--r-- 1 sammy sammy 737 Apr 18 14:21 Dockerfile
-rw-r--r-- 1 sammy sammy 101 Jan 7 2020 README.md
drwxr-xr-x 6 sammy sammy 4096 Jan 7 2020 app
-rwxr-xr-x 1 sammy sammy 1686 Jan 7 2020 artisan
drwxr-xr-x 3 sammy sammy 4096 Jan 7 2020 bootstrap
-rw-r--r-- 1 sammy sammy 1501 Jan 7 2020 composer.json
-rw-r--r-- 1 sammy sammy 179071 Jan 7 2020 composer.lock
drwxr-xr-x 2 sammy sammy 4096 Jan 7 2020 config
drwxr-xr-x 5 sammy sammy 4096 Jan 7 2020 database
drwxr-xr-x 4 sammy sammy 4096 Apr 18 14:22 docker-compose
-rw-r--r-- 1 sammy sammy 1017 Apr 18 14:29 docker-compose.yml
-rw-r--r-- 1 sammy sammy 1013 Jan 7 2020 package.json
-rw-r--r-- 1 sammy sammy 1405 Jan 7 2020 phpunit.xml
drwxr-xr-x 2 sammy sammy 4096 Jan 7 2020 public
-rw-r--r-- 1 sammy sammy 273 Jan 7 2020 readme.md
drwxr-xr-x 6 sammy sammy 4096 Jan 7 2020 resources
drwxr-xr-x 2 sammy sammy 4096 Jan 7 2020 routes
-rw-r--r-- 1 sammy sammy 563 Jan 7 2020 server.php
drwxr-xr-x 5 sammy sammy 4096 Jan 7 2020 storage
drwxr-xr-x 4 sammy sammy 4096 Jan 7 2020 tests
-rw-r--r-- 1 sammy sammy 538 Jan 7 2020 webpack.mix.jsWir werden nun composer install ausführen, um die Anwendungsabhängigkeiten zu installieren:
docker compose exec app rm -rf vendor composer.lock
docker compose exec app composer installSie werden eine Ausgabe wie diese sehen:
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
. . .
Lock file operations: 89 installs, 0 updates, 0 removals
- Locking doctrine/inflector (2.0.4)
- Locking doctrine/instantiator (1.4.1)
- Locking doctrine/lexer (1.2.3)
- Locking dragonmantank/cron-expression (v2.3.1)
- Locking egulias/email-validator (2.1.25)
- Locking facade/flare-client-php (1.9.1)
- Locking facade/ignition (1.18.1)
- Locking facade/ignition-contracts (1.0.2)
- Locking fideloper/proxy (4.4.1)
- Locking filp/whoops (2.14.5)
. . .
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 89 installs, 0 updates, 0 removals
- Downloading doctrine/inflector (2.0.4)
- Downloading doctrine/lexer (1.2.3)
- Downloading dragonmantank/cron-expression (v2.3.1)
- Downloading symfony/polyfill-php80 (v1.25.0)
- Downloading symfony/polyfill-php72 (v1.25.0)
- Downloading symfony/polyfill-mbstring (v1.25.0)
- Downloading symfony/var-dumper (v4.4.39)
- Downloading symfony/deprecation-contracts (v2.5.1)
. . .
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.Das Letzte, was wir tun müssen, bevor wir die Anwendung testen, ist, einen eindeutigen Anwendungsschlüssel mit dem artisan Laravel Kommandozeilen-Tool zu erstellen. Dieser Schlüssel wird verwendet, um Benutzersitzungen und andere sensible Daten zu verschlüsseln:
docker compose exec app php artisan key:generateApplication key set successfully.Gehe nun zu deinem Browser und rufe den Domainnamen oder die IP-Adresse deines Servers auf Port 8000 auf:
http://server_domain_or_IP:8000Hinweis: Falls Sie diese Demo auf Ihrem lokalen Rechner ausführen, verwenden Sie http://localhost:8000, um die Anwendung über Ihren Browser zu erreichen.
Du wirst eine Seite wie diese sehen:
Sie können die Laravel-Anwendung auch von innerhalb des App-Containers testen, ohne einen Browser zu verwenden:
docker compose exec app curl http://nginxWenn alles korrekt konfiguriert ist, sollten Sie die HTML-Ausgabe der Standard-Willkommensseite von Laravel sehen.
<html>
<head>
<title>Travel List</title>
</head>
<body>
<h1>My Travel Bucket List</h1>
<h2>Places I'd Like to Visit</h2>
<ul>
<li>Berlin</li>
<li>Budapest</li>
<li>Denver</li>
<li>Helsinki</li>
<li>Lisbon</li>
<li>Nairobi</li>
<li>Rio</li>
<li>Tokyo</li>
</ul>
<h2>Places I've Already Been To</h2>
<ul>
<li>Cincinnati</li>
<li>Moscow</li>
<li>Oslo</li>
</ul>
</body>
</html>Sie können den Befehl logs verwenden, um die von Ihren Diensten erzeugten Protokolle zu überprüfen:
docker compose logs nginxAttaching to travellist-nginx
. . .
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:49:16 +0000] "GET / HTTP/1.1" 200 627 "-" "curl/7.82.0"
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:51:27 +0000] "GET / HTTP/1.1" 200 627 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"
travellist-nginx | 172.24.9.1 - - [18/Apr/2022:14:51:27 +0000] "GET /favicon.ico HTTP/1.1" 200 0 "http://localhost:8000/" "Mozilla/5.0 (X11; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"Sie können auch den folgenden curl-Befehl verwenden, um Logeinträge auszulösen:
curl http://localhost:8000Dann erneut ausführen:
docker compose logs nginxSie sollten jetzt einen entsprechenden Zugriffseintrag für Ihre Anfrage sehen.
Wenn Sie Ihre Docker-Compose-Umgebung pausieren möchten, während Sie den Zustand aller Dienste beibehalten, führen Sie Folgendes aus:
docker compose pausePausing travellist-db ... done
Pausing travellist-nginx ... done
Pausing travellist-app ... doneSie können Ihre Dienste dann wieder aufnehmen mit:
docker compose unpauseUnpausing travellist-app ... done
Unpausing travellist-nginx ... done
Unpausing travellist-db ... doneUm Ihre Docker-Compose-Umgebung herunterzufahren und alle dazugehörigen Container, Netzwerke und Volumes zu entfernen, führen Sie aus:
docker compose downStopping travellist-nginx ... done
Stopping travellist-db ... done
Stopping travellist-app ... done
Removing travellist-nginx ... done
Removing travellist-db ... done
Removing travellist-app ... done
Removing network travellist-laravel-demo_travellistFür eine Übersicht aller Docker Compose-Befehle besuchen Sie bitte die Docker Compose-Befehlsreferenz.
Laravel-Datei- und Verzeichnisberechtigungen beheben
Beim Ausführen von Laravel innerhalb von Docker-Containern ist eines der häufigsten Probleme, auf das Entwickler stoßen, mit Datei- und Verzeichnisberechtigungen verbunden. Laravel erfordert, dass bestimmte Verzeichnisse vom PHP-FPM-Prozess innerhalb des app-Containers beschreibbar sind. Wenn diese Verzeichnisse nicht beschreibbar sind, kann die Anwendung Fehler möglicherweise nicht protokollieren, Konfigurationsdateien nicht cachen oder Sitzungsdaten nicht korrekt speichern.
Sie könnten auf Nachrichten wie diese stoßen:
The stream or file "/var/www/storage/logs/laravel.log" could not be opened in append mode: failed to open stream: Permission deniedoder
file_put_contents(/var/www/bootstrap/cache/config.php): Failed to open stream: Permission deniedDiese Fehler weisen darauf hin, dass der Benutzer, der PHP innerhalb des Containers ausführt, keine Berechtigung hat, in die erforderlichen Verzeichnisse zu schreiben.
Die folgenden Schritte beschreiben, wie man diese Probleme sowohl in lokalen als auch in Produktionsumgebungen diagnostiziert und behebt.
Beschreibbare Verzeichnisberechtigungen anpassen
Laravel erfordert, dass zwei Verzeichnisse vom Webserver-Benutzer beschreibbar sind:
/var/www/storage/var/www/bootstrap/cache
Wenn Sie Berechtigungsfehler sehen, können Sie diese beheben, indem Sie Eigentum und Berechtigungen innerhalb des Containers anpassen:
docker compose exec app chown -R sammy:sammy /var/www/storage /var/www/bootstrap/cache
docker compose exec app chmod -R 775 /var/www/storage /var/www/bootstrap/cacheWenn Ihr Dockerfile einen anderen Benutzernamen verwendet (definiert durch das Build-Argument user), ersetzen Sie sammy durch diesen Benutzernamen.
Sie können die Eigentümerschaft mit folgendem Befehl überprüfen:
docker compose exec app ls -ld /var/www/storage /var/www/bootstrap/cacheDie Ausgabe sollte zeigen, dass der Benutzer und die Gruppe mit dem PHP-FPM-Prozess innerhalb des Containers übereinstimmen.
Wenn Sie stattdessen die Berechtigungen vom Host-Rechner aus anpassen möchten, führen Sie aus:
sudo chown -R $(id -u):$(id -g) storage bootstrap/cache
sudo chmod -R 775 storage bootstrap/cacheDies stellt sicher, dass beide Laravel-Verzeichnisse sowohl vom Container als auch von Ihrem Host-Benutzer beschrieben werden können.
Verzeichnisbesitz während des Image-Builds festlegen
Um zu verhindern, dass Berechtigungsprobleme nach jedem Neuaufbau erneut auftreten, können Sie während des Docker-Image-Erstellungsprozesses die Besitzrechte des Verzeichnisses festlegen. Öffnen Sie Ihre Dockerfile und fügen Sie die folgende Zeile am Ende hinzu, bevor Sie zum Benutzer ohne Root-Rechte wechseln:
RUN chown -R $user:www-data /var/wwwDieser Befehl stellt sicher, dass alle Dateien und Verzeichnisse unter /var/www dem Benutzer gehören, den Sie in Ihrem Dockerfile definiert haben.
Für einen gezielteren und sichereren Ansatz können Sie nur die Verzeichnisse anpassen, in die Laravel schreiben muss:
RUN chown -R $user:www-data /var/www/storage /var/www/bootstrap/cacheNachdem Sie diese Änderung vorgenommen haben, erstellen Sie das Image neu und starten die Container neu:
docker compose build app
docker compose up -dBeim nächsten Start des Containers wird es bereits die richtigen Berechtigungen haben.
Überprüfen Sie die Konsistenz der Benutzer-ID zwischen Host und Container
Bei der Verwendung von Bind-Mounts teilt Docker Dateien zwischen Ihrem Host und dem Container. Wenn die numerische UID des Host-Benutzers von der im Container definierten UID abweicht, kann es zu Konflikten bei der Dateibesitzerschaft kommen. Dies ist häufig auf Systemen der Fall, bei denen die Benutzer-IDs zwischen den Maschinen variieren.
Um die UID-Werte zu überprüfen, führen Sie aus:
id -u $(whoami)
docker compose exec app id -uWenn diese beiden Zahlen nicht übereinstimmen, aktualisieren Sie Ihre docker-compose.yml-Datei, um Ihre aktuelle UID an den Build-Prozess zu übergeben:
build:
args:
user: sammy
uid: 1000Dann das Image neu erstellen:
docker compose build app
docker compose up -dDies stellt sicher, dass der Containerbenutzer mit Ihrem Host-Benutzer übereinstimmt, wodurch Berechtigungsfehler bei bind-gemounteten Dateien vermieden werden.
Berechtigungen des Composer-Cache-Verzeichnisses reparieren
Composer speichert heruntergeladene Abhängigkeiten und Cache-Dateien im Home-Verzeichnis des Benutzers innerhalb des Containers (/home/sammy/.composer). Wenn dieses Verzeichnis nicht beschreibbar ist, können Sie Warnungen wie die folgenden sehen:
Cannot create cache directory /home/sammy/.composer/cacheSie können dies beheben, indem Sie das Cache-Verzeichnis erstellen und die korrekten Besitzrechte zuweisen:
docker compose exec app mkdir -p /home/sammy/.composer/cache
docker compose exec app chown -R sammy:sammy /home/sammy/.composerDies stellt sicher, dass Composer Abhängigkeiten und Cache-Dateien ohne Berechtigungsfehler speichern kann, was auch zukünftige composer install-Durchläufe beschleunigt.
Empfohlene Vorgehensweisen für Produktionsumgebungen
In der Produktion sollte die Berechtigungsverwaltung während des Image-Builds und nicht zur Laufzeit erfolgen. Dies verbessert die Konsistenz und Sicherheit.
Befolgen Sie diese Praktiken für eine produktionsbereite Konfiguration:
Vermeiden Sie Bind-Mounts für den Anwendungscode: Stattdessen sollten die Anwendungsdateien während des Builds in das Image kopiert werden. Bind-Mounts sollten nur für die Entwicklung verwendet werden.
Berechtigungen während des Builds festlegen: Fügen Sie die
RUN chown- undchmod-Befehle in Ihr Dockerfile ein, um vor der Bereitstellung die korrekten Eigentumsrechte und Zugriffsrechte sicherzustellen.Verwenden Sie den Benutzer mit den geringsten Rechten: Stellen Sie sicher, dass der PHP-Prozess unter einem Nicht-Root-Benutzer läuft (die aktuelle Einrichtung mit
$usermacht dies bereits).Berechtigungen für nicht beschreibbare Verzeichnisse einschränken: Die meisten Anwendungsdateien sollten schreibgeschützt sein. Sie können dies erzwingen mit:
chmod -R 755 /var/www chmod -R 775 /var/www/storage /var/www/bootstrap/cacheDieses Setup ermöglicht es Laravel, nur dort zu schreiben, wo es nötig ist, und schützt gleichzeitig andere Anwendungsdateien vor Änderungen.
Wenn Sie diese Schritte befolgen, werden Ihre Laravel-Container in sowohl lokalen als auch Produktionsumgebungen stabile, vorhersehbare Dateiberechtigungen haben. Dies reduziert wiederkehrende Fehler und stellt sicher, dass Laravel Daten protokollieren, Dateien cachen und Sitzungen zuverlässig schreiben kann.
Verstehen von docker-compose.override.yml für lokale und Produktionsumgebungen
Docker Compose ermöglicht es Ihnen, Multi-Container-Anwendungen mit einer einzigen Konfigurationsdatei zu definieren. In den meisten Fällen wird diese Konfiguration in einer Datei namens docker-compose.yml gespeichert. Die Verwaltung mehrerer Umgebungen, wie z. B. der lokalen Entwicklung und der Produktion, erfordert jedoch oft umgebungsspezifische Anpassungen. Hierbei wird die Datei docker-compose.override.yml nützlich.
Standardmäßig sucht Docker Compose automatisch nach einer Datei mit dem Namen docker-compose.override.yml im selben Verzeichnis wie die Basis-Compose-Datei. Wenn sie gefunden wird, werden die Konfigurationen beider Dateien zusammengeführt, wenn Sie einen beliebigen docker compose-Befehl ausführen. Dieser Ansatz ermöglicht es Entwicklern, eine saubere, wiederverwendbare Basis-Konfiguration zu pflegen und gleichzeitig bestimmte Aspekte der Einrichtung für lokale oder Produktionsumgebungen anzupassen.
Die Rolle von docker-compose.override.yml
Die docker-compose.override.yml-Datei ist eine Erweiterung der Basis-Compose-Konfiguration. Sie ändert oder fügt Eigenschaften hinzu, die nur für eine bestimmte Umgebung gelten, ohne dass Änderungen an der primären docker-compose.yml-Datei erforderlich sind. Die Override-Datei ist besonders nützlich in lokalen Entwicklungs-Workflows, in denen Entwickler oft Quellcode einbinden, Debugging-Tools aktivieren oder Umgebungsvariablen für Tests ändern müssen.
Wenn Sie den Befehl docker compose up ausführen, kombiniert Docker automatisch die Inhalte von docker-compose.yml und docker-compose.override.yml. Wenn ein Dienst, Volume oder eine Konfiguration in beiden Dateien definiert ist, haben die Werte in der Override-Datei Vorrang.
Um eine andere Override-Datei zu verwenden, zum Beispiel eine für die Produktion, können Sie die Datei manuell mit dem -f-Flag angeben:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dDieser Ansatz ermöglicht es Ihnen, separate Konfigurationen für verschiedene Umgebungen beizubehalten, während Sie eine einheitliche Befehlsstruktur verwenden.
Strukturierung für lokale Entwicklung
Lokale Entwicklungsumgebungen erfordern in der Regel häufige Änderungen, Live-Code-Neuladungen und ausführliche Protokollierung. Die Datei docker-compose.override.yml ermöglicht es, diese Funktionen einzuführen, ohne andere Umgebungen zu beeinträchtigen.
Eine typische lokale Überschreibungsdatei kann Folgendes enthalten:
- Bind-Mounts für Live-Code-Updates
- Lokale Build-Anweisungen anstelle der Verwendung vorgefertigter Images
- Entwicklungsspezifische Umgebungsvariablen
- Debugging- und Testdienste
Zum Beispiel:
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- ./src:/app
- ./logs:/app/logs
environment:
- DATABASE_URL=postgres://postgres:postgres@db:5432/app_db
- LOG_LEVEL=debug
ports:
- "8000:8000"
depends_on:
- db
db:
environment:
- POSTGRES_PASSWORD=postgresIn diesem Beispiel:
- Der
app-Dienst wird direkt aus einer lokalen Dockerfile (Dockerfile.dev) erstellt, was es einfach macht, Änderungen zu testen, ohne Images über ein Registry neu bauen zu müssen. - Der Quellcode wird mithilfe von Bind-Mounts eingebunden, wodurch der Container lokale Dateiänderungen in Echtzeit widerspiegelt.
- Umgebungsvariablen wie
LOG_LEVEL=debugwerden gesetzt, um während der Entwicklung detailliertere Ausgaben zu erhalten. - Die Datenbank verwendet einfache Zugangsdaten, die für lokale Tests geeignet sind, aber nicht in der Produktion verwendet werden sollten.
Diese Konfiguration bietet eine schnellere und flexiblere Entwicklungsumgebung, während die Basiskonfiguration unverändert bleibt.
Vorbereitung auf die Produktion
Produktionsumgebungen erfordern Stabilität, Reproduzierbarkeit und Sicherheit. Container sollten aus vorgefertigten Images ausgeführt werden, anstatt lokal erstellt zu werden, und sensible Informationen sollten sicher verwaltet werden. Im Gegensatz zu der automatisch angewendeten Override-Datei, die für die lokale Entwicklung verwendet wird, müssen Produktions-Overrides ausdrücklich angegeben werden.
Eine Produktionsüberschreibungsdatei (docker-compose.prod.yml) ist in der Regel dafür vorgesehen, lokale Build-Schritte durch Image-Referenzen zu ersetzen, benannte Volumes anstelle von Bind-Mounts zu verwenden und bereitstellungsbezogene Eigenschaften wie Ressourcengrenzen und Skalierung zu definieren.
Beispiel:
version: "3.9"
services:
app:
image: registry.example.com/myapp:1.2.3
environment:
- DATABASE_URL=${DATABASE_URL}
- LOG_LEVEL=info
volumes:
- app-data:/var/lib/app
ports:
- "8000:8000"
restart: unless-stopped
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 512M
db:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
external: true
volumes:
app-data:
db-data:In dieser Konfiguration:
Der
app-Dienst verweist auf ein vorgefertigtes Image (myapp:1.2.3), das in einem Registry gespeichert ist, anstatt es lokal zu erstellen.Bind-Mounts werden durch benannte Volumes ersetzt, um eine konsistente und isolierte Datenspeicherung zu gewährleisten.
Sensible Zugangsdaten werden sicher mithilfe von Docker-Geheimnissen gespeichert.
Der
deploy-Abschnitt definiert das Skalierungsverhalten und die Ressourcengrenzen für eine bessere Stabilität unter Last.Die Konfiguration muss während der Bereitstellung ausdrücklich angewendet werden:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Diese Struktur stellt sicher, dass Produktionsbereitstellungen konsistent, kontrolliert und frei von lokalen Entwicklungsartefakten sind.
Vergleich von lokalen und produktiven Überschreibungen
| Konfigurationsaspekt | Lokal (docker-compose.override.yml) | Produktion (docker-compose.prod.yml) |
|---|---|---|
| Automatisch angewendet | Ja | Nein (muss -f verwenden) |
| Quellcodeverwaltung | Bind-Mounts für Live-Updates | Vorgefertigte Images aus dem Register |
| Umgebungsvariablen | Entwicklerorientierte Werte | Produktionssichere Werte |
| Protokollierung | Ausführlich (debug) | Kompakt (info oder error) |
| Geheimnisverwaltung | Einfache Werte oder .env | Docker-Geheimnisse oder verwaltete Geheimnisse |
| Skalierung | Einzelcontainer | Mehrere Replikate |
| Leistungsoptimierung | Nicht erforderlich | Ressourcenlimits definiert |
| Debugging-Tools | Aktiviert | Deaktiviert |
| Neustart-Richtlinie | Manuell oder keine | |
Die Verwendung mehrerer Docker-Compose-Dateien bietet eine saubere Möglichkeit, um umgebungsspezifische Konfigurationen von der Basisinstallation zu trennen. Die Basis-docker-compose.yml definiert die gemeinsame Anwendungsstruktur, während docker-compose.override.yml diese für die lokale Entwicklung anpasst. Beim Einsatz in der Produktion sorgt eine explizite Override-Datei für eine vorhersehbare und sichere Konfiguration.
Dieses Muster ermöglicht es Teams, einen konsistenten Arbeitsablauf beizubehalten. Entwickler können die Anwendung lokal starten mit:
docker compose upund in die Produktion bereitstellen mit:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -dBeide Umgebungen teilen die gleiche Kernkonfiguration, während sie unabhängige Einstellungen beibehalten, die für ihre spezifischen Anforderungen geeignet sind. Diese Trennung verbessert die Wartbarkeit, reduziert Konfigurationsfehler und hält lokale und Produktionsumgebungen im Einklang.
Fehlerbehebung in Ihrer Umgebung
Dieser Abschnitt bietet Schritte zur Fehlerbehebung für häufige Probleme, die beim Ausführen Ihrer App mit Docker Compose auftreten können.
502 Ungültiges Gateway (Nginx zeigt 502-Antworten an)
Symptome:
- Der Browser zeigt 502 Bad Gateway an, wenn
http://localhost:8000aufgerufen wird. - Die Nginx-Protokolle enthalten Zeilen wie
recv() failed (111: Connection refused)oderconnect() failed (111: Connection refused) while connecting to upstream.
Wahrscheinliche Ursachen:
- PHP-FPM (der
app-Dienst) läuft nicht oder hört nicht auf dem erwarteten Socket/Port. - Nginx
fastcgi_passzeigt auf den falschen Host/Port. - Container-Name stimmt nicht überein oder Netzwerkprobleme zwischen
nginxundapp. appist beim Start abgestürzt (z. B. aufgrund fehlender Erweiterungen oder Konfigurationsfehler).
Wie man bestätigt:
Nginx-Protokolle überprüfen:
docker compose logs nginx | tail -n 100Suche nach
502-Meldungen oder Fehlern bei der Verbindung zum Upstream.Überprüfen Sie den Status und die Protokolle des
app-Containers:docker compose ps app docker compose logs app --tail=200Bestätigen Sie, dass PHP-FPM im
app-Container lauscht:docker compose exec app ss -ltnp | grep :9000 || docker compose exec app ss -lxp | grep php-fpmErwartet: entweder ein TCP-Listener auf Port
9000oder ein vonnginxverwendeter Unix-Socket (bei diesem Compose weniger üblich).Überprüfen Sie, ob
nginxappim Compose-Netzwerk auflösen und erreichen kann:docker compose exec nginx ping -c 2 app docker compose exec nginx wget -qO- --timeout=2 http://app:9000/ || trueWenn
pingfehlschlägt oderwgetzeitüberschreitet, besteht ein Netzwerkproblem oder eine Diskrepanz beim Servicenamen.
Häufige Fehlerbehebungen:
Wenn PHP-FPM nicht läuft, überprüfen Sie die
app-Protokolle auf schwerwiegende PHP-Fehler oder Startprobleme. Beheben Sie den zugrunde liegenden Fehler (oft eine fehlende Erweiterung oder ein Berechtigungsproblem) und starten Sie neu:docker compose restart app docker compose logs app --tail=100Wenn die Nginx-Konfiguration einen anderen Upstream verwendet (z. B.
fastcgi_pass 127.0.0.1:9000;), aktualisieren Siedocker-compose/nginx/travellist.confauffastcgi_pass app:9000;(entsprechend dem Namen Ihres Compose-Dienstes) und laden Sie Nginx neu:# After editing config in host docker compose exec nginx nginx -s reload docker compose logs nginx --tail=50Wenn PHP-FPM auf einem Unix-Socket hört (z. B.
/run/php/php7.4-fpm.sock), Nginx jedoch TCP erwartet oder umgekehrt, standardisieren Sie auf TCPapp:9000für Compose-Setups oder mounten Sie den Socket korrekt zwischen den Containern (empfohlen: TCP in Multi-Container-Compose verwenden).
Fehlende PHP-Erweiterungen (Fehler beim Ausführen von Composer oder Artisan oder Laufzeitfehler)
Symptome:
- Composer- oder Laravel-Befehle schlagen fehl mit Meldungen wie
Class "PDO" not found,ext-pdo is missingoderCall to undefined function json_encode. - PHP-Fehler in den
app-Logs, die auf nicht definierte Klassen oder Funktionen verweisen.
Wie man bestätigt:
Überprüfen Sie die Liste der PHP-Module im
app-Container:docker compose exec app php -m | sortSuche nach den Erweiterungsnamen, die du benötigst (für typische Laravel-Erweiterungen:
pdo_mysql,mbstring,bcmath,openssl,tokenizer,xml,ctype,json,gd).Überprüfen Sie die Composer-Fehlermeldung, die normalerweise die erforderlichen Erweiterungen nennt:
docker compose exec app composer install
Fehlerbehebungen:
Fügen Sie fehlende Erweiterungen in Ihrem Dockerfile hinzu und bauen Sie das Image neu. Beispiel (für
pdo_mysqlundgd):RUN apt-get update && apt-get install -y libpng-dev libxml2-dev \ && docker-php-ext-install pdo_mysql mbstring xml gdDann neu bauen und neu starten:
docker compose build app docker compose up -d app docker compose logs app --tail=100Wenn eine Erweiterung Systembibliotheken benötigt (zum Beispiel benötigt
gdlibpng-dev), fügen Sie die entsprechendenapt-get install-Zeilen vordocker-php-ext-installhinzu.Wenn Sie eine PHP-Erweiterung benötigen, die nicht eingebaut ist, ziehen Sie in Betracht, sie über PECL zu installieren und in
php.inizu aktivieren.
Datenbankverbindungsfehler (Laravel kann keine Verbindung zu MySQL herstellen)
Symptome:
- Laravel zeigt Datenbankverbindungsfehler (
SQLSTATE[HY000] [2002] Verbindung verweigertoderZugriff für Benutzer verweigert). - Migrationen schlagen fehl, oder die Anwendung zeigt eine leere Seite für datengesteuerte Seiten an.
Wie man bestätigt:
Prüfen Sie die DB-Container-Protokolle auf Initialisierungsfehler:
docker compose logs db --tail=200Überprüfen, ob der DB-Container läuft:
docker compose ps dbÜberprüfen Sie, ob die Anmeldedaten und der Host zwischen
.envunddocker-compose.ymlübereinstimmen. In der Laravel-.envsollteDB_HOSTder Name des Compose-Dienstes (db) und nicht127.0.0.1oderlocalhostsein:DB_HOST=db DB_PORT=3306 DB_DATABASE=travellist DB_USERNAME=travellist_user DB_PASSWORD=passwordTest aus dem
db-Container:docker compose exec db mysql -u"${DB_USERNAME}" -p"${DB_PASSWORD}" -e "SHOW DATABASES;"Oder testen Sie vom
app-Container aus, um die Netzwerkverbindung sicherzustellen:docker compose exec app sh -c 'which mysql >/dev/null 2>&1 || echo "no mysql client"; mysql -h db -u"${DB_USERNAME}" -p"${DB_PASSWORD}" -e "SELECT VERSION();"'
Häufige Ursachen und Lösungen:
Falscher Host in
.env: aktualisiereDB_HOST=db, erstelle die Container neu oder lade die Umgebungen neu:docker compose down docker compose up -d docker compose exec app php artisan migrateDatenbank beim Start der App nicht bereit: Verwenden Sie einen Wiederholungsmechanismus in Ihrer App oder fügen Sie einen Healthcheck hinzu und starten Sie die Bestellung. Sie können auch manuell warten:
docker compose exec db mysqladmin -u"${DB_USERNAME}" -p"${DB_PASSWORD}" ping # expected: mysqld is aliveInitialisierungs-SQL schlägt fehl: Überprüfen Sie die Dateien unter
./docker-compose/mysql, ein Syntax- oder Berechtigungsfehler kann die DB-Initialisierung abbrechen. Prüfen Sie die DB-Protokolle auf Importfehler.Privilegien/falsche Anmeldeinformationen: Stellen Sie sicher, dass die Datenbank und der Benutzer existieren. Erstellen Sie die Datenbank neu oder führen Sie SQL aus, um die Berechtigungen zu vergeben.
Host-Ebene Portnutzung: Wenn Sie versucht haben,
curl telnet://localhost:3306auszuführen und derdb-Dienst keinen Host-Port freigibt, wird diese Verbindung absichtlich abgelehnt. Testen Sie dies innerhalb von Containern oder geben Sie den Port indocker-compose.ymlfrei (ports: - "3306:3306") für lokales Debugging.
Berechtigungs- und Dateisystemprobleme (Speicher, Cache, Protokolldateien)
Symptome:
- Laravel wirft Ausnahmen im Zusammenhang mit dem Schreiben von Cache oder Logs:
Der Stream oder die Datei "/var/www/storage/logs/laravel.log" konnte nicht geöffnet werden. - Von Container-Prozessen erstellte Dateien gehören
rootund sind für Ihren Host-Benutzer nicht beschreibbar.
Wie man bestätigt:
Überprüfen Sie die Dateiberechtigungen vom Host aus:
ls -l ls -l storage bootstrap/cache docker compose exec app id -u # user id inside containerÜberprüfen Sie die Containerprotokolle auf Berechtigungsfehler.
Behobene Fehler:
Stellen Sie sicher, dass das Dockerfile den Benutzer und die UID festlegt, die mit Ihrem Host-Benutzer übereinstimmen (Ihr Dockerfile erstellt bereits einen Benutzer mit
ARG uid). Überprüfen Sie, dass dieuidin den Build-Argumenten derdocker-compose.ymlmit Ihrer Host-UID übereinstimmt (normalerweise1000).Eigentum vom Host oder innerhalb des Containers korrigieren:
docker compose exec app chown -R sammy:sammy /var/www/storage /var/www/bootstrap/cacheoder vom Host:
sudo chown -R $(id -u):$(id -g) storage bootstrap/cacheFür die Entwicklung können Bind-Mounts zu Berechtigungsproblemen führen; es ist besser, Container-Befehle auszuführen, um die Besitzrechte nach dem Start der Container anzupassen.
Komponisten- oder lieferantenbezogene Fehler
Symptome:
composer installschlägt innerhalb vonappfehl oder ein fehlendervendor-Ordner verursacht, dass die Klasse nicht gefunden wird.composermeldet Speicherauslastung im Container.
Wie man bestätigt:
Führen Sie Composer innerhalb des
app-Containers aus und erfassen Sie die Ausgabe:docker compose exec app composer install --no-interaction --prefer-dist
Fehlerbehebungen:
Wenn die Speicherlimits von
composererreicht werden, erlauben Sie mehr Speicher oder setzen Sie die Composer-Umgebungsvariable:docker compose exec app php -d memory_limit=-1 /usr/bin/composer installStellen Sie sicher, dass die Composer-Datei vorhanden ist (Ihr Dockerfile kopiert Composer). Falls nicht, bauen Sie das Image mit der Composer-Schicht neu.
Wenn
vendoraufgrund eines Bind-Mount-Overlays fehlt, stellen Sie sicher, dass Ihr Bind-Mount den in dem Image erstelltenvendor-Ordner nicht verdeckt. Die beste Vorgehensweise ist,composer installauszuführen, nachdem die Container gestartet wurden, damitvendorim gemounteten Ordner erstellt wird, odervendorfür die Produktion über den Image-Build zum Container hinzuzufügen.
Die Anwendung gibt eine leere Seite oder 500-Fehler zurück
Symptome:
- Der Browser zeigt eine leere Antwort oder HTTP 500 an.
- Nginx-Protokolle zeigen 200, aber die Seite ist leer;
app-Protokolle zeigen fatale Ausnahmen.
Wie man bestätigt:
Anwendungsprotokolle prüfen:
docker compose exec app tail -n 200 storage/logs/laravel.log docker compose logs app --tail=200Überprüfen Sie die Umgebung:
APP_DEBUG=truein.envbewirkt, dass Laravel detaillierte Fehler in der Entwicklung anzeigt (nicht in der Produktion aktivieren).
Behobene Fehler:
Behebe die zugrunde liegende Ausnahme, die in
laravel.logangezeigt wird.Stellen Sie sicher, dass
.envvorhanden ist undAPP_KEYgesetzt ist:docker compose exec app php artisan key:generateMigrationen ausführen, Cache leeren:
docker compose exec app php artisan migrate --force docker compose exec app php artisan config:cache docker compose exec app php artisan route:cache docker compose exec app php artisan view:cache
Fehler beim Erstellen von Containern (Fehler während docker compose build)
Symptome:
docker compose buildschlägt mit apt- oder Build-Schritten fehl.
Wie man bestätigt:
Baustatus mit Protokollen erneut ausführen:
docker compose build app
Behobene Fehler:
Lies die Ausgabe des fehlgeschlagenen Schritts. Typische Probleme:
- Netzwerk/DNS in der Build-Umgebung: erneut versuchen oder sicherstellen, dass Docker auf das Internet zugreifen kann.
- Fehlende Pakete oder falsche apt-Quelle: Führen Sie
apt-get updatevor der Installation aus und bereinigen Sie anschließend die apt-Listen. - Berechtigungen für in das Image kopierte Dateien: Stellen Sie die korrekten
COPY-Pfade sicher.
Beispielhafter Dockerfile-Ausschnitt für robuste Installationen:
RUN apt-get update && apt-get install -y --no-install-recommends \
libpng-dev libxml2-dev zip unzip \
&& docker-php-ext-install pdo_mysql mbstring xml gd \
&& apt-get clean && rm -rf /var/lib/apt/lists/*Netzwerk- oder DNS-Probleme zwischen Containern
Symptome:
- Ein Container kann einen anderen nicht über den Servicenamen erreichen (z. B. kann
appdbnicht überdb:3306erreichen). pingnach Dienstnamen schlägt fehl.
Wie man bestätigt:
docker compose exec app ping -c 3 db
docker compose exec app getent hosts db
docker network inspect travellistBehobene Fehler:
Stellen Sie sicher, dass die Dienste dasselbe Netzwerk in
docker-compose.ymlteilen (beide sollten auftravellistverweisen).Wenn Sie die Servicenamen oder Netzwerknamen geändert haben, aktualisieren Sie entsprechend
DB_HOSTund Nginx-Upstreams.Netzwerk neu erstellen (dies zerstört temporäre Container, also sei vorsichtig):
docker compose down docker network prune # optional and destructive docker compose up -d
Nützliche Diagnosebefehle
Führen Sie diese zur gezielten Inspektion aus:
Laufende Container und Ports anzeigen:
docker compose psTail-Protokolle für einen Dienst:
docker compose logs -f --tail=200 nginxFühre eine Shell innerhalb eines Containers aus:
docker compose exec app sh docker compose exec db bashContainer-Umgebungsvariablen prüfen:
docker compose exec app env | sort docker compose exec db env | grep MYSQLÜberprüfen Sie die Prozessliste des Containers:
docker compose exec app ps aux docker compose exec app ss -ltnpÜberprüfen Sie den Zustand von MySQL:
docker compose exec db mysqladmin -u"${DB_USERNAME}" -p"${DB_PASSWORD}" ping
Wann Host-Ports zum Debuggen freigegeben werden sollten
Standardmäßig ist der db-Dienst in dieser Konfiguration nicht an Host-Ports gebunden. Öffnen Sie Ports nur für das lokale Debugging. Um MySQL vorübergehend auf dem Host verfügbar zu machen, fügen Sie unter db Folgendes zu docker-compose.yml hinzu:
ports:
- "3306:3306"Dann neu starten:
docker compose up -d dbNach dem Debuggen entfernen Sie die Ports-Zuordnung, um zu vermeiden, dass die Datenbank im Netzwerk sichtbar wird.
Häufig gestellte Fragen
1. Muss Composer auf dem Host installiert sein?
Nein. Sie können Composer vollständig innerhalb des App-Containers ausführen, was der empfohlene Ansatz für diesen Compose-Workflow ist. Das Dockerfile im Tutorial enthält Composer, daher können Sie Befehle wie docker compose exec app composer install oder docker compose run --rm app composer require vendor/package ausführen. Die Ausführung von Composer im Container stellt sicher, dass die richtige PHP-Version und die erforderlichen Erweiterungen verwendet werden und verhindert, dass Vendor-Dateien auf dem Host mit falschem Besitz erstellt werden.
2. Kann ich Laravel-Migrationen von innerhalb des Containers ausführen?
Ja. Führen Sie Migrationen aus dem App-Container aus, damit sie dieselbe Laufzeit und dasselbe Netzwerk wie Ihre Anwendung verwenden: docker compose exec app php artisan migrate. Für einmalige Aufgaben oder CI-Aufgaben können Sie docker compose run --rm app php artisan migrate --force verwenden. Bevor Sie Migrationen ausführen, stellen Sie sicher, dass der Datenbank-Container gesund ist und Verbindungen akzeptiert, zum Beispiel mit docker compose exec db mysqladmin -u$ {DB_USERNAME} -p$ {DB_PASSWORD} ping oder indem Sie so lange neu versuchen, bis er reagiert.
3. Wie installiere ich zusätzliche PHP-Erweiterungen?
Fügen Sie die erforderlichen Systempakete und Erweiterungsbefehle in die Dockerfile ein und bauen Sie dann das Image neu. Installieren Sie zum Beispiel Abhängigkeiten und erstellen Sie gängige Erweiterungen mit etwas wie:
RUN apt-get update && apt-get install -y libpng-dev libjpeg-dev \
&& docker-php-ext-configure gd --with-jpeg \
&& docker-php-ext-install pdo_mysql mbstring gdWenn Sie eine PECL-Erweiterung benötigen, verwenden Sie pecl install und docker-php-ext-enable. Nachdem Sie die Dockerfile bearbeitet haben, führen Sie docker compose build app und dann docker compose up -d app aus, um die Änderungen anzuwenden.
4. Wie mache ich den Nginx-Container für HTTPS zugänglich?
Fügen Sie einen HTTPS-Serverblock zu Ihrer Nginx-Konfiguration hinzu, binden Sie Ihr Zertifikat und Ihren Schlüssel in den Container ein und veröffentlichen Sie Port 443 in docker-compose. Hier ist ein Beispiel mit minimalen Änderungen in docker-compose.yml:
services:
nginx:
ports:
- "8000:80"
- "443:443"
volumes:
- ./docker-compose/nginx:/etc/nginx/conf.d
- ./certs:/etc/nginx/certs:roFügen Sie dann einen SSL-Server-Block hinzu, der auf /etc/nginx/certs/fullchain.pem und /etc/nginx/certs/privkey.pem verweist. Für die Produktion sollten Sie einen Reverse-Proxy oder einen Zertifikat-Manager wie Traefik oder einen externen Load Balancer verwenden, um Zertifikate sicher zu erhalten und zu erneuern, anstatt private Schlüssel im Anwendungs-Stack zu speichern.
5. Wie baue ich Laravel nach Codeänderungen neu auf?
Es hängt davon ab, was sich geändert hat. Wenn du Bind-Mounts für das Projektverzeichnis verwendest, werden Änderungen an PHP, Templates, Routen und Controllern sofort übernommen; führe bei Bedarf Laravel-Cache-Clears aus, zum Beispiel:
docker compose exec app php artisan config:clear
docker compose exec app php artisan route:clear
docker compose exec app php artisan view:clearWenn Sie Composer-Abhängigkeiten oder die Dockerfile (neue Erweiterungen oder Systempakete) geändert haben, installieren oder bauen Sie neu: docker compose exec app composer install bei Abhängigkeitsänderungen und docker compose build app && docker compose up -d bei Änderungen an der Dockerfile. Starten Sie den betroffenen Dienst neu, wenn Sie die PHP-FPM- oder Nginx-Konfiguration ändern: docker compose restart app oder docker compose restart nginx.
Schlussfolgerung
In diesem Leitfaden haben wir eine Docker-Umgebung mit drei Containern eingerichtet und Docker Compose verwendet, um unsere Infrastruktur in einer YAML-Datei zu definieren.
Ab diesem Punkt können Sie an Ihrer Laravel-Anwendung arbeiten, ohne einen lokalen Webserver für die Entwicklung und Tests installieren und einrichten zu müssen. Darüber hinaus arbeiten Sie mit einer temporären Umgebung, die leicht repliziert und verteilt werden kann, was sowohl bei der Entwicklung Ihrer Anwendung als auch beim Übergang zu einer Produktionsumgebung hilfreich sein kann.
Für weitere Laravel-Tutorials sehen Sie sich die folgenden Artikel an:
- Hosten Sie Ihre Laravel-App auf Linux-Console.net
- Anleitung zur Installation und Konfiguration von Laravel mit Nginx auf Ubuntu (LEMP-Stack)
- So erstellen Sie Laravel Eloquent API-Ressourcen, um Modelle in JSON umzuwandeln
- Wie man eine neue Laravel-Anwendung mit Docker Compose startet
Danke, dass Sie mit der Linux-Console.net Community lernen.

