[nginx] Nginx를 업스트림 프록시로 사용하도록 Docker 포트 매핑을 구성하는 방법은 무엇입니까?

업데이트 II

지금은 2015 년 7 월 16 일이고 상황이 다시 바뀌 었습니다. 나는에서이 자동적 인 컨테이너 발견 한 제이슨 와일더을 :
https://github.com/jwilder/nginx-proxy그것은 약으로 오래가 걸립니다이 문제를 해결 docker run컨테이너. 이것이 제가이 문제를 해결하기 위해 사용하고있는 해결책입니다.

최신 정보

이제 2015 년 7 월이며 Docker 컨테이너 네트워킹과 관련하여 상황이 크게 변경되었습니다. 이제이 문제를 다양한 방식으로 해결하는 다양한 제품이 있습니다.

이 게시물을 사용 docker --link하여 서비스 검색 에 대한 접근 방식에 대한 기본적인 이해를 얻어야합니다. 서비스 검색 에 대한 접근 방식은 기본적이며 매우 잘 작동하며 실제로는 대부분의 다른 솔루션보다 멋진 춤이 덜 필요합니다. 특정 클러스터의 개별 호스트에 컨테이너를 네트워크화하는 것은 매우 어렵고, 네트워크가 연결되면 컨테이너를 다시 시작할 수 없다는 점에서 제한적이지만 동일한 호스트의 컨테이너를 네트워크에 빠르고 비교적 쉽게 연결할 수있는 방법을 제공합니다. 이 문제를 해결하는 데 사용할 소프트웨어가 실제로 내부에서 수행하는 작업에 대한 아이디어를 얻는 좋은 방법입니다.

또한 Docker의 초기 network, Hashicorp consul, Weaveworks weave, Jeff Lindsay ‘s progrium/consul&gliderlabs/registrator , Google을 확인하고 싶을 것입니다 Kubernetes.

이 또한의 CoreOS의 활용 제품 etcd, fleetflannel.

정말 파티를하고 싶다면 클러스터를 가동하여 Mesosphere, 또는 Deis, 또는 을 실행할 수 있습니다 Flynn.

네트워킹이 처음이라면 (나와 같은) 돋보기를 꺼내서 Wi-Hi-Fi에서 “Paint The Sky With Stars — The Best of Enya” 를 팝업 하고 맥주를 크래킹해야합니다. 당신이하려는 것이 정확히 무엇인지 정말로 이해하기 전에. 힌트 : 당신은을 구현하기 위해 노력하고 Service Discovery Layer당신에 Cluster Control Plane. 토요일 밤을 보내는 아주 좋은 방법입니다.

그것은 많은 재미 있어요,하지만 난 다이빙 직전에 일반적으로 네트워킹에 대한 더 나은 자신을 교육하는 시간을 가지고 좋겠 나는 결국 호의적 인 디지털 오션 튜토리얼 신에서 몇 게시물을 발견. Introduction to Networking TerminologyUnderstanding ... Networking. 잠수하기 전에 먼저 몇 번 읽는 것이 좋습니다.

즐기세요!

원본 게시물

Docker컨테이너에 대한 포트 매핑을 파악할 수없는 것 같습니다 . 특히 동일한 서버의 다른 포트에서 수신 대기하면서 Nginx에서 다른 컨테이너로 요청을 전달하는 방법.

다음과 같은 Nginx 컨테이너에 대한 Dockerfile이 있습니다.

FROM ubuntu:14.04
MAINTAINER Me <me@myapp.com>

RUN apt-get update && apt-get install -y htop git nginx

ADD sites-enabled/api.myapp.com /etc/nginx/sites-enabled/api.myapp.com
ADD sites-enabled/app.myapp.com /etc/nginx/sites-enabled/app.myapp.com
ADD nginx.conf /etc/nginx/nginx.conf

RUN echo "daemon off;" >> /etc/nginx/nginx.conf

EXPOSE 80 443

CMD ["service", "nginx", "start"]

그리고 api.myapp.com구성 파일은 다음과 같습니다.

upstream api_upstream{

    server 0.0.0.0:3333;

}


server {

    listen 80;
    server_name api.myapp.com;
    return 301 https://api.myapp.com/$request_uri;

}


server {

    listen 443;
    server_name api.mypp.com;

    location / {

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_pass http://api_upstream;

    }

}

그리고 또 다른 app.myapp.com것도.

그런 다음 실행합니다.

sudo docker run -p 80:80 -p 443:443 -d --name Nginx myusername/nginx

그리고 모든 것이 정상이지만 요청이 다른 컨테이너 / 포트로 전달되지 않습니다. 그리고 Nginx 컨테이너로 ssh하고 로그를 검사하면 오류가 표시되지 않습니다.

도움이 필요하세요?



답변

@ T0xicCode의 대답 은 정확하지만 실제로 작동하는 솔루션을 구현하는 데 실제로 약 20 시간이 걸렸기 때문에 세부 사항을 확장 할 것이라고 생각했습니다.

자체 컨테이너에서 Nginx를 실행하고이를 역방향 프록시로 사용하여 동일한 서버 인스턴스에서 여러 애플리케이션의 부하를 분산하려는 경우 따라야 할 단계는 다음과 같습니다.

컨테이너 연결

docker run일반적으로 셸 스크립트를에 입력하여 컨테이너를 사용할 때 실행중인User Data 다른 컨테이너 에 대한 링크를 선언 할 수 있습니다 . 즉, 컨테이너를 순서대로 시작해야하며 후자의 컨테이너 만 이전 컨테이너에 연결할 수 있습니다. 이렇게 :

#!/bin/bash
sudo docker run -p 3000:3000 --name API mydockerhub/api
sudo docker run -p 3001:3001 --link API:API --name App mydockerhub/app
sudo docker run -p 80:80 -p 443:443 --link API:API --link App:App --name Nginx mydockerhub/nginx

이 예에서는 그래서, API용기는 어떤 다른 사람에 연결되지 않지만
App용기에 연결되어 APINginx모두 연결되어 APIApp.

그 결과 및 컨테이너 내에있는 envvars 및 /etc/hosts파일 이 변경됩니다 . 결과는 다음과 같습니다.
APIApp

/ etc / hosts

컨테이너 cat /etc/hosts내에서 실행 Nginx하면 다음이 생성됩니다.

172.17.0.5  0fd9a40ab5ec
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3  App
172.17.0.2  API

ENV 변수

컨테이너 env내에서 실행 Nginx하면 다음이 생성됩니다.

API_PORT=tcp://172.17.0.2:3000
API_PORT_3000_TCP_PROTO=tcp
API_PORT_3000_TCP_PORT=3000
API_PORT_3000_TCP_ADDR=172.17.0.2

APP_PORT=tcp://172.17.0.3:3001
APP_PORT_3001_TCP_PROTO=tcp
APP_PORT_3001_TCP_PORT=3001
APP_PORT_3001_TCP_ADDR=172.17.0.3

실제 변수의 많은 부분을 잘라 냈지만 위의 내용은 트래픽을 컨테이너로 프록시하는 데 필요한 핵심 값입니다.

실행중인 컨테이너 내에서 위의 명령을 실행하는 셸을 얻으려면 다음을 사용하세요.

sudo docker exec -i -t Nginx bash

이제 연결된 컨테이너에 대한 로컬 IP 주소를 포함하는 /etc/hosts파일 항목과 env변수 가 모두 있음을 알 수 있습니다 . 내가 말할 수있는 한, 이것은 링크 옵션이 선언 된 컨테이너를 실행할 때 발생하는 모든 것입니다. 그러나 이제이 정보를 사용 nginx하여 Nginx컨테이너 내 에서 구성 할 수 있습니다 .

Nginx 구성

이것은 약간 까다로워지고 몇 가지 옵션이 있습니다. 생성 된 /etc/hosts파일 의 항목을 가리 키도록 사이트를 구성하도록 선택 docker하거나, ENV변수를 활용 하고 IP를 삽입 하기 위해 폴더에 있을 수있는 다른 conf 파일 에서 문자열 대체 (I used sed)를 실행할 nginx.conf수 있습니다. /etc/nginx/sites-enabled가치.

옵션 A : ENV 변수를 사용하여 Nginx 구성

이것은 /etc/hosts파일 옵션을 작동 시킬 수 없기 때문에 내가 사용했던
옵션입니다. 곧 옵션 B를 시도하고이 게시물을 발견 한 내용으로 업데이트 할 것입니다.

이 옵션과 /etc/hosts파일 옵션 사용의 주요 차이점은 Dockerfile쉘 스크립트를 CMD인수 로 사용하도록 작성하는 방법 이며, 차례로 문자열 대체를 처리 ENV하여 conf 파일로 IP 값을 복사합니다 .

내가 만든 구성 파일 세트는 다음과 같습니다.

Dockerfile

FROM ubuntu:14.04
MAINTAINER Your Name <you@myapp.com>

RUN apt-get update && apt-get install -y nano htop git nginx

ADD nginx.conf /etc/nginx/nginx.conf
ADD api.myapp.conf /etc/nginx/sites-enabled/api.myapp.conf
ADD app.myapp.conf /etc/nginx/sites-enabled/app.myapp.conf
ADD Nginx-Startup.sh /etc/nginx/Nginx-Startup.sh

EXPOSE 80 443

CMD ["/bin/bash","/etc/nginx/Nginx-Startup.sh"]

nginx.conf

daemon off;
user www-data;
pid /var/run/nginx.pid;
worker_processes 1;


events {
    worker_connections 1024;
}


http {

    # Basic Settings

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 33;
    types_hash_max_size 2048;

    server_tokens off;
    server_names_hash_bucket_size 64;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;


    # Logging Settings
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;


    # Gzip Settings

gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 3;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types text/plain text/xml text/css application/x-javascript application/json;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";

    # Virtual Host Configs
    include /etc/nginx/sites-enabled/*;

    # Error Page Config
    #error_page 403 404 500 502 /srv/Splash;


}

참고 : 컨테이너가 시작된 후 즉시 종료되지 않도록 파일 에 포함 daemon off;하는 것이 중요합니다 nginx.conf.

api.myapp.conf

upstream api_upstream{
    server APP_IP:3000;
}

server {
    listen 80;
    server_name api.myapp.com;
    return 301 https://api.myapp.com/$request_uri;
}

server {
    listen 443;
    server_name api.myapp.com;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        proxy_pass http://api_upstream;
    }

}

Nginx-Startup.sh

#!/bin/bash
sed -i 's/APP_IP/'"$API_PORT_3000_TCP_ADDR"'/g' /etc/nginx/sites-enabled/api.myapp.com
sed -i 's/APP_IP/'"$APP_PORT_3001_TCP_ADDR"'/g' /etc/nginx/sites-enabled/app.myapp.com

service nginx start

nginx.conf및의 대부분의 내용에 대해 숙제하는 것은 귀하에게 맡기겠습니다 api.myapp.conf.

마법 은 우리 와 파일 의 블록에 쓴 자리 표시 자 에서 문자열 교체를 수행 Nginx-Startup.sh하는 sed데 사용 됩니다 .APP_IPupstreamapi.myapp.confapp.myapp.conf

이 ask.ubuntu.com 질문은 매우 잘 설명합니다.
명령을 사용하여 파일 내에서 텍스트 찾기 및 바꾸기

GOTCHA
OSX에서 sed옵션, 특히 -i플래그를 다르게 처리합니다 . 우분투에서는 -i플래그가 ‘in place’교체를 처리합니다. 파일을 열고 텍스트를 변경 한 다음 동일한 파일을 ‘저장’합니다. OSX에서 -i플래그 에는 결과 파일에 적용 할 파일 확장자 가 필요 합니다. 확장자가없는 파일로 작업하는 경우 -i플래그 값으로 ”를 입력해야합니다 .

GOTCHAsed 교체하려는 문자열을 찾는 데 사용
하는 정규식 내에서 ENV 변수를 사용하려면 var를 큰 따옴표로 묶어야합니다. 따라서 엉뚱 해 보이지만 올바른 구문은 위와 같습니다.

따라서 docker는 컨테이너를 시작하고 Nginx-Startup.sh스크립트를 실행 하여 명령 에서 제공 한 해당 변수로 sedAPP_IP을 변경하는 데 사용 되었습니다 . 이제 컨테이너를 시작할 때 docker가 설정 한 변수 의 IP 주소가 있는 conf 파일이 디렉터리 내에 있습니다. 파일 내 에서 블록이 다음과 같이 변경된 것을 볼 수 있습니다 .ENVsed/etc/nginx/sites-enabledENVapi.myapp.confupstream

upstream api_upstream{
    server 172.0.0.2:3000;
}

표시되는 IP 주소는 다를 수 있지만 일반적으로 172.0.0.x.

이제 모든 것이 적절하게 라우팅되어야합니다.

GOTCHA
초기 인스턴스 시작을 실행 한 후에는 컨테이너를 다시 시작 / 다시 실행할 수 없습니다. Docker는 시작시 각 컨테이너에 새 IP를 제공하며 이전에 사용 된 IP를 재사용하지 않는 것 같습니다. 따라서 api.myapp.com처음에는 172.0.0.2를 얻고 다음에는 172.0.0.4를 얻습니다. 그러나 Nginx이미 첫 번째 IP를 conf 파일이나 해당 /etc/hosts파일에 설정 했으므로 .NET의 새 IP를 확인할 수 없습니다 api.myapp.com. 이에 대한 해결책 은 내 제한된 이해 로 동일한 클러스터에 등록 된 모든 시스템에 대해 공유 된 것처럼 작동 CoreOS하는 etcd서비스 와 사용 가능성이 높습니다 . 이것은 제가 설정과 함께 놀게 될 다음 장난감입니다.ENVCoreOS

옵션 B : /etc/hosts파일 항목 사용

이 작업을 수행하는 더 빠르고 쉬운 방법 이어야 하지만 작동하지 못했습니다. 표면적으로는 /etc/hosts항목 의 값을 api.myapp.confapp.myapp.conf파일에 입력했지만이 방법을 사용할 수 없습니다.

업데이트 : 이 방법을 작동시키는 방법에 대한 지침
@Wes Tod의 답변 을 참조하십시오 .

내가 시도한 것은 다음과 같습니다 api.myapp.conf.

upstream api_upstream{
    server API:3000;
}

/etc/hosts파일에 다음과 같은 항목이 있다는 것을 고려할 때 : 172.0.0.2 API값을 끌어 올 것이라고 생각했지만 그렇지 않은 것 같습니다.

또한 Elastic Load Balancer모든 AZ에서 소싱 하는 데 몇 가지 보조 문제가 있었기 때문에이 경로를 시도 할 때 문제가되었을 수 있습니다. 대신 Linux에서 문자열 교체를 처리하는 방법을 배워야했기 때문에 재미있었습니다. 잠시 후에 시도해보고 어떻게 진행되는지 볼 것입니다.


답변

나는 모든 사람에게 코드 마술처럼 작동하는 인기있는 Jason Wilder 역방향 프록시를 사용해 보았지만 모든 사람 (예 : 나)에게 작동하지 않는다는 것을 알게되었습니다. 그리고 저는 NGINX를 처음 접했고 제가 사용하려는 기술을 이해하지 못했다는 점이 마음에 들지 않았습니다.

linking컨테이너에 대한 위의 논의 는 더 이상 사용되지 않는 기능이므로 이제 날짜가 지정 되었기 때문에 2 센트를 추가하고 싶었습니다 . 을 사용하여 수행하는 방법에 대한 설명이 있습니다 networks. 이 답변은 Docker Compose및 nginx 구성을 사용하여 정적으로 페이지가 지정된 웹 사이트에 대한 역방향 프록시로 nginx를 설정하는 전체 예제입니다 .

TL; DR;

서로 통신해야하는 서비스를 미리 정의 된 네트워크에 추가합니다. Docker 네트워크에 대한 단계별 토론을 위해 https://technologyconversations.com/2016/04/25/docker-networking-and-dns-the-good-the-bad-and-에서 몇 가지를 배웠습니다.
못난이/

네트워크 정의

우선, 모든 백엔드 서비스가 통신 할 수있는 네트워크가 필요합니다. 내가 전화 web했지만 원하는대로 할 수 있습니다.

docker network create web

앱 빌드

간단한 웹 사이트 앱을 만들 것입니다. 웹 사이트는 nginx 컨테이너에서 제공하는 간단한 index.html 페이지입니다. 컨텐츠는 폴더 아래의 호스트에 마운트 된 볼륨입니다.content

DockerFile :

FROM nginx
COPY default.conf /etc/nginx/conf.d/default.conf

default.conf

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /var/www/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

docker-compose.yml

version: "2"

networks:
  mynetwork:
    external:
      name: web

services:
  nginx:
    container_name: sample-site
    build: .
    expose:
      - "80"
    volumes:
      - "./content/:/var/www/html/"
    networks:
      default: {}
      mynetwork:
        aliases:
          - sample-site

여기서는 더 이상 포트 매핑이 필요하지 않습니다. 간단히 포트 80을 노출합니다. 이것은 포트 충돌을 피하는 데 편리합니다.

앱 실행

이 웹 사이트 시작

docker-compose up -d

컨테이너의 DNS 매핑과 관련된 몇 가지 재미있는 검사 :

docker exec -it sample-site bash
ping sample-site

이 핑은 컨테이너 내부에서 작동합니다.

프록시 구축

Nginx 역방향 프록시 :

Dockerfile

FROM nginx

RUN rm /etc/nginx/conf.d/*

사용자 정의 할 것이므로 모든 가상 호스트 구성을 재설정합니다.

docker-compose.yml

version: "2"

networks:
  mynetwork:
    external:
      name: web


services:
  nginx:
    container_name: nginx-proxy
    build: .
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./conf.d/:/etc/nginx/conf.d/:ro
      - ./sites/:/var/www/
    networks:
      default: {}
      mynetwork:
        aliases:
          - nginx-proxy

프록시 실행

우리의 신뢰를 사용하여 프록시를 시작하십시오.

docker-compose up -d

문제가 없다고 가정하면 이름을 사용하여 서로 통신 할 수있는 두 개의 컨테이너가 실행됩니다. 테스트 해 봅시다.

docker exec -it nginx-proxy bash
ping sample-site
ping nginx-proxy

가상 호스트 설정

마지막 세부 사항은 가상 호스팅 파일을 설정하여 프록시가 일치를 설정하려는 방식에 따라 트래픽을 전달할 수 있도록하는 것입니다.

가상 호스팅 구성을위한 sample-site.conf :

  server {
    listen 80;
    listen [::]:80;

    server_name my.domain.com;

    location / {
      proxy_pass http://sample-site;
    }

  }

프록시 설정 방법 에 따라 파일 conf.dvolumes선언을 통해 마운트 한 로컬 폴더 아래에이 파일을 저장해야 docker-compose합니다.

마지막으로, nginx에게 구성을 다시로드하도록 지시하십시오.

docker exec nginx-proxy service nginx reload

이러한 일련의 단계는 고통스러운 502 Bad Gateway 오류로 고생하고 처음으로 nginx를 배우는 동안 두통을 두드리는 시간의 정점입니다.

이 답변은 컨테이너가 서로 통신 할 수 없기 때문에 발생하는 502 Bad Gateway 오류를 종료하는 방법을 보여주기위한 것입니다.

이 답변이 누군가의 고통을 덜어주기를 바랍니다. 컨테이너가 서로 대화하도록하는 것은 내가 명백한 사용 사례 임에도 불구하고 어떤 이유에서인지 알아 내기가 정말 어려웠 기 때문입니다. 그러나 다시, 나는 바보입니다. 이 접근 방식을 개선 할 수있는 방법을 알려주십시오.


답변

docker links를 사용 하면 업스트림 컨테이너를 nginx 컨테이너에 연결할 수 있습니다. 추가 된 기능은 docker가 호스트 파일을 관리한다는 것입니다. 즉, 잠재적으로 임의의 ip가 아닌 이름을 사용하여 연결된 컨테이너를 참조 할 수 있습니다.


답변

AJB의 “옵션 B” 는 기본 Ubuntu 이미지를 사용하고 자체적으로 nginx를 설정하여 작동하도록 만들 수 있습니다. (Docker Hub의 Nginx 이미지를 사용할 때는 작동하지 않았습니다.)

내가 사용한 Docker 파일은 다음과 같습니다.

FROM ubuntu
RUN apt-get update && apt-get install -y nginx
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log
RUN rm -rf /etc/nginx/sites-enabled/default
EXPOSE 80 443
COPY conf/mysite.com /etc/nginx/sites-enabled/mysite.com
CMD ["nginx", "-g", "daemon off;"]

내 nginx 구성 (일명 : conf / mysite.com) :

server {
    listen 80 default;
    server_name mysite.com;

    location / {
        proxy_pass http://website;
    }
}

upstream website {
    server website:3000;
}

마지막으로 컨테이너를 시작하는 방법 :

$ docker run -dP --name website website
$ docker run -dP --name nginx --link website:website nginx

이것은 나를 시작하고 실행시켜 내 nginx가 포트 3000을 노출 한 두 번째 도커 컨테이너를 업스트림으로 가리 켰습니다.


답변

@gdbj의 답변은 훌륭한 설명이며 최신 답변입니다. 그러나 여기에 더 간단한 접근 방식이 있습니다.

따라서 80노출되는 다른 컨테이너로 수신 대기중인 nginx의 모든 트래픽을 리디렉션 하려면 8080최소 구성이 다음과 같을 수 있습니다.

nginx.conf :

server {
    listen 80;

    location / {
        proxy_pass http://client:8080; # this one here
        proxy_redirect off;
    }

}

docker-compose.yml

version: "2"
services:
  entrypoint:
    image: some-image-with-nginx
    ports:
      - "80:80"
    links:
      - client  # will use this one here

  client:
    image: some-image-with-api
    ports:
      - "8080:8080"

Docker 문서


답변

방금 Anand Mani Sankar 의 기사 에서 docker composer와 함께 nginx 업스트림 프록시를 사용하는 간단한 방법을 보여줍니다.

기본적으로 docker-compose 파일에서 인스턴스 링크 및 포트를 구성하고 그에 따라 nginx.conf에서 업스트림을 업데이트해야합니다.


답변