Làm cách nào để liên kết chính xác các vùng chứa php-fpm và Nginx Docker?


102

Tôi đang cố gắng liên kết 2 vùng chứa riêng biệt:

Vấn đề là các tập lệnh php không hoạt động. Có lẽ cấu hình php-fpm không chính xác. Đây là mã nguồn, trong kho của tôi . Đây là tệp docker-compose.yml:

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

Dockerfilecái mà tôi đã sử dụng để xây dựng hình ảnh tùy chỉnh dựa trên hình ảnh nginx:

FROM nginx

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

Cuối cùng, đây là cấu hình máy chủ ảo Nginx tùy chỉnh của tôi:

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

Ai có thể giúp tôi định cấu hình các vùng chứa này một cách chính xác để thực thi các tập lệnh php không?

PS Tôi chạy các vùng chứa thông qua docker-composer như thế này:

docker-compose up

từ thư mục gốc của dự án.


1
Bạn đã cố định cấu hình chúng như thế nào cho đến nay hoặc bạn đã sử dụng mã nào. Xin đừng bắt tôi đoán tôi là rác rưởi khi đoán.
Matthew Brown hay còn gọi là Chúa Matt,

1
@MatthewBrown Huh, tôi đặt mã của tôi để công kho trên GitHub và nghĩ rằng đây sẽ là đủ, nhưng bạn là đúng, tốt hơn để hiển thị mã ở đây trong câu hỏi của tôi quá.
Victor Bocharsky

khi hình ảnh quay lên, bạn có thể docker execvào vùng chứa đang chạy và ping fpm không?
Vincent De Smet

1
@MatthewBrown vâng, tôi giành được nó, nhờ
Victor Bocharsky

1
Tái bút Tôi cũng đã đạt được một giải pháp làm việc để liên kết NginxPHP-FPMcùng với Vagrant và Ansible. Kiểm tra repo github.com/bocharsky-bw/vagrant-ansible-docker của tôi nếu bạn muốn.
Victor Bocharsky

Câu trả lời:


32

Không hardcode ip của các vùng chứa trong cấu hình nginx, liên kết docker sẽ thêm tên máy chủ của máy được liên kết vào tệp máy chủ của vùng chứa và bạn sẽ có thể ping theo tên máy chủ.

CHỈNH SỬA: Docker 1.9 Networking không còn yêu cầu bạn liên kết các vùng chứa nữa, khi nhiều vùng chứa được kết nối với cùng một mạng, tệp máy chủ của chúng sẽ được cập nhật để chúng có thể kết nối với nhau bằng tên máy chủ.

Mỗi khi một vùng chứa docker quay lên từ một hình ảnh (thậm chí dừng / bắt đầu một vùng chứa hiện có), các vùng chứa sẽ nhận được ip mới được chỉ định bởi máy chủ docker. Các ip này không nằm trong cùng một mạng con với các máy thực của bạn.

xem tài liệu liên kết docker (đây là những gì soạn thư sử dụng trong nền)

nhưng được giải thích rõ ràng hơn trong docker-composetài liệu về liên kết & hiển thị

liên kết

links:
 - db
 - db:database
 - redis

Một mục nhập có tên bí danh sẽ được tạo trong / etc / hosts bên trong các vùng chứa cho dịch vụ này, ví dụ:

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis

lộ ra

Hiển thị các cổng mà không xuất bản chúng lên máy chủ - chúng sẽ chỉ có thể truy cập vào các dịch vụ được liên kết . Chỉ có thể chỉ định cổng nội bộ.

và nếu bạn thiết lập dự án của mình để lấy các cổng + thông tin đăng nhập khác thông qua các biến môi trường, các liên kết sẽ tự động đặt một loạt các biến hệ thống :

Để xem những biến môi trường nào có sẵn cho một dịch vụ, hãy chạy docker-compose run SERVICE env.

name_PORT

URL đầy đủ, ví dụ: DB_PORT = tcp: //172.17.0.5: 5432

name_PORT_num_protocol

URL đầy đủ, ví dụ: DB_PORT_5432_TCP=tcp://172.17.0.5:5432

name_PORT_num_protocol_ADDR

Địa chỉ IP của vùng chứa, ví dụ: DB_PORT_5432_TCP_ADDR=172.17.0.5

name_PORT_num_protocol_PORT

Số cổng tiếp xúc, ví dụ: DB_PORT_5432_TCP_PORT=5432

name_PORT_num_protocol_PROTO

Giao thức (tcp hoặc udp), ví dụ: DB_PORT_5432_TCP_PROTO=tcp

name_NAME

Tên vùng chứa đủ điều kiện, ví dụ: DB_1_NAME=/myapp_web_1/myapp_db_1


2
bạn cũng không cần xuất bản cổng 9000 trên máy chủ, các cổng được mở giữa các bộ chứa docker được liên kết, trừ khi bạn muốn khắc phục sự cố cổng trực tiếp từ máy chủ của mình.
Vincent De Smet

Yeas, bạn nói đúng, cảm ơn. Trong trường hợp của tôi, tôi nên sử dụng fastcgi_pass fpm: 9000 thay vì ip trực tiếp. Tôi không biết rằng Docker thêm nó vào máy chủ lưu trữ tự động, lỗi của tôi.
Victor Bocharsky

Vậy còn cổng, tốt hơn nên sử dụng phơi sáng thay vì cổng ? Hoặc tôi không thể sử dụng bất kỳ cổng nào trong số các cổng này và hiển thị các chỉ thị vì các vùng chứa được liên kết sẽ có quyền truy cập vào cổng này?
Victor Bocharsky

xin lỗi vì trả lời trễ - Tôi nghĩ rằng bạn có thể cần phải sử dụng tiếp xúc, xin lỗi tôi không thể kiểm tra ngay bây giờ
Vincent De Smet

2
--linkshiện đã lỗi thời, theo tài liệu docker mà bạn tham khảo. Họ vẫn đang được hỗ trợ nhưng các kế hoạch rõ ràng là để họ được lỗi thời.
therobyouknow

85

Tôi biết đó là một bài đăng cũ, nhưng tôi đã gặp vấn đề tương tự và không thể hiểu tại sao mã của bạn không hoạt động. Sau rất nhiều thử nghiệm, tôi đã tìm ra lý do.

Có vẻ như fpm nhận đường dẫn đầy đủ từ nginx và cố gắng tìm các tệp trong vùng chứa fpm, vì vậy nó phải giống hệt như server.roottrong cấu hình nginx, ngay cả khi nó không tồn tại trong vùng chứa nginx.

Để lam sang tỏ:

docker-compos.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
LÀM TỐT!!! Đó chính xác là điểm! Tôi đặt gốc nginx thành một đường dẫn thay thế khác /var/www/htmlvới lỗi.
Alfred Huang

3
Ngoài ra, chỉ cần lưu ý rằng :9000cổng đang được sử dụng trong vùng chứa không phải là cổng tiếp xúc với máy chủ của bạn. Tôi đã mất 2 giờ để tìm ra điều này. Hy vọng rằng bạn không cần phải như vậy.
thét lên

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

4
Bạn thực sự không cần phải bao gồm một portsphần nào ở đây. Bạn có thể chỉ cần exposenó nếu nó chưa có trong hình ảnh (có thể là như vậy). Nếu bạn đang thực hiện giao tiếp giữa các vùng chứa, bạn không nên để lộ cổng PHP-FPM.
Seer

Đang tìm kiếm một giải pháp cho AH01071: Got error 'Primary script unknown\n'và vùng chứa php-fpm phải chia sẻ cùng một thư mục với các nút web là giải pháp!
cptPH

23

Như đã chỉ ra trước đây, vấn đề là các tệp không hiển thị bởi vùng chứa fpm. Tuy nhiên, để chia sẻ dữ liệu giữa các vùng chứa, mẫu được đề xuất là sử dụng vùng chứa chỉ dữ liệu (như được giải thích trong bài viết này ).

Câu chuyện ngắn: tạo một vùng chứa chỉ chứa dữ liệu của bạn, chia sẻ nó với một ổ và liên kết ổ này trong các ứng dụng của bạn với volumes_from.

Sử dụng soạn thư (1.6.2 trong máy của tôi), docker-compose.ymltệp sẽ đọc:

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

Lưu ý rằng dataxuất bản một tập được liên kết với nginxfpmcác dịch vụ. Sau đó, Dockerfilecho dịch vụ dữ liệu , có chứa mã nguồn của bạn:

FROM busybox

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

Dockerfileđối với nginx, chỉ thay thế cấu hình mặc định:

FROM nginx

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

Để hoàn thành, đây là tệp cấu hình cần thiết để ví dụ hoạt động:

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

điều này chỉ yêu cầu nginx sử dụng ổ đĩa được chia sẻ làm gốc tài liệu và đặt cấu hình phù hợp để nginx có thể giao tiếp với vùng chứa fpm (nghĩa là: quyền HOST:PORT, là fpm:9000nhờ vào tên máy chủ được xác định bởi soạn thư và SCRIPT_FILENAME).


Có vẻ như Dữ liệu không nhận được cập nhật từ máy chủ tới các vùng chứa và khi tôi thực hiện docker ps -a, tôi thấy vùng chứa dữ liệu bị dừng, đó có phải là vấn đề không?
Aftab Naveed

2
Đó là hành vi được mong đợi. Vùng chứa chỉ dữ liệu không chạy bất kỳ lệnh nào và nó sẽ chỉ được liệt kê là đã dừng. Ngoài ra, vùng Dockerfilechứa dữ liệu đang sao chép các nguồn của bạn vào vùng chứa theo thời gian xây dựng. Đó là lý do tại sao chúng sẽ không được cập nhật nếu bạn thay đổi tệp trong máy chủ. Nếu bạn muốn chia sẻ các nguồn giữa máy chủ và vùng chứa, bạn cần gắn thư mục. Thay đổi datadịch vụ trong tệp soạn thư để tải image: busyboxvà trong volumesphần nhập ./sources:/var/www/html, đâu ./sourceslà đường dẫn đến các nguồn của bạn trong máy chủ lưu trữ.
iKanor

16

Câu trả lời mới

Docker Compose đã được cập nhật. Bây giờ chúng có định dạng tệp phiên bản 2 .

Các tệp phiên bản 2 được hỗ trợ bởi Compose 1.6.0+ và yêu cầu Công cụ Docker của phiên bản 1.10.0+.

Giờ đây, chúng hỗ trợ tính năng kết nối mạng của Docker mà khi chạy sẽ thiết lập một mạng mặc định có tên myapp_default

Từ tài liệu của họ, tệp của bạn sẽ trông giống như dưới đây:

version: '2'

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

Vì những vùng chứa này được tự động thêm vào mạng myapp_default mặc định, chúng sẽ có thể nói chuyện với nhau. Sau đó, bạn sẽ có trong cấu hình Nginx:

fastcgi_pass fpm:9000;

Cũng như đã đề cập bởi @treeface trong phần nhận xét, hãy nhớ đảm bảo PHP-FPM đang lắng nghe trên cổng 9000, điều này có thể được thực hiện bằng cách chỉnh sửa /etc/php5/fpm/pool.d/www.confở nơi bạn cần listen = 9000.

Câu trả lời cũ

Tôi đã giữ phần bên dưới ở đây cho những người sử dụng phiên bản Docker / Docker cũ hơn và muốn biết thông tin.

Tôi tiếp tục tình cờ gặp câu hỏi này trên google khi cố gắng tìm câu trả lời cho câu hỏi này nhưng nó không hoàn toàn là những gì tôi đang tìm kiếm do Q / A nhấn mạnh vào docker-soạn (tại thời điểm viết bài này chỉ có hỗ trợ thử nghiệm cho tính năng kết nối mạng của docker). Vì vậy, đây là tôi tiếp nhận những gì tôi đã học được.

Docker gần đây đã không dùng tính năng liên kết để thay thế cho tính năng mạng của nó

Do đó, bằng cách sử dụng tính năng Docker Networks, bạn có thể liên kết các vùng chứa bằng cách làm theo các bước sau. Để có giải thích đầy đủ về các tùy chọn, hãy đọc trên các tài liệu được liên kết trước đó.

Đầu tiên hãy tạo mạng của bạn

docker network create --driver bridge mynetwork

Tiếp theo, chạy vùng chứa PHP-FPM của bạn để đảm bảo bạn mở cổng 9000 và gán cho mạng mới của bạn ( mynetwork).

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

Bit quan trọng ở đây là --name php-fpmở cuối lệnh là tên, chúng ta sẽ cần điều này sau.

Tiếp theo, chạy vùng chứa Nginx của bạn một lần nữa được gán cho mạng bạn đã tạo.

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

Đối với các vùng chứa PHP và Nginx, bạn cũng có thể thêm --volumes-fromcác lệnh, v.v. theo yêu cầu.

Bây giờ đến cấu hình Nginx. Cái nào sẽ trông giống như sau:

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

Lưu ý fastcgi_pass php-fpm:9000;trong khối vị trí. Đó là nói container liên lạc php-fpmtrên cảng 9000. Khi bạn thêm vùng chứa vào mạng cầu nối Docker, tất cả chúng đều tự động nhận được bản cập nhật tệp máy chủ lưu trữ, đặt tên vùng chứa tương ứng với địa chỉ IP của chúng. Vì vậy, khi Nginx thấy rằng nó sẽ biết liên hệ với vùng chứa PHP-FPM mà bạn đã đặt tên php-fpmtrước đó và được gán cho mynetworkmạng Docker của bạn .

Bạn có thể thêm cấu hình Nginx đó trong quá trình xây dựng vùng chứa Docker của mình hoặc sau đó tùy thuộc vào bạn.


Ngoài ra, hãy nhớ đảm bảo rằng bạn php-fpmđang nghe trên cổng 9000. Đây sẽ là listen = 9000trong /etc/php5/fpm/pool.d/www.conf.
treeface,

Cảm ơn @treeface điểm tốt. Tôi đã cập nhật với bình luận của bạn.
DavidT

8

Như các câu trả lời trước đã giải quyết cho, nhưng cần được tuyên bố rất rõ ràng: mã php cần nằm trong vùng chứa php-fpm, trong khi các tệp tĩnh cần phải nằm trong vùng chứa nginx. Để đơn giản, hầu hết mọi người chỉ đính kèm tất cả mã vào cả hai, như tôi cũng đã thực hiện bên dưới. Nếu trong tương lai, tôi có thể sẽ tách các phần mã khác nhau này ra trong các dự án của riêng mình để giảm thiểu những vùng chứa nào có quyền truy cập vào những phần nào.

Đã cập nhật các tệp ví dụ của tôi bên dưới với tiết lộ mới nhất này (cảm ơn bạn @alkaline)

Đây có vẻ là thiết lập tối thiểu cho docker 2.0 trở đi (vì mọi thứ trở nên dễ dàng hơn trong docker 2.0)

docker-compile.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

( ĐÃ CẬP NHẬT docker-compo.yml ở trên : Đối với các trang web có tệp css, javascript, tệp tĩnh, v.v., bạn sẽ cần các tệp đó có thể truy cập được vào vùng chứa nginx. Trong khi vẫn có tất cả mã php có thể truy cập vào vùng chứa fpm. Một lần nữa, bởi vì mã cơ sở của tôi là một hỗn hợp lộn xộn của css, js và php, ví dụ này chỉ đính kèm tất cả mã vào cả hai vùng chứa)

Trong cùng một thư mục:

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

Trong mã thư mục:

./code/index.php:

<?php
phpinfo();

và đừng quên cập nhật tệp máy chủ của bạn:

127.0.0.1 site.local.[YOUR URL].com

và chạy docker-soạn của bạn

$docker-compose up -d

và thử URL từ trình duyệt yêu thích của bạn

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

1
Tệp cấu hình nginx của bạn giả định rằng trang web của bạn chỉ có tệp php. Cách tốt nhất là tạo quy tắc vị trí nginx cho các tệp tĩnh (jpg, txt, svg, ...) và tránh trình thông dịch php. Trong trường hợp đó, cả vùng chứa nginx và php đều cần quyền truy cập vào các tệp trang web. Câu trả lời của @iKanor ở trên giải quyết vấn đề đó.
Bernard

Cảm ơn @Alkaline, các tệp tĩnh có vấn đề với câu trả lời ban đầu của tôi. Trên thực tế, nginx thực sự cần tối thiểu các tệp css và js là cục bộ cho máy đó để hoạt động bình thường.
Phillip

7

Tôi nghĩ chúng ta cũng cần cung cấp cho thùng chứa fpm âm lượng, phải không? Vì vậy =>

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

Nếu tôi không làm điều này, tôi sẽ gặp trường hợp ngoại lệ này khi kích hoạt một yêu cầu, vì fpm không thể tìm thấy tệp được yêu cầu:

[error] 6 # 6: * 4 FastCGI được gửi trong stderr: "Tập lệnh chính không xác định" trong khi đọc tiêu đề phản hồi từ ngược dòng, máy khách: 172.17.42.1, máy chủ: localhost, yêu cầu: "GET / HTTP / 1.1", ngược dòng: "fastcgi : //172.17.0.81: 9000 ", máy chủ:" localhost "


1
Vâng, bạn đã đúng! Chúng ta phải để chia sẻ file với fpm và nginx
Victor Bocharsky

Tôi có ví dụ làm việc với NginxPHP-FPMtrên GitHub
Victor Bocharsky

1

Đối với bất kỳ ai khác nhận được

Lỗi Nginx 403: chỉ mục thư mục của [thư mục] bị cấm

khi sử dụng index.phpwhile index.htmlhoạt động hoàn hảo và đã được đưa index.phpvào chỉ mục trong khối máy chủ của cấu hình trang web của họ trongsites-enabled

server {
    listen 80;

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

    index index.php

    ...
}

Đảm bảo rằng tệp nginx.conf của bạn /etc/nginx/nginx.confthực sự tải cấu hình trang web của bạn trong httpkhối ...

http {

    ...

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

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

cảm ơn vì điều này, cũ nhưng vẫn còn nhiều thông tin, tôi phải sử dụng / usr / share / nginx / html 👍, cảm ơn
Simon Davies
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.