php-fpm 및 Nginx Docker 컨테이너를 올바르게 연결하는 방법은 무엇입니까?


103

2 개의 별도 컨테이너를 연결하려고합니다.

문제는 PHP 스크립트가 작동하지 않는다는 것입니다. 아마도 php-fpm 구성이 올바르지 않을 수 있습니다. 다음은 내 저장소 에있는 소스 코드 입니다. 다음은 파일입니다 docker-compose.yml.

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

그리고 Dockerfile나는의 nginx 하나에 따라 사용자 정의 이미지를 구축하는 데 사용되는 :

FROM nginx

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

마지막으로 사용자 지정 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;
    }
}

아무도 PHP 스크립트를 실행하기 위해 이러한 컨테이너를 올바르게 구성하는 데 도움을 줄 수 있습니까?

PS 나는 다음과 같이 docker-composer를 통해 컨테이너를 실행합니다.

docker-compose up

프로젝트 루트 디렉토리에서.


1
지금까지 구성을 어떻게 시도했거나 어떤 코드를 사용했는지. 내가 짐작할 때 쓰레기라고 생각하게하지 마세요.
매튜 브라운 주님 일명 매트

1
@MatthewBrown 허, 나는 GitHub의 공개 저장소에 내 코드를 넣고 이것으로 충분할 것이라고 생각하지만 내 질문에도 여기에 코드를 표시하는 것이 옳습니다.
Victor Bocharsky 2015

이미지가 회전 docker exec하면 실행중인 컨테이너로 들어가 fpm을 핑할 수 있습니까?
Vincent De Smet 2015

1
@MatthewBrown 네, 감사합니다 그것을 원
빅터 Bocharsky

1
PS I는 또한 Vagrant 및 Ansible NginxPHP-FPM함께 연결하는 작업 솔루션을 얻었습니다 . 원하는 경우 내 repo github.com/bocharsky-bw/vagrant-ansible-docker를 확인하십시오 .
Victor Bocharsky 2015 년

답변:


32

nginx 구성에서 컨테이너의 IP를 하드 코딩하지 마십시오. docker 링크는 연결된 머신의 호스트 이름을 컨테이너의 호스트 파일에 추가하므로 호스트 이름으로 핑할 수 있습니다.

편집 : Docker 1.9 네트워킹은 더 이상 컨테이너를 연결할 필요가 없으며 여러 컨테이너가 동일한 네트워크에 연결되면 호스트 파일이 업데이트되어 호스트 이름으로 서로 연결할 수 있습니다.

Docker 컨테이너가 이미지에서 회전 할 때마다 (기존 컨테이너를 중지 / 시작할 수도 있음) 컨테이너는 Docker 호스트에 의해 할당 된 새 IP를 가져옵니다. 이 IP는 실제 머신과 동일한 서브넷에 있지 않습니다.

docker linking docs 참조 (이것은 compose가 백그라운드에서 사용하는 것입니다)

그러나 docker-compose링크 및 노출 에 대한 문서 에서 더 명확하게 설명됩니다.

연결

links:
 - db
 - db:database
 - redis

별칭의 이름을 가진 항목은이 서비스에 대한 컨테이너 내부의 / etc / hosts에 생성됩니다. 예 :

172.17.2.186  db
172.17.2.186  database
172.17.2.187  redis

폭로

포트 를 호스트 컴퓨터에 게시하지 않고 노출 합니다 . 연결된 서비스 에서만 액세스 할 수 있습니다 . 내부 포트만 지정할 수 있습니다.

환경 변수를 통해 포트 + 기타 자격 증명을 가져 오도록 프로젝트를 설정하면 링크가 자동으로 시스템 변수를 설정합니다 .

서비스에 사용할 수있는 환경 변수를 확인하려면을 실행하십시오 docker-compose run SERVICE env.

name_PORT

전체 URL, 예 : DB_PORT = tcp : //172.17.0.5 : 5432

name_PORT_num_protocol

전체 URL, 예 : DB_PORT_5432_TCP=tcp://172.17.0.5:5432

name_PORT_num_protocol_ADDR

컨테이너의 IP 주소, 예 : DB_PORT_5432_TCP_ADDR=172.17.0.5

name_PORT_num_protocol_PORT

노출 된 포트 번호, 예 : DB_PORT_5432_TCP_PORT=5432

name_PORT_num_protocol_PROTO

프로토콜 (tcp 또는 udp), 예 : DB_PORT_5432_TCP_PROTO=tcp

name_NAME

완전한 컨테이너 이름 (예 : DB_1_NAME=/myapp_web_1/myapp_db_1


2
또한 호스트에서 포트 9000을 게시 할 필요가 없습니다. 호스트에서 직접 포트 문제를 해결하려는 경우가 아니면 연결된 Docker 컨테이너간에 포트가 열려 있습니다.
Vincent De Smet 2015

네, 맞아요, 고마워요. 제 경우 에는 직접 ip 대신 fastcgi_pass fpm : 9000을 사용해야합니다 . Docker가 자동으로 호스트에 추가한다는 것을 모르겠습니다.
Victor Bocharsky 2015

포트는 어떻습니까? 포트 대신 노출 을 사용하는 것이 좋습니다 . 아니면 연결된 컨테이너가이 포트에 액세스 할 수 있기 때문에이 포트를 사용하고 지시문을 노출 할 수 없습니까?
Victor Bocharsky 2015

죄송합니다 늦게 답장을 - 당신이 미안 내가 지금 확인할 수 없습니다, 노출 사용해야 할 수도 있습니다 생각
빈센트 드 스멧을

2
--links참조하는 도커 문서에 따르면 이제는 더 이상 사용되지 않습니다. 현재 는 여전히 지원되지만 명백한 계획은 폐기 될 것입니다.
therobyouknow

86

나는 그것이 일종의 오래된 게시물이라는 것을 알고 있지만 동일한 문제가 있었고 왜 코드가 작동하지 않았는지 이해할 수 없었습니다. 많은 테스트 후 나는 그 이유를 알아 냈습니다.

fpm이 nginx에서 전체 경로를 수신하고 fpm 컨테이너에서 파일을 찾으려고하는 것처럼 보이므로 정확히 동일해야합니다. server.root 보이므로 nginx 컨테이너에 존재하지 않더라도 nginx 구성에서 .

시연하려면 :

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
잘 했어!!! 그게 바로 요점입니다! nginx 루트를 /var/www/html실패가 아닌 다른 경로로 설정했습니다 .
Alfred Huang

3
또한 :9000호스트에 노출 된 포트가 아닌 컨테이너에서 사용되는 포트 인 메모입니다 . 이것을 알아내는 데 2 ​​시간이 걸렸습니다. 바라건대, 그럴 필요가 없습니다.
비명

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

4
실제로 ports여기에 섹션 을 포함 할 필요는 없습니다 . expose이미지에 아직없는 경우 에만 필요할 수 있습니다 (아마도). 컨테이너 간 통신을 수행하는 경우 PHP-FPM 포트를 노출 하지 않아야 합니다.
Seer

해결책을 찾고 있었고 AH01071: Got error 'Primary script unknown\n'php-fpm 컨테이너가 웹 노드와 동일한 디렉토리를 공유해야한다는 것이 해결책이었습니다!
cptPH

23

이전에 지적했듯이 문제는 fpm 컨테이너에서 파일을 볼 수 없다는 것입니다. 그러나 컨테이너간에 데이터를 공유하기 위해 권장되는 패턴은 데이터 전용 컨테이너를 사용하는 것입니다 ( 이 문서 에서 설명). ).

간단히 말해, 데이터를 보관하는 컨테이너를 만들고 볼륨과 공유하고 앱의이 볼륨을 volumes_from.

compose (내 컴퓨터의 1.6.2)를 사용하면 docker-compose.yml파일이 다음 과 같이 표시 됩니다.

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

및 서비스에 data연결된 볼륨 을 게시 합니다. 그런 다음 소스 코드를 포함 하는 데이터 서비스의 경우 :nginxfpmDockerfile

FROM busybox

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

그리고 Dockerfilenginx의 경우 기본 구성을 대체합니다.

FROM nginx

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

완료를 위해 예제가 작동하는 데 필요한 구성 파일은 다음과 같습니다.

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

(: 권리 즉, 이는 단지 문서 루트로 공유 볼륨을 사용하는 Nginx에 지시하고, FPM 컨테이너와 통신 할 수 있도록 Nginx에 대한 올바른 설정을 설정 HOST:PORT입니다 fpm:9000작성에 의해 정의 된 호스트 이름에 감사하며 SCRIPT_FILENAME).


데이터가 호스트에서 컨테이너로 업데이트되지 않는 것처럼 보이며 docker ps -a를 수행하면 데이터 컨테이너가 중지 된 것을 볼 수 있습니다. 그게 문제입니까?
아프 탑 Naveed

2
그것이 예상되는 행동입니다. 데이터 전용 컨테이너는 어떤 명령도 실행하지 않으며 중지 된 것으로 표시됩니다. 또한 Dockerfile데이터 컨테이너의는 빌드 시간에 소스를 컨테이너에 복사합니다. 그렇기 때문에 호스트에서 파일을 변경하면 업데이트되지 않습니다. 호스트와 컨테이너간에 소스를 공유하려면 디렉토리를 마운트해야합니다. 변경 data부하로 작성 파일에 서비스를 image: busybox하고있는 volumes부분 입력 ./sources:/var/www/html, ./sources호스트에서 소스의 경로입니다.
iKanor

16

새로운 답변

Docker Compose가 업데이트되었습니다. 이제 버전 2 파일 형식이 있습니다.

버전 2 파일은 Compose 1.6.0 이상에서 지원되며 버전 1.10.0 이상의 Docker 엔진이 필요합니다.

이제 Docker의 네트워킹 기능을 지원하며 실행시 myapp_default 라는 기본 네트워크를 설정합니다.

에서 자신의 문서 파일은 다음과 같을 것이다 :

version: '2'

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

이러한 컨테이너는 기본 myapp_default 네트워크에 자동으로 추가 되므로 서로 통신 할 수 있습니다. 그런 다음 Nginx 구성에 있습니다.

fastcgi_pass fpm:9000;

또한 주석에서 @treeface가 언급했듯이 PHP-FPM이 포트 9000에서 수신하는지 확인 /etc/php5/fpm/pool.d/www.conf해야합니다 listen = 9000. 필요한 위치를 편집 하여 수행 할 수 있습니다 .

이전 답변

이전 버전의 Docker / Docker compose를 사용하는 사람들을 위해 여기에 보관했으며 정보를 원합니다.

나는이 질문에 대한 답을 찾으려고 할 때 Google 에서이 질문에 계속 걸려 넘어졌지만 docker-compose에 대한 Q / A 강조로 인해 내가 찾고 있던 것이 아닙니다 도커 네트워킹 기능). 그래서 여기 내가 배운 것에 대한 나의 견해가 있습니다.

Docker는 최근 네트워크 기능 을 위해 링크 기능을 사용하지 않습니다.

따라서 Docker Networks 기능을 사용하면 다음 단계에 따라 컨테이너를 연결할 수 있습니다. 옵션에 대한 자세한 설명은 이전에 링크 된 문서를 참조하십시오.

먼저 네트워크 생성

docker network create --driver bridge mynetwork

다음으로 PHP-FPM 컨테이너를 실행하여 포트 9000을 열고 새 네트워크에 할당하십시오 ( mynetwork).

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

여기서 중요한 부분은 --name php-fpm 부분은 이름 인 명령의 끝 부분입니다. 나중에 필요합니다.

다음으로 Nginx 컨테이너를 다시 실행하여 생성 한 네트워크에 할당합니다.

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

PHP 및 Nginx 컨테이너의 --volumes-from경우 필요에 따라 명령 등을 추가 할 수도 있습니다 .

이제 Nginx 구성이 제공됩니다. 다음과 비슷하게 보일 것입니다.

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

주목 fastcgi_pass php-fpm:9000;위치 블록에. 그것은 php-fpm포트의 연락처 컨테이너 를 말합니다 9000. Docker 브리지 네트워크에 컨테이너를 추가하면 모두 자동으로 호스트 파일 업데이트를 받아 IP 주소에 대해 컨테이너 이름을 입력합니다. 따라서 Nginx가 php-fpm이전에 이름 을 지정하고 mynetworkDocker 네트워크에 할당 한 PHP-FPM 컨테이너에 연결해야한다는 것을 알게되면 알 수 있습니다.

Docker 컨테이너의 빌드 프로세스 중에 또는 나중에 해당 Nginx 구성을 추가 할 수 있습니다.


또한 확인하기 위해 기억 php-fpm이 될 것이다 포트 9000에서 수신 대기 listen = 9000에서 /etc/php5/fpm/pool.d/www.conf.
treeface jul.

감사합니다 @treeface 좋은 지적. 귀하의 의견으로 업데이트했습니다.
철주

8

이전 답변이 해결되었지만 매우 명시 적으로 명시해야합니다. PHP 코드는 php-fpm 컨테이너에 있어야하고 정적 파일은 nginx 컨테이너에 있어야합니다. 간단하게하기 위해 대부분의 사람들은 아래에서 설명한 것처럼 두 가지 모두에 모든 코드를 첨부했습니다. 미래라면 어떤 컨테이너가 어떤 부분에 액세스 할 수 있는지 최소화하기 위해 내 프로젝트에서 코드의 다른 부분을 분리 할 것입니다.

이 최신 계시로 아래 예제 파일을 업데이트했습니다 (@alkaline 감사합니다)

이것은 도커 2.0 포워드에 대한 최소 설정 인 것 같습니다 ( 도커 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

( 위의 docker-compose.yml 업데이트 : css, javascript, static 파일 등이있는 사이트의 경우 nginx 컨테이너에 액세스 할 수있는 파일이 필요합니다. 여전히 fpm 컨테이너에 액세스 할 수있는 모든 PHP 코드를 보유하고 있습니다. 내 기본 코드는 css, js 및 php의 지저분한 혼합입니다.이 예제는 모든 코드를 두 컨테이너에 모두 첨부합니다)

동일한 폴더에서 :

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

폴더 코드에서 :

./code/index.php :

<?php
phpinfo();

호스트 파일을 업데이트하는 것을 잊지 마십시오.

127.0.0.1 site.local.[YOUR URL].com

도커를 실행하십시오.

$docker-compose up -d

좋아하는 브라우저에서 URL을 시도해보세요

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

1
nginx 구성 파일은 웹 사이트에 php 파일 만 있다고 가정합니다. 정적 파일 (jpg, txt, svg, ...)에 대한 nginx 위치 규칙을 만들고 PHP 인터프리터를 사용하지 않는 것이 가장 좋습니다. 이 경우 nginx 및 php 컨테이너 모두 웹 사이트 파일에 액세스해야합니다. 위의 @iKanor의 답변이 처리합니다.
Bernard

감사합니다 @Alkaline, 정적 파일은 원래 답변에 문제가 있습니다. 실제로 nginx는 제대로 작동하기 위해 최소한 css 및 js 파일이 해당 시스템에 로컬이어야합니다.
Phillip

7

또한 fpm 컨테이너에 볼륨을 제공해야한다고 생각합니다. 그래서 =>

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

이 작업을 수행하지 않으면 fpm이 요청 된 파일을 찾을 수 없기 때문에 요청을 실행할 때 다음 예외가 발생합니다.

[오류] 6 # 6 : * 4 FastCGI가 stderr로 전송 됨 : 업스트림에서 응답 헤더를 읽는 동안 "Primary script unknown", 클라이언트 : 172.17.42.1, 서버 : localhost, 요청 : "GET / HTTP / 1.1", 업스트림 : "fastcgi : //172.17.0.81 : 9000 ", 호스트 :"localhost "


1
네, 맞아요! 우리는 FPM과의 nginx와 파일을 공유 할 수 있어야합니다
빅터 Bocharsky

나는 함께 작업 예제가 NginxPHP-FPMGitHub의
빅터 Bocharsky

1

다른 사람을 위해

Nginx 403 오류 : [폴더]의 디렉토리 색인이 금지되었습니다.

index.phpwhile 사용 index.html이 완벽하게 작동 index.php하고 사이트 구성의 서버 블록에 색인에 포함되어 있을 때sites-enabled

server {
    listen 80;

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

    index index.php

    ...
}

의 nginx.conf 파일이 /etc/nginx/nginx.conf실제로 사이트 구성을 http블록 에로드 하는지 확인하십시오 .

http {

    ...

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

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

감사합니다. 오래되었지만 여전히 유익합니다. / usr / share / nginx / html 👍, 감사합니다
Simon Davies
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.