Programing

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

lottogame 2020. 10. 6. 07:45
반응형

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하거나 ENVvars를 활용 하고 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 vars를 사용하려면 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

가상 호스트 설정

Last detail is to set up the virtual hosting file so the proxy can direct traffic based on however you want to set up your matching:

sample-site.conf for our virtual hosting config:

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

    server_name my.domain.com;

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

  }

Based on how the proxy was set up, you'll need this file stored under your local conf.d folder which we mounted via the volumes declaration in the docker-compose file.

Last but not least, tell nginx to reload it's config.

docker exec nginx-proxy service nginx reload

These sequence of steps is the culmination of hours of pounding head-aches as I struggled with the ever painful 502 Bad Gateway error, and learning nginx for the first time, since most of my experience was with Apache.

This answer is to demonstrate how to kill the 502 Bad Gateway error that results from containers not being able to talk to one another.

I hope this answer saves someone out there hours of pain, since getting containers to talk to each other was really hard to figure out for some reason, despite it being what I expected to be an obvious use-case. But then again, me dumb. And please let me know how I can improve this approach.


Using docker links, you can link the upstream container to the nginx container. An added feature is that docker manages the host file, which means you'll be able to refer to the linked container using a name rather than the potentially random ip.


AJB's "Option B" can be made to work by using the base Ubuntu image and setting up nginx on your own. (It didn't work when I used the Nginx image from Docker Hub.)

Here is the Docker file I used:

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;"]

My nginx config (aka: conf/mysite.com):

server {
    listen 80 default;
    server_name mysite.com;

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

upstream website {
    server website:3000;
}

And finally, how I start my containers:

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

This got me up and running so my nginx pointed the upstream to the second docker container which exposed port 3000.


@gdbj's answer is a great explanation and the most up to date answer. Here's however a simpler approach.

So if you want to redirect all traffic from nginx listening to 80 to another container exposing 8080, minimum configuration can be as little as:

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 docs


Just found an article from Anand Mani Sankar wich shows a simple way of using nginx upstream proxy with docker composer.

Basically one must configure the instance linking and ports at the docker-compose file and update upstream at nginx.conf accordingly.

참고URL : https://stackoverflow.com/questions/27912917/how-to-configure-docker-port-mapping-to-use-nginx-as-an-upstream-proxy

반응형