Bagaimana cara menautkan kontainer php-fpm dan Nginx Docker dengan benar?

103

Saya mencoba menautkan 2 wadah terpisah:

Masalahnya adalah skrip php tidak berfungsi. Mungkin konfigurasi php-fpm salah. Ini adalah kode sumbernya, yang ada di repositori saya . Ini filenya docker-compose.yml:

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

dan Dockerfileyang saya gunakan untuk membuat gambar khusus berdasarkan nginx:

FROM nginx

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

Terakhir, berikut adalah konfigurasi virtual host Nginx khusus saya:

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

Adakah yang bisa membantu saya mengkonfigurasi wadah ini dengan benar untuk menjalankan skrip php?

PS Saya menjalankan kontainer melalui buruh pelabuhan-komposer seperti ini:

docker-compose up

dari direktori root proyek.

Victor Bocharsky
sumber
1
Bagaimana Anda mencoba untuk mengkonfigurasinya sejauh ini atau kode apa yang telah Anda gunakan. Tolong jangan membuat saya menebak saya sampah dalam menebak-nebak.
Matthew Brown alias Lord Matt
1
@MatthewBrown Huh, saya meletakkan kode saya ke repositori publik di GitHub dan berpikir ini akan cukup, tetapi Anda benar, lebih baik menunjukkan kode di sini dalam pertanyaan saya juga.
Victor Bocharsky
saat gambar berputar, dapatkah Anda docker execmasuk ke container yang sedang berjalan dan melakukan ping ke fpm?
Vincent De Smet
1
@MatthewBrown ya, saya memenangkannya, terima kasih
Victor Bocharsky
1
PS I juga mencapai solusi kerja untuk menghubungkan Nginxdan PHP-FPM bersama dengan Gelandangan dan Ansible. Periksa repo saya github.com/bocharsky-bw/vagrant-ansible-docker jika Anda mau.
Victor Bocharsky

Jawaban:

32

Jangan melakukan hardcode ip kontainer di konfigurasi nginx, tautan pekerja pelabuhan menambahkan nama host dari mesin yang ditautkan ke file host dari kontainer dan Anda harus dapat melakukan ping dengan nama host.

EDIT: Jaringan Docker 1.9 tidak lagi mengharuskan Anda untuk menghubungkan kontainer, ketika beberapa kontainer terhubung ke jaringan yang sama, file host mereka akan diperbarui sehingga mereka dapat menjangkau satu sama lain dengan nama host.

Setiap kali kontainer buruh pelabuhan berputar dari gambar (bahkan menghentikan / memulai kontainer yang ada) kontainer mendapatkan ip baru yang ditetapkan oleh tuan rumah buruh pelabuhan. Ip ini tidak berada di subnet yang sama dengan mesin Anda yang sebenarnya.

lihat dokumen penautan buruh pelabuhan (inilah yang digunakan penulisan di latar belakang)

tetapi lebih jelas dijelaskan dalam docker-composedokumen tentang tautan & ekspos

tautan

links:
 - db
 - db:database
 - redis

Entri dengan nama alias akan dibuat di / etc / hosts di dalam kontainer untuk layanan ini, misalnya:

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis

membuka

Buka port tanpa memublikasikannya ke mesin host - itu hanya akan diakses ke layanan yang ditautkan . Hanya port internal yang dapat ditentukan.

dan jika Anda menyiapkan proyek Anda untuk mendapatkan port + kredensial lain melalui variabel lingkungan, tautan secara otomatis menetapkan banyak variabel sistem :

Untuk melihat variabel lingkungan apa yang tersedia untuk layanan, jalankan docker-compose run SERVICE env.

name_PORT

URL lengkap, misalnya DB_PORT = tcp: //172.17.0.5: 5432

name_PORT_num_protocol

URL lengkap, mis DB_PORT_5432_TCP=tcp://172.17.0.5:5432

name_PORT_num_protocol_ADDR

Alamat IP wadah, mis DB_PORT_5432_TCP_ADDR=172.17.0.5

name_PORT_num_protocol_PORT

Nomor port yang terlihat, mis DB_PORT_5432_TCP_PORT=5432

name_PORT_num_protocol_PROTO

Protokol (tcp atau udp), mis DB_PORT_5432_TCP_PROTO=tcp

name_NAME

Nama kontainer yang sepenuhnya memenuhi syarat, mis DB_1_NAME=/myapp_web_1/myapp_db_1

Vincent De Smet
sumber
2
Anda juga tidak perlu menerbitkan port 9000 pada host, port terbuka di antara kontainer buruh pelabuhan yang ditautkan, kecuali Anda ingin memecahkan masalah port langsung dari host Anda.
Vincent De Smet
Ya, Anda benar, terima kasih. Dalam kasus saya, saya harus menggunakan fastcgi_pass fpm: 9000 daripada ip langsung. Saya tidak tahu bahwa Docker menambahkannya ke host secara otomatis, saya buruk.
Victor Bocharsky
Bagaimana dengan port, jadi lebih baik menggunakan expose daripada port ? Atau saya tidak dapat menggunakan salah satu port ini dan mengekspos arahan karena kontainer yang terhubung akan memiliki akses ke port ini?
Victor Bocharsky
maaf atas balasan terlambat - Saya pikir Anda mungkin perlu menggunakan ekspos, maaf saya tidak bisa memeriksa sekarang
Vincent De Smet
2
--linkssekarang sudah usang, menurut dokumentasi buruh pelabuhan yang Anda rujuk. Mereka saat ini masih didukung tetapi rencana yang jelas agar mereka ditinggalkan.
therobyouknow
86

Saya tahu ini semacam posting lama, tetapi saya memiliki masalah yang sama dan tidak dapat memahami mengapa kode Anda tidak berfungsi. Setelah BANYAK tes, saya menemukan alasannya.

Sepertinya fpm menerima jalur lengkap dari nginx dan mencoba menemukan file di penampung fpm, jadi itu harus persis sama dengan server.root di konfigurasi nginx, meskipun tidak ada di penampung nginx.

Untuk menunjukkan:

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
sumber
4
SUDAH SELESAI DILAKUKAN DENGAN BAIK!!! Itulah intinya! Saya mengatur root nginx ke jalur alternatif selain /var/www/htmldengan kegagalan.
Alfred Huang
3
Juga, hanya catatan bahwa :9000port yang digunakan di wadah bukan yang terekspos ke host Anda. Butuh waktu 2 jam untuk menyelesaikannya. Mudah-mudahan, Anda tidak perlu melakukannya.
berteriak
1
services.fpm.ports is invalid: Invalid port ":9000", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
030
4
Anda tidak benar-benar perlu memasukkan satu portsbagian sama sekali di sini. Anda mungkin hanya perlu melakukannya exposejika belum ada dalam gambar (yang mungkin sudah ada). Jika Anda melakukan komunikasi antar-kontainer, Anda tidak boleh mengekspos port PHP-FPM.
Peramal
Sedang mencari solusi untuk AH01071: Got error 'Primary script unknown\n'dan bahwa wadah php-fpm harus berbagi direktori yang sama dengan node web adalah solusinya!
cptPH
23

Seperti yang ditunjukkan sebelumnya, masalahnya adalah file tidak terlihat oleh penampung fpm. Namun untuk berbagi data di antara penampung, pola yang disarankan menggunakan penampung hanya data (seperti yang dijelaskan dalam artikel ini ).

Singkat cerita: buat wadah yang hanya menyimpan data Anda, bagikan dengan volume, dan tautkan volume ini di aplikasi Anda dengan volumes_from.

Menggunakan compose (1.6.2 di mesin saya), docker-compose.ymlfile akan membaca:

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

Perhatikan bahwa datamenerbitkan volume yang terkait dengan layanan nginxdan fpm. Kemudian Dockerfileuntuk layanan data , yang berisi kode sumber Anda:

FROM busybox

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

Dan Dockerfileuntuk nginx, itu hanya menggantikan konfigurasi default:

FROM nginx

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

Demi penyelesaian, berikut file konfigurasi yang diperlukan agar contoh berfungsi:

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

yang hanya memberi tahu nginx untuk menggunakan volume bersama sebagai root dokumen, dan menyetel konfigurasi yang tepat untuk nginx agar dapat berkomunikasi dengan penampung fpm (yaitu: hak HOST:PORT, yang fpm:9000berkat nama host yang ditentukan oleh compose, dan the SCRIPT_FILENAME).

iKanor
sumber
Sepertinya Data tidak mendapatkan update dari host ke container, dan ketika saya melakukan docker ps -a Saya melihat container data berhenti, apakah itu menjadi masalah?
Aftab Naveed
2
Itu perilaku yang diharapkan. Penampung khusus data tidak menjalankan perintah apa pun, dan hanya akan terdaftar sebagai dihentikan. Selain itu, Dockerfilepenampung data menyalin sumber Anda ke penampung pada waktu pembuatan. Itulah mengapa mereka tidak akan diperbarui jika Anda mengubah file di host. Jika Anda ingin membagikan sumber antara host dan container, Anda perlu memasang direktori. Ubah datalayanan di file tulis yang akan dimuat image: busybox, dan di volumesbagian masukkan ./sources:/var/www/html, di mana ./sourcesjalur ke sumber Anda di host.
iKanor
16

Jawaban Baru

Docker Compose telah diperbarui. Mereka sekarang memiliki format file versi 2 .

File versi 2 didukung oleh Compose 1.6.0+ dan memerlukan Mesin Docker versi 1.10.0+.

Mereka sekarang mendukung fitur jaringan Docker yang ketika dijalankan mengatur jaringan default yang disebut myapp_default

Dari dokumentasinya, file Anda akan terlihat seperti di bawah ini:

version: '2'

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

Karena kontainer ini secara otomatis ditambahkan ke jaringan default myapp_default, mereka akan dapat saling berbicara. Anda kemudian akan memiliki konfigurasi Nginx:

fastcgi_pass fpm:9000;

Juga seperti yang disebutkan oleh @treeface di komentar ingat untuk memastikan PHP-FPM mendengarkan pada port 9000, ini dapat dilakukan dengan mengedit di /etc/php5/fpm/pool.d/www.conftempat yang Anda perlukanlisten = 9000 .

Jawaban Lama

Saya telah menyimpan di bawah ini di sini untuk mereka yang menggunakan versi lama penulisan Docker / Docker dan ingin informasinya.

Saya terus tersandung pada pertanyaan ini di google ketika mencoba menemukan jawaban untuk pertanyaan ini tetapi itu tidak cukup apa yang saya cari karena penekanan Q / A pada docker-compose (yang pada saat penulisan hanya memiliki dukungan eksperimental untuk fitur jaringan buruh pelabuhan). Jadi inilah pendapat saya tentang apa yang telah saya pelajari.

Docker baru - baru ini menghentikan fitur tautannya demi fitur jaringannya

Oleh karena itu, dengan menggunakan fitur Jaringan Docker Anda dapat menautkan kontainer dengan mengikuti langkah-langkah berikut. Untuk penjelasan lengkap tentang opsi, baca di dokumen yang ditautkan sebelumnya.

Pertama buat jaringan Anda

docker network create --driver bridge mynetwork

Selanjutnya jalankan penampung PHP-FPM Anda memastikan Anda membuka port 9000 dan menetapkan ke jaringan baru Anda ( mynetwork).

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

Bagian penting di sini adalah --name php-fpm di akhir perintah yang merupakan namanya, kita akan membutuhkannya nanti.

Selanjutnya jalankan container Nginx Anda lagi tetapkan ke jaringan yang Anda buat.

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

Untuk wadah PHP dan Nginx, Anda juga dapat menambahkan --volumes-fromperintah dll sesuai kebutuhan.

Sekarang sampai pada konfigurasi Nginx. Yang seharusnya terlihat seperti ini:

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

Perhatikan fastcgi_pass php-fpm:9000;di blok lokasi. Itu mengatakan wadah kontak php-fpmdi pelabuhan 9000. Ketika Anda menambahkan kontainer ke jaringan jembatan Docker, mereka semua secara otomatis mendapatkan pembaruan file host yang menempatkan nama kontainer mereka pada alamat IP mereka. Jadi ketika Nginx melihat bahwa ia akan tahu untuk menghubungi wadah PHP-FPM yang Anda beri nama php-fpmsebelumnya dan ditugaskan ke Andamynetwork jaringan Docker .

Anda dapat menambahkan konfigurasi Nginx itu selama proses pembuatan container Docker Anda atau setelahnya terserah Anda.

DavidT
sumber
Juga ingat untuk memastikan php-fpmsedang mendengarkan pada port 9000. Ini akan listen = 9000masuk /etc/php5/fpm/pool.d/www.conf.
treeface
Terima kasih @treeface poin yang bagus. Saya telah memperbarui dengan komentar Anda.
DavidT
8

Seperti jawaban sebelumnya telah dipecahkan, tetapi harus dinyatakan dengan sangat eksplisit: kode php harus tinggal di wadah php-fpm, sedangkan file statis harus tinggal di wadah nginx. Untuk kesederhanaan, kebanyakan orang baru saja melampirkan semua kode ke keduanya, seperti yang juga saya lakukan di bawah ini. Jika di masa mendatang, saya kemungkinan akan memisahkan bagian kode yang berbeda ini dalam proyek saya sendiri untuk meminimalkan wadah mana yang memiliki akses ke bagian mana.

Memperbarui file contoh saya di bawah dengan wahyu terbaru ini (terima kasih @alkaline)

Ini tampaknya menjadi pengaturan minimum untuk docker 2.0 ke depan (karena segalanya menjadi jauh lebih mudah di buruh pelabuhan 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

( DIPERBARUI docker-compose.yml di atas : Untuk situs yang memiliki css, javascript, file statis, dll., Anda memerlukan file tersebut yang dapat diakses ke penampung nginx. Sambil tetap memiliki semua kode php yang dapat diakses ke penampung fpm. Sekali lagi, karena kode dasar saya adalah campuran css, js, dan php yang berantakan, contoh ini hanya melampirkan semua kode ke kedua wadah)

Di folder yang sama:

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

Dalam kode folder:

./code/index.php:

<?php
phpinfo();

dan jangan lupa untuk memperbarui file host Anda:

127.0.0.1 site.local.[YOUR URL].com

dan jalankan docker-compose Anda

$docker-compose up -d

dan coba URL dari browser favorit Anda

site.local.[YOUR URL].com/index.php
Phillip
sumber
1
File konfigurasi nginx Anda mengasumsikan bahwa situs web Anda hanya memiliki file php. Merupakan praktik terbaik untuk membuat aturan lokasi nginx untuk file statis (jpg, txt, svg, ...) dan menghindari interpreter php. Dalam hal ini, wadah nginx dan php membutuhkan akses ke file situs web. Jawaban @iKanor di atas menangani itu.
Bernard
Terima kasih @Alkaline, file statis bermasalah dengan jawaban asli saya. Nyatanya, nginx benar-benar membutuhkan, minimal, file css dan js menjadi lokal ke mesin itu agar bisa bekerja dengan baik.
Phillip
7

Saya pikir kita juga perlu memberikan volume pada wadah fpm, bukan? Jadi =>

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

Jika saya tidak melakukan ini, saya mengalami pengecualian ini saat menjalankan permintaan, karena fpm tidak dapat menemukan file yang diminta:

[kesalahan] 6 # 6: * 4 FastCGI dikirim dalam stderr: "Skrip utama tidak diketahui" saat membaca header respons dari hulu, klien: 172.17.42.1, server: localhost, permintaan: "GET / HTTP / 1.1", upstream: "fastcgi : //172.17.0.81: 9000 ", host:" localhost "

leberknecht
sumber
1
Ya kamu benar! Kita harus berbagi file dengan fpm dan nginx
Victor Bocharsky
Saya memiliki contoh kerja dengan Nginxdan PHP-FPMdi GitHub
Victor Bocharsky
1

Untuk siapa saja yang mendapatkan

Kesalahan Nginx 403: indeks direktori [folder] dilarang

saat menggunakan index.phpwhile index.htmlberfungsi dengan sempurna dan telah memasukkan index.phpindeks di blok server konfigurasi situs merekasites-enabled

server {
    listen 80;

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

    index index.php

    ...
}

Pastikan file nginx.conf Anda /etc/nginx/nginx.confbenar-benar memuat konfigurasi situs Anda di httpblok ...

http {

    ...

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

    # Load our websites config 
    include /etc/nginx/sites-enabled/*;
}
myol
sumber
terima kasih untuk ini, lama tapi masih informatif, saya harus menggunakan / usr / share / nginx / html 👍, terima kasih
Simon Davies