Wie kann man php-fpm- und Nginx Docker-Container richtig verknüpfen?

102

Ich versuche 2 separate Container zu verknüpfen:

Das Problem ist, dass PHP-Skripte nicht funktionieren. Möglicherweise ist die PHP-Fpm-Konfiguration falsch. Hier ist der Quellcode, der sich in meinem Repository befindet . Hier ist die Datei docker-compose.yml:

nginx:
    build: .
    ports:
        - "80:80"
        - "443:443"
    volumes:
        - ./:/var/www/test/
    links:
        - fpm
fpm:
    image: php:fpm
    ports:
        - "9000:9000"

und mit Dockerfiledem ich ein benutzerdefiniertes Image basierend auf dem Nginx erstellt habe:

FROM nginx

# Change Nginx config here...
RUN rm /etc/nginx/conf.d/default.conf
ADD ./default.conf /etc/nginx/conf.d/

Zuletzt ist hier meine benutzerdefinierte Konfiguration des virtuellen Nginx-Hosts:

server {
    listen  80;

    server_name localhost;
    root /var/www/test;

    error_log /var/log/nginx/localhost.error.log;
    access_log /var/log/nginx/localhost.access.log;

    location / {
        # try to serve file directly, fallback to app.php
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/.+\.php(/|$) {
        fastcgi_pass 192.168.59.103:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS off;
    }
}

Könnte mir jemand helfen, diese Container richtig zu konfigurieren, um PHP-Skripte auszuführen?

PS Ich führe Container über Docker-Composer wie folgt aus:

docker-compose up

aus dem Projektstammverzeichnis.

Victor Bocharsky
quelle
1
Wie haben Sie bisher versucht, sie zu konfigurieren, oder welchen Code haben Sie verwendet? Bitte lassen Sie mich nicht raten, dass ich beim Raten Unsinn bin.
Matthew Brown alias Lord Matt
1
@MatthewBrown Huh, ich habe meinen Code in ein öffentliches Repository auf GitHub gestellt und denke, das wird ausreichen, aber Sie haben Recht, besser, Code auch hier in meiner Frage anzuzeigen.
Victor Bocharsky
Wenn sich die Bilder drehen, können Sie docker execin den laufenden Container gehen und fpm pingen?
Vincent De Smet
1
@ MatthewBrown ja, ich habe es gewonnen, danke
Victor Bocharsky
1
PS ich erreicht auch eine Arbeitslösung zu Link Nginxund PHP-FPM zusammen mit Vagrant und ansible. Überprüfen Sie mein Repo github.com/bocharsky-bw/vagrant-ansible-docker, wenn Sie möchten.
Victor Bocharsky

Antworten:

32

Codieren Sie die IP-Adresse von Containern in der Nginx-Konfiguration nicht fest. Der Docker-Link fügt den Hostnamen des verknüpften Computers zur Hosts-Datei des Containers hinzu, und Sie sollten in der Lage sein, nach Hostnamen zu pingen.

BEARBEITEN: Für Docker 1.9 Networking müssen Sie keine Container mehr verknüpfen. Wenn mehrere Container mit demselben Netzwerk verbunden sind, wird ihre Hosts-Datei aktualisiert, damit sie sich über den Hostnamen erreichen können.

Jedes Mal, wenn sich ein Docker-Container aus einem Image heraus dreht (sogar einen vorhandenen Container stoppen / starten), erhalten die Container vom Docker-Host neue IPs. Diese IPs befinden sich nicht im selben Subnetz wie Ihre tatsächlichen Computer.

Siehe Docker-Verknüpfungsdokumente (dies wird von Compose im Hintergrund verwendet).

aber klarer erklärt in den docker-composeDokumenten auf Links & Expose

Links

links:
 - db
 - db:database
 - redis

Für diesen Dienst wird in / etc / hosts in Containern für diesen Dienst ein Eintrag mit dem Namen des Alias ​​erstellt, z.

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis

entlarven

Stellen Sie Ports bereit, ohne sie auf dem Hostcomputer zu veröffentlichen. Sie sind nur für verknüpfte Dienste zugänglich . Es kann nur der interne Port angegeben werden.

Wenn Sie Ihr Projekt so einrichten, dass die Ports und andere Anmeldeinformationen über Umgebungsvariablen abgerufen werden, legen Links automatisch eine Reihe von Systemvariablen fest :

Führen Sie aus, um festzustellen, welche Umgebungsvariablen für einen Dienst verfügbar sind docker-compose run SERVICE env.

name_PORT

Vollständige URL, z. B. DB_PORT = tcp: //172.17.0.5: 5432

name_PORT_num_protocol

Vollständige URL, z DB_PORT_5432_TCP=tcp://172.17.0.5:5432

name_PORT_num_protocol_ADDR

IP-Adresse des Containers, z DB_PORT_5432_TCP_ADDR=172.17.0.5

name_PORT_num_protocol_PORT

Freiliegende Portnummer, z DB_PORT_5432_TCP_PORT=5432

name_PORT_num_protocol_PROTO

Protokoll (tcp oder udp), z DB_PORT_5432_TCP_PROTO=tcp

name_NAME

Vollqualifizierter Containername, z DB_1_NAME=/myapp_web_1/myapp_db_1

Vincent De Smet
quelle
2
Sie müssen Port 9000 auch nicht auf dem Host veröffentlichen. Die Ports sind zwischen den verknüpften Docker-Containern geöffnet, es sei denn, Sie möchten den Port direkt von Ihrem Host aus beheben.
Vincent De Smet
Ja, du hast recht, danke. In meinem Fall sollte ich fastcgi_pass fpm: 9000 anstelle der direkten IP verwenden. Ich weiß nicht, dass Docker es automatisch zum Host hinzufügt, mein schlechtes.
Victor Bocharsky
Was ist mit Port, also besser Expose anstelle von Ports verwenden ? Oder konnte ich keinen dieser Ports verwenden und Direktiven offenlegen, da verknüpfte Container Zugriff auf diesen Port haben?
Victor Bocharsky
sorry für die späte Antwort - ich glaube , Sie belichten verwenden müssen, sorry ich kann jetzt nicht überprüfen
Vincent De Smet
2
--linkssind laut der Docker-Dokumentation, auf die Sie verweisen, jetzt veraltet. Sie werden derzeit noch unterstützt, aber der offensichtliche Plan sieht vor, dass sie überholt werden.
Therobyouknow
85

Ich weiß, dass es ein alter Beitrag ist, aber ich hatte das gleiche Problem und konnte nicht verstehen, warum Ihr Code nicht funktioniert hat. Nach vielen Tests habe ich herausgefunden warum.

Es scheint, als ob fpm den vollständigen Pfad von nginx empfängt und versucht, die Dateien im fpm-Container zu finden. Daher muss es genau das gleiche sein wie server.rootin der nginx-Konfiguration, auch wenn es im nginx-Container nicht vorhanden ist.

Demonstrieren:

docker-compose.yml

nginx:
    build: .
    ports:
        - "80:80"
    links:
        - fpm
fpm:
    image: php:fpm
    ports:
        - ":9000"

    # seems like fpm receives the full path from nginx
    # and tries to find the files in this dock, so it must
    # be the same as nginx.root
    volumes:
        - ./:/complex/path/to/files/

/etc/nginx/conf.d/default.conf

server {
    listen  80;

    # this path MUST be exactly as docker-compose.fpm.volumes,
    # even if it doesn't exist in this dock.
    root /complex/path/to/files;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/.+\.php(/|$) {
        fastcgi_pass fpm:9000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Dockerfile

FROM nginx:latest
COPY ./default.conf /etc/nginx/conf.d/
Rafael Quintela
quelle
4
GUT GEMACHT!!! Genau darum geht es! Ich habe die Nginx-Wurzel auf einen anderen Pfad als /var/www/htmlmit Fehler gesetzt.
Alfred Huang
3
Nur ein Hinweis, der :9000der Port ist, der im Container verwendet wird, und nicht der, der Ihrem Host ausgesetzt ist. Ich habe 2 Stunden gebraucht, um das herauszufinden. Hoffentlich musst du nicht.
Schrei
1
services.fpm.ports is invalid: Invalid port ":9000", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
030
4
Sie müssen hier eigentlich gar keinen portsAbschnitt einfügen. Möglicherweise müssen Sie es nur verwenden, exposewenn es nicht bereits im Bild enthalten ist (was es wahrscheinlich ist). Wenn Sie zwischen Containern kommunizieren, sollten Sie den PHP-FPM-Port nicht offenlegen.
Seher
War auf der Suche nach einer Lösung für AH01071: Got error 'Primary script unknown\n'und dass der PHP-Fpm-Container das gleiche Verzeichnis mit den Webknoten teilen muss, war die Lösung!
cptPH
23

Wie bereits erwähnt, bestand das Problem darin, dass die Dateien im fpm-Container nicht sichtbar waren. Für die gemeinsame Nutzung von Daten zwischen Containern werden jedoch nur Datencontainer empfohlen (wie in diesem Artikel erläutert ).

Lange Rede, kurzer Sinn: Erstellen Sie einen Container, der nur Ihre Daten enthält, teilen Sie sie mit einem Volume und verknüpfen Sie dieses Volume in Ihren Apps mit volumes_from.

Bei Verwendung von compose (1.6.2 in meinem Computer) docker-compose.ymlwürde die Datei lauten:

version: "2"
services:
  nginx:
    build:
      context: .
      dockerfile: nginx/Dockerfile
    ports:
      - "80:80"
    links:
      - fpm
    volumes_from:
      - data
  fpm:
    image: php:fpm
    volumes_from:
      - data
  data:
    build:
      context: .
      dockerfile: data/Dockerfile
    volumes:
      - /var/www/html

Beachten Sie, dass dataein Volume veröffentlicht wird, das mit den Diensten nginxund verknüpft ist fpm. Dann das Dockerfilefür den Datendienst , der Ihren Quellcode enthält:

FROM busybox

# content
ADD path/to/source /var/www/html

Und das Dockerfilefür nginx, das nur die Standardkonfiguration ersetzt:

FROM nginx

# config
ADD config/default.conf /etc/nginx/conf.d

Zur Vervollständigung ist hier die Konfigurationsdatei aufgeführt, die erforderlich ist, damit das Beispiel funktioniert:

server {
    listen 0.0.0.0:80;

    root /var/www/html;

    location / {
        index index.php index.html;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass fpm:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
}

Dies weist nginx lediglich an, das freigegebene Volume als Dokumentstamm zu verwenden, und legt die richtige Konfiguration für nginx fest, um mit dem fpm-Container kommunizieren zu können (dh das richtige HOST:PORT, was fpm:9000den durch compose definierten Hostnamen und dem zu verdanken ist SCRIPT_FILENAME).

iKanor
quelle
Es sieht so aus, als würden die Daten nicht vom Host auf die Container aktualisiert. Wenn ich Docker ps -a mache, sehe ich, dass der Datencontainer gestoppt ist. Ist das ein Problem?
Aftab Naveed
2
Das ist das erwartete Verhalten. Ein Nur-Daten-Container führt keinen Befehl aus und wird nur als gestoppt aufgeführt. Außerdem Dockerfilekopiert der Datencontainer Ihre Quellen während der Erstellungszeit in den Container. Aus diesem Grund werden sie nicht aktualisiert, wenn Sie die Dateien auf dem Host ändern. Wenn Sie die Quellen zwischen dem Host und dem Container freigeben möchten, müssen Sie das Verzeichnis bereitstellen. Ändern Sie den dataDienst in der zu ladenden Erstellungsdatei image: busyboxund geben Sie im volumesAbschnitt eingeben ein ./sources:/var/www/html, wo ./sourcessich der Pfad zu Ihren Quellen auf dem Host befindet.
iKanor
16

Neue Antwort

Docker Compose wurde aktualisiert. Sie haben jetzt ein Dateiformat der Version 2 .

Dateien der Version 2 werden von Compose 1.6.0+ unterstützt und erfordern eine Docker Engine der Version 1.10.0+.

Sie unterstützen jetzt die Netzwerkfunktion von Docker, die beim Ausführen ein Standardnetzwerk namens myapp_default einrichtet

Aus ihrer Dokumentation würde Ihre Datei ungefähr so ​​aussehen:

version: '2'

services:
  web:
    build: .
    ports:
      - "8000:8000"
  fpm:
    image: phpfpm
  nginx
    image: nginx

Da diese Container automatisch zum Standardnetzwerk myapp_default hinzugefügt werden, können sie miteinander kommunizieren . Sie hätten dann in der Nginx-Konfiguration:

fastcgi_pass fpm:9000;

Wie auch von @treeface in den Kommentaren erwähnt, denken Sie daran, sicherzustellen, dass PHP-FPM Port 9000 überwacht. Dies kann durch Bearbeiten erfolgen, /etc/php5/fpm/pool.d/www.confwo Sie es benötigen listen = 9000.

Alte Antwort

Ich habe das Folgende hier für diejenigen aufbewahrt, die eine ältere Version von Docker / Docker Compose verwenden, und möchte die Informationen.

Ich bin bei Google immer wieder auf diese Frage gestoßen, als ich versucht habe, eine Antwort auf diese Frage zu finden, aber es war nicht ganz das, wonach ich gesucht habe, da der Schwerpunkt Q / A auf Docker-Compose liegt (für den zum Zeitpunkt des Schreibens nur experimentelle Unterstützung besteht Docker-Netzwerkfunktionen). Hier ist meine Sicht auf das, was ich gelernt habe.

Docker hat kürzlich seine Link- Funktion zugunsten seiner Netzwerk-Funktion abgelehnt

Daher können Sie mithilfe der Docker-Netzwerkfunktion Container verknüpfen, indem Sie die folgenden Schritte ausführen. Ausführliche Erläuterungen zu den Optionen finden Sie in den zuvor verlinkten Dokumenten.

Erstellen Sie zuerst Ihr Netzwerk

docker network create --driver bridge mynetwork

Führen Sie als Nächstes Ihren PHP-FPM-Container aus, und stellen Sie sicher, dass Sie Port 9000 öffnen und Ihrem neuen Netzwerk zuweisen ( mynetwork).

docker run -d -p 9000 --net mynetwork --name php-fpm php:fpm

Das wichtige Bit hier ist das --name php-fpmam Ende des Befehls, das der Name ist, wir werden dies später brauchen.

Führen Sie als Nächstes Ihren Nginx-Container erneut aus, und weisen Sie ihn dem von Ihnen erstellten Netzwerk zu.

docker run --net mynetwork --name nginx -d -p 80:80 nginx:latest

Für die PHP- und Nginx-Container können Sie bei Bedarf auch --volumes-fromBefehle usw. hinzufügen .

Jetzt kommt die Nginx-Konfiguration. Welches sollte ungefähr so ​​aussehen:

server {
    listen 80;
    server_name localhost;

    root /path/to/my/webroot;

    index index.html index.htm index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php-fpm:9000; 
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

Beachten Sie die fastcgi_pass php-fpm:9000;im Standortblock. Das heißt Kontaktcontainer php-fpmam Hafen 9000. Wenn Sie einem Docker-Bridge-Netzwerk Container hinzufügen, erhalten alle automatisch eine Host-Dateiaktualisierung, bei der der Containername mit der IP-Adresse verglichen wird. Wenn Nginx also feststellt, dass es den php-fpmzuvor genannten und Ihrem mynetworkDocker-Netzwerk zugewiesenen PHP-FPM-Container kontaktieren muss .

Sie können diese Nginx-Konfiguration entweder während des Erstellungsprozesses Ihres Docker-Containers oder danach nach Ihren Wünschen hinzufügen.

DavidT
quelle
Denken Sie auch daran, php-fpmPort 9000 abzuhören. Dies wäre listen = 9000in /etc/php5/fpm/pool.d/www.conf.
Baumgesicht
Danke @treeface guter Punkt. Ich habe mit Ihrem Kommentar aktualisiert.
DavidT
8

Wie frühere Antworten gelöst haben, sollte aber sehr explizit angegeben werden: Der PHP-Code muss im PHP-Fpm-Container leben, während die statischen Dateien im Nginx-Container leben müssen. Der Einfachheit halber haben die meisten Leute gerade den gesamten Code an beide angehängt, wie ich es auch unten getan habe. In Zukunft werde ich diese verschiedenen Teile des Codes wahrscheinlich in meinen eigenen Projekten trennen, um zu minimieren, welche Container Zugriff auf welche Teile haben.

Meine Beispieldateien unten wurden mit dieser neuesten Offenbarung aktualisiert (danke @alkaline)

Dies scheint das Mindest-Setup für Docker 2.0 Forward zu sein (da es in Docker 2.0 viel einfacher wurde).

docker-compose.yml:

version: '2'
services:
  php:
    container_name: test-php
    image: php:fpm
    volumes:
      - ./code:/var/www/html/site
  nginx:
    container_name: test-nginx
    image: nginx:latest
    volumes:
      - ./code:/var/www/html/site
      - ./site.conf:/etc/nginx/conf.d/site.conf:ro
    ports:
      - 80:80

( AKTUALISIERT die Datei docker-compose.yml oben : Für Sites mit CSS, Javascript, statischen Dateien usw. benötigen Sie diese Dateien, auf die der Nginx-Container zugreifen kann Mein Basiscode ist eine chaotische Mischung aus CSS, JS und PHP. In diesem Beispiel wird nur der gesamte Code an beide Container angehängt.

Im selben Ordner:

site.conf:

server
{
    listen   80;
    server_name site.local.[YOUR URL].com;

    root /var/www/html/site;
    index index.php;

    location /
    {
        try_files $uri =404;
    }

    location ~ \.php$ {
        fastcgi_pass   test-php:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

Im Ordnercode:

./code/index.php:

<?php
phpinfo();

und vergessen Sie nicht, Ihre Hosts-Datei zu aktualisieren:

127.0.0.1 site.local.[YOUR URL].com

und führen Sie Ihr Docker-Compose aus

$docker-compose up -d

und probieren Sie die URL Ihres Lieblingsbrowsers aus

site.local.[YOUR URL].com/index.php
Phillip
quelle
1
Ihre Nginx-Konfigurationsdatei geht davon aus, dass Ihre Website nur PHP-Dateien enthält. Es wird empfohlen, eine Nginx-Speicherortregel für statische Dateien (jpg, txt, svg, ...) zu erstellen und den PHP-Interpreter zu vermeiden. In diesem Fall benötigen sowohl der Nginx- als auch der PHP-Container Zugriff auf die Website-Dateien. Die Antwort von @iKanor oben kümmert sich darum.
Bernard
Danke @Alkaline, statische Dateien sind ein Problem mit meiner ursprünglichen Antwort. Tatsächlich benötigt nginx mindestens die CSS- und JS-Dateien, um lokal auf diesem Computer zu sein, damit sie ordnungsgemäß funktionieren.
Phillip
7

Ich denke, wir müssen dem fpm-Container auch das Volumen geben, nicht wahr? Also =>

fpm:
    image: php:fpm
    volumes:
        - ./:/var/www/test/

Wenn ich dies nicht tue, stoße ich beim Auslösen einer Anfrage auf diese Ausnahme, da fpm die angeforderte Datei nicht finden kann:

[Fehler] 6 # 6: * 4 FastCGI gesendet in stderr: "Primäres Skript unbekannt" beim Lesen des Antwortheaders vom Upstream, Client: 172.17.42.1, Server: localhost, Anforderung: "GET / HTTP / 1.1", Upstream: "fastcgi" : //172.17.0.81: 9000 ", Host:" localhost "

leberknecht
quelle
1
Ja, du hast recht! Wir müssen Dateien mit fpm und nginx teilen
Victor Bocharsky
Ich habe Arbeitsbeispiel mit Nginxund PHP-FPMauf GitHub
Victor Bocharsky
1

Für alle anderen

Nginx 403-Fehler: Verzeichnisindex von [Ordner] ist verboten

bei Verwendung funktioniert index.phpwhile index.htmleinwandfrei und index.phpim Index im Serverblock ihrer Site-Konfiguration enthaltensites-enabled

server {
    listen 80;

    # this path MUST be exactly as docker-compose php volumes
    root /usr/share/nginx/html;

    index index.php

    ...
}

Stellen Sie sicher, dass Ihre Datei nginx.conf /etc/nginx/nginx.conftatsächlich Ihre Site-Konfiguration in den httpBlock lädt ...

http {

    ...

    include /etc/nginx/conf.d/*.conf;

    # Load our websites config 
    include /etc/nginx/sites-enabled/*;
}
Myol
quelle
danke dafür, alt aber immer noch informativ, ich musste / usr / share / nginx / html verwenden thanks, danke
Simon Davies