Come collegare correttamente i container php-fpm e Nginx Docker?


103

Sto cercando di collegare 2 contenitori separati:

Il problema è che gli script php non funzionano. Forse la configurazione php-fpm non è corretta. Ecco il codice sorgente, che si trova nel mio repository . Ecco il file docker-compose.yml:

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

e Dockerfileche ho usato per creare un'immagine personalizzata basata su quella nginx:

FROM nginx

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

Infine, ecco la mia configurazione personalizzata dell'host virtuale Nginx:

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;
    }
}

Qualcuno potrebbe aiutarmi a configurare correttamente questi contenitori per eseguire script php?

PS Eseguo container tramite docker-composer in questo modo:

docker-compose up

dalla directory principale del progetto.


1
Come hai tentato di configurarli finora o quale codice hai usato. Per favore, non farmi indovinare che sono una schifezza a indovinare.
Matthew Brown aka Lord Matt il

1
@ MatthewBrown Huh, ho inserito il mio codice in un repository pubblico su GitHub e penso che sarà sufficiente, ma hai ragione, meglio mostrare il codice anche qui nella mia domanda.
Victor Bocharsky

quando le immagini girano, puoi docker execentrare nel container in esecuzione e fare il ping a fpm?
Vincent De Smet

1
@MatthewBrown sì, l'ho vinto, grazie
Victor Bocharsky

1
PS Ho anche realizzato una soluzione di lavoro da collegare Nginxe PHP-FPM insieme a Vagrant e Ansible. Controlla il mio repository github.com/bocharsky-bw/vagrant-ansible-docker se vuoi.
Victor Bocharsky,

Risposte:


32

Non codificare l'ip dei contenitori nella configurazione di nginx, docker link aggiunge il nome host della macchina collegata al file hosts del contenitore e dovresti essere in grado di eseguire il ping in base al nome host.

EDIT: Docker 1.9 Networking non richiede più il collegamento di contenitori, quando più contenitori sono connessi alla stessa rete, il loro file host verrà aggiornato in modo che possano raggiungersi l'un l'altro tramite il nome host.

Ogni volta che un container docker si avvia da un'immagine (anche arrestando / avviando un container esistente), i container ricevono nuovi ip assegnati dall'host docker. Questi IP non sono nella stessa sottorete delle vostre macchine reali.

vedere i documenti sui collegamenti alla finestra mobile (questo è ciò che compose usa in background)

ma più chiaramente spiegato nei docker-composedocumenti su link ed esporre

collegamenti

links:
 - db
 - db:database
 - redis

Verrà creata una voce con il nome dell'alias in / etc / hosts all'interno dei contenitori per questo servizio, ad esempio:

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis

esporre

Esponi le porte senza pubblicarle sul computer host : saranno accessibili solo ai servizi collegati . È possibile specificare solo la porta interna.

e se imposti il ​​tuo progetto per ottenere le porte + altre credenziali tramite variabili di ambiente, i collegamenti impostano automaticamente un gruppo di variabili di sistema :

Per vedere quali variabili di ambiente sono disponibili per un servizio, esegui docker-compose run SERVICE env.

name_PORT

URL completo, ad esempio DB_PORT = tcp: //172.17.0.5: 5432

name_PORT_num_protocol

URL completo, ad es DB_PORT_5432_TCP=tcp://172.17.0.5:5432

name_PORT_num_protocol_ADDR

Indirizzo IP del contenitore, ad es DB_PORT_5432_TCP_ADDR=172.17.0.5

name_PORT_num_protocol_PORT

Numero di porta esposto, ad es DB_PORT_5432_TCP_PORT=5432

name_PORT_num_protocol_PROTO

Protocollo (tcp o udp), ad es DB_PORT_5432_TCP_PROTO=tcp

name_NAME

Nome del contenitore completo, ad es DB_1_NAME=/myapp_web_1/myapp_db_1


2
Inoltre, non è necessario pubblicare la porta 9000 sull'host, le porte sono aperte tra i contenitori Docker collegati, a meno che non si desideri risolvere i problemi della porta direttamente dal proprio host.
Vincent De Smet

Sì, hai ragione, grazie. Nel mio caso dovrei usare fastcgi_pass fpm: 9000 invece di direct ip. Non so che Docker lo aggiunga all'host automaticamente, colpa mia.
Victor Bocharsky

E la porta, quindi è meglio usare l' esposizione invece delle porte ? O non potrei usare nessuna di queste porte ed esporre le direttive perché i contenitori collegati avranno accesso a questa porta?
Victor Bocharsky

scusa per la risposta in ritardo - Penso che potrebbe essere necessario utilizzare l'esposizione, scusa non posso controllare in questo momento
Vincent De Smet

2
--linkssono ora obsoleti, secondo la documentazione docker a cui fai riferimento. Sono ancora attualmente supportati, ma l'apparente piano è che diventino obsoleti.
therobyouknow

86

So che è gentile un vecchio post, ma ho avuto lo stesso problema e non sono riuscito a capire perché il tuo codice non funzionasse. Dopo molti test ho scoperto il motivo.

Sembra che fpm riceva il percorso completo da nginx e cerchi di trovare i file nel contenitore fpm, quindi deve essere esattamente lo stesso di server.root della configurazione di nginx, anche se non esiste nel contenitore nginx.

Dimostrare:

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/

4
MOLTO BENE!!! Questo è esattamente il punto! Ho impostato la radice nginx su un percorso alternativo diverso da quello /var/www/htmlcon errore.
Alfred Huang

3
Inoltre, solo una nota che :9000è la porta che viene utilizzata nel contenitore non quella esposta al tuo host. Mi ci sono volute 2 ore per capirlo. Si spera che non sia necessario.
urla il

1
services.fpm.ports is invalid: Invalid port ":9000", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
030

4
In realtà non è necessario includere una portssezione qui. Potrebbe essere necessario solo exposese non è già nell'immagine (cosa che probabilmente è). Se stai effettuando comunicazioni tra container, non dovresti esporre la porta PHP-FPM.
Veggente

Stavo cercando una soluzione per AH01071: Got error 'Primary script unknown\n'e che il contenitore php-fpm condividesse la stessa directory con i nodi web era la soluzione!
cptPH

23

Come sottolineato prima, il problema era che i file non erano visibili dal contenitore fpm. Tuttavia, per condividere i dati tra i contenitori, il modello consigliato utilizza contenitori di soli dati (come spiegato in questo articolo ).

Per farla breve: crea un contenitore che contenga solo i tuoi dati, condividilo con un volume e collega questo volume nelle tue app con volumes_from.

Usando compose (1.6.2 nella mia macchina), il docker-compose.ymlfile leggerebbe:

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

Notare che datapubblica un volume collegato ai servizi nginxe fpm. Quindi il Dockerfileper il servizio dati , che contiene il codice sorgente:

FROM busybox

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

E il Dockerfilefor nginx, che sostituisce semplicemente la configurazione predefinita:

FROM nginx

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

Per motivi di completamento, ecco il file di configurazione richiesto per il funzionamento dell'esempio:

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;
    }
}

che dice semplicemente a nginx di usare il volume condiviso come root del documento e imposta la configurazione corretta per nginx per poter comunicare con il contenitore fpm (cioè: il diritto HOST:PORT, che è fpm:9000grazie agli hostname definiti da compose, e il SCRIPT_FILENAME).


Sembra che i dati non vengano aggiornati dall'host ai contenitori e quando eseguo docker ps -a vedo il contenitore di dati arrestato, è un problema?
Aftab Naveed

2
Questo è il comportamento previsto. Un contenitore di soli dati non esegue alcun comando e verrà semplicemente elencato come interrotto. Inoltre, il Dockerfiledel contenitore di dati sta copiando le tue origini nel contenitore in fase di compilazione. Questo è il motivo per cui non verranno aggiornati se si modificano i file nell'host. Se vuoi condividere i sorgenti tra l'host e il container devi montare la directory. Cambia il dataservizio nel file di composizione da caricare image: busyboxe nella volumessezione inserisci ./sources:/var/www/html, dove si ./sourcestrova il percorso dei tuoi sorgenti nell'host.
iKanor

16

Nuova risposta

Docker Compose è stato aggiornato. Ora hanno un formato di file versione 2 .

I file della versione 2 sono supportati da Compose 1.6.0+ e richiedono un Docker Engine della versione 1.10.0+.

Ora supportano la funzionalità di rete di Docker che quando viene eseguita imposta una rete predefinita chiamata myapp_default

Dalla loro documentazione, il tuo file sarebbe simile al seguente:

version: '2'

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

Poiché questi contenitori vengono aggiunti automaticamente alla rete predefinita myapp_default , saranno in grado di parlare tra loro. Avresti quindi nella configurazione di Nginx:

fastcgi_pass fpm:9000;

Inoltre, come menzionato da @treeface nei commenti, ricorda di assicurarti che PHP-FPM sia in ascolto sulla porta 9000, questo può essere fatto modificando /etc/php5/fpm/pool.d/www.confdove ti servelisten = 9000 .

Vecchia risposta

Ho mantenuto il seguente qui per coloro che utilizzano una versione precedente di Docker / Docker compose e vorrei le informazioni.

Ho continuato a imbattermi in questa domanda su google quando cercavo di trovare una risposta a questa domanda, ma non era proprio quello che stavo cercando a causa dell'enfasi Q / A su docker-compose (che al momento della scrittura ha solo supporto sperimentale per funzionalità di rete docker). Quindi ecco la mia opinione su ciò che ho imparato.

Docker ha recentemente deprecato la sua funzione di collegamento a favore della sua funzione di rete

Pertanto, utilizzando la funzionalità Docker Networks è possibile collegare i contenitori seguendo questi passaggi. Per spiegazioni complete sulle opzioni, leggere i documenti collegati in precedenza.

Per prima cosa crea la tua rete

docker network create --driver bridge mynetwork

Quindi esegui il tuo contenitore PHP-FPM assicurandoti di aprire la porta 9000 e assegnarla alla tua nuova rete ( mynetwork).

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

La parte importante qui è il file --name php-fpm fine del comando che è il nome, ne avremo bisogno in seguito.

Quindi esegui nuovamente il tuo contenitore Nginx assegnato alla rete che hai creato.

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

Per i contenitori PHP e Nginx puoi anche aggiungere --volumes-fromcomandi ecc. Come richiesto.

Ora arriva la configurazione di Nginx. Quale dovrebbe essere qualcosa di simile a questo:

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;
    }
}

Notare fastcgi_pass php-fpm:9000;nel blocco di posizione. Quello sta dicendo il contenitore di contatto php-fpmsul porto 9000. Quando aggiungi contenitori a una rete bridge Docker, tutti ottengono automaticamente un aggiornamento del file host che inserisce il nome del contenitore rispetto al loro indirizzo IP. Quindi, quando Nginx vede che saprà contattare il contenitore PHP-FPM che hai nominato in php-fpmprecedenza e assegnato alla tua mynetworkrete Docker.

Puoi aggiungere quella configurazione Nginx durante il processo di compilazione del tuo contenitore Docker o successivamente dipende da te.


Ricordati anche di assicurarti che php-fpmsia in ascolto sulla porta 9000. Questo sarebbe listen = 9000in /etc/php5/fpm/pool.d/www.conf.
treeface

Grazie @treeface buon punto. Mi sono aggiornato con il tuo commento.
DavidT

8

Come hanno risolto le risposte precedenti, ma dovrebbe essere dichiarato in modo molto esplicito: il codice php deve risiedere nel contenitore php-fpm, mentre i file statici devono risiedere nel contenitore nginx. Per semplicità, la maggior parte delle persone ha semplicemente allegato tutto il codice a entrambi, come ho fatto anche di seguito. In futuro, probabilmente separerò queste diverse parti del codice nei miei progetti per ridurre al minimo quali contenitori hanno accesso a quali parti.

Ho aggiornato i miei file di esempio di seguito con questa ultima rivelazione (grazie @alkaline)

Questa sembra essere l'impostazione minima per la finestra mobile 2.0 in avanti (perché le cose sono diventate molto più semplici nella finestra mobile 2.0)

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

( AGGIORNATO il file docker-compose.yml sopra : per i siti che hanno css, javascript, file statici, ecc., bisogno di quei file accessibili al contenitore nginx. Pur avendo tutto il codice php accessibile al contenitore fpm. Di nuovo, perché il mio codice di base è un mix disordinato di css, js e php, questo esempio allega solo tutto il codice a entrambi i contenitori)

Nella stessa cartella:

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;
    }
}

Nel codice della cartella:

./code/index.php:

<?php
phpinfo();

e non dimenticare di aggiornare il tuo file hosts:

127.0.0.1 site.local.[YOUR URL].com

ed esegui il tuo docker-compose

$docker-compose up -d

e prova l'URL dal tuo browser preferito

site.local.[YOUR URL].com/index.php

1
Il tuo file di configurazione nginx presume che il tuo sito web abbia solo file php. È consigliabile creare una regola di posizione nginx per i file statici (jpg, txt, svg, ...) ed evitare l'interprete php. In tal caso, sia i contenitori nginx che php devono accedere ai file del sito web. La risposta di @iKanor sopra si occupa di questo.
Bernard

Grazie @Alkaline, i file statici sono un problema con la mia risposta originale. In effetti, nginx ha davvero bisogno, come minimo, che i file css e js siano locali su quella macchina per funzionare correttamente.
Phillip

7

Penso che dobbiamo anche dare il volume al contenitore fpm, non è vero? Quindi =>

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

Se non lo faccio, mi imbatto in questa eccezione quando lancio una richiesta, poiché fpm non riesce a trovare il file richiesto:

[errore] 6 # 6: * 4 FastCGI inviato in stderr: "Script primario sconosciuto" durante la lettura dell'intestazione della risposta dall'upstream, client: 172.17.42.1, server: localhost, richiesta: "GET / HTTP / 1.1", upstream: "fastcgi : //172.17.0.81: 9000 ", host:" localhost "


1
Si hai ragione! Dobbiamo condividere file con fpm e nginx
Victor Bocharsky

Ho un esempio di lavoro con Nginxe PHP-FPMsu GitHub
Victor Bocharsky

1

Per chiunque altro

Errore Nginx 403: l'indice della directory di [cartella] è vietato

quando si utilizza index.phpwhile index.htmlfunziona perfettamente e avendo incluso index.phpnell'indice nel blocco server del proprio sito config insites-enabled

server {
    listen 80;

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

    index index.php

    ...
}

Assicurati che il tuo file nginx.conf /etc/nginx/nginx.confcarichi effettivamente la configurazione del tuo sito nel httpblocco ...

http {

    ...

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

    # Load our websites config 
    include /etc/nginx/sites-enabled/*;
}

grazie per questo, vecchio ma ancora informativo, ho dovuto usare / usr / share / nginx / html 👍, grazie
Simon Davies
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.