Docker Networking - nginx: [emerg] host not found in upstream 문제?

Docker 1.9와 Docker-Compose 1.5의 네트워킹 기능을 사용하여 기존의 링크(link) 방식을 대체하려고 마이그레이션을 시작했습니다. 지금까지는 링크를 사용하여 nginx가 다른 서버의 php5-fpm fastcgi 서버에 문제없이 연결되었는데…

docker-compose --x-networking up 명령어를 사용하여 php-fpm, mongo, nginx 컨테이너를 실행하면 nginx가 바로 종료되며 다음과 같은 에러가 발생합니다:

[emerg] 1#1: host not found in upstream “waapi_php_1” in /etc/nginx/conf.d/default.conf:16

그런데, php와 mongo 컨테이너가 실행된 상태에서 docker-compose 명령어를 다시 실행하면 (nginx는 종료된 상태), nginx가 정상적으로 시작되고 이후에는 잘 동작합니다.

아래는 docker-compose.yml 파일입니다:

nginx:
  image: nginx
  ports:
    - "42080:80"
  volumes:
    - ./config/docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro

php:
  build: config/docker/php
  ports:
    - "42022:22"
  volumes:
    - .:/var/www/html
  env_file: config/docker/php/.env.development

mongo:
  image: mongo
  ports:
    - "42017:27017"
  volumes:
    - /var/mongodata/wa-api:/data/db
  command: --smallfiles

아래는 nginx의 default.conf` 파일입니다:

server {
    listen  80;

    root /var/www/test;

    error_log /dev/stdout debug;
    access_log /dev/stdout;

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

    location ~ ^/.+\.php(/|$) {
        # Referencing the php service host (Docker)
        fastcgi_pass waapi_php_1:9000;

        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;

        # We must reference the document_root of the external server ourselves here.
        fastcgi_param SCRIPT_FILENAME /var/www/html/public$fastcgi_script_name;

        fastcgi_param HTTPS off;
    }
}

nginx를 단일 docker-compose 호출로 정상적으로 작동하게 하려면 어떻게 해야 하나요?

[CloudBro AI Bot Response]
이 문제는 Docker Compose의 네트워크 초기화 타이밍과 DNS 해석 문제에서 비롯됩니다. nginx 컨테이너가 시작할 때 waapi_php_1 호스트명이 아직 DNS에 등록되지 않아 “host not found in upstream” 에러가 발생하는 것입니다.

Docker Compose 1.5와 Docker 1.9의 네트워킹 기능(--x-networking)은 각 컨테이너에 서비스명 기반의 DNS 이름 해석을 제공합니다. 즉, 컨테이너 간 통신 시 컨테이너 이름(php, mongo, nginx)을 직접 호스트명으로 사용할 수 있어야 합니다. 그런데 현재 fastcgi_pass waapi_php_1:9000;로 되어 있는데, 이는 Docker Compose가 생성한 컨테이너 이름이며, Compose 네트워크 내에서의 서비스 이름(php)과 다릅니다.

해결 방법

  1. upstream 호스트명을 서비스명으로 변경
    default.conf에서 fastcgi_pass waapi_php_1:9000;fastcgi_pass php:9000;으로 변경하세요.

    fastcgi_pass php:9000;
    

    Docker Compose 네트워크는 서비스명을 DNS 이름으로 인식하므로, php로 지정하면 컨테이너가 시작되면서 바로 이름 해석이 가능합니다.

  2. docker-compose.yml에 네트워크 명시
    Docker Compose 1.5에서 --x-networking이 실험적 기능이었기 때문에, 명시적으로 네트워크를 정의하고 각 서비스에 연결해주는 것이 안정적입니다.

    예를 들어:

    version: "2"
    services:
      nginx:
        image: nginx
        ports:
          - "42080:80"
          -        volumes:
          -          - ./config/docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
          -        networks:
          -          - waapi_net
      php:
        build: config/docker/php
        ports:
          - "42022:22"
          -        volumes:
          -          - .:/var/www/html
          -        env_file: config/docker/php/.env.development
          -        networks:
          -          - waapi_net
      mongo:
        image: mongo
        ports:
          - "42017:27017"
          -        volumes:
          -          - /var/mongodata/wa-api:/data/db
          -        command: --smallfiles
          -        networks:
          -          - waapi_net
    networks:
      waapi_net:
        driver: bridge
    
  3. 컨테이너 시작 순서 보장
    네트워크 이름 해석 문제 외에도 nginxphp가 완전히 시작되기 전에 실행되어 연결이 실패할 수 있습니다. 이를 방지하기 위해 docker-compose에서 depends_on을 사용해 nginxphp에 의존하도록 설정할 수 있습니다.

    nginx:
      ...
      depends_on:
        - php
        -    ```
    다만 `depends_on`은 컨테이너가 "시작된" 상태만 보장할 뿐, 서비스가 완전히 준비된 상태까지는 보장하지 않습니다. 필요하다면 `wait-for-it.sh` 같은 스크립트를 통해 `php-fpm` 포트가 열릴 때까지 대기하는 방법도 고려하세요.
    
    

요약

  • fastcgi_pass에서 컨테이너 이름 대신 서비스명(php)을 사용하세요.
    • Compose 파일에 명시적으로 네트워크를 정의하고 모든 서비스가 같은 네트워크에 속하도록 하세요.
    • depends_on으로 컨테이너 시작 순서를 지정하고, 필요시 서비스 준비 상태를 체크하는 스크립트를 추가하세요.
      이렇게 하면 docker-compose up 한 번에 모든 컨테이너가 정상적으로 네트워킹되어 nginx가 바로 php-fpm에 연결할 수 있습니다.