Nginx를 업스트림 프록시로 사용하도록 Docker 포트 매핑을 구성하는 방법은 무엇입니까?
업데이트 II
지금은 2015 년 7 월 16 일이고 상황이 다시 바뀌 었습니다. 나는에서이 자동적 인 컨테이너 발견 한 제이슨 와일더을 :
https://github.com/jwilder/nginx-proxy
그것은 약으로 오래가 걸립니다이 문제를 해결docker run
컨테이너. 이것이 제가이 문제를 해결하기 위해 사용하고있는 해결책입니다.
최신 정보
지금은 2015 년 7 월이며 네트워킹 Docker 컨테이너와 관련하여 상황이 크게 변경되었습니다. 이제이 문제를 다양한 방식으로 해결하는 다양한 솔루션이 있습니다.
이 게시물을 사용
docker --link
하여 서비스 검색 에 대한 접근 방식에 대한 기본적인 이해를 얻어야합니다. 서비스 검색 방법은 기본적이며 매우 잘 작동하며 실제로 대부분의 다른 솔루션보다 멋진 춤이 덜 필요합니다. 특정 클러스터의 개별 호스트에 컨테이너를 네트워크로 연결하는 것이 매우 어렵고 네트워크가 연결되면 컨테이너를 다시 시작할 수 없다는 점에서 제한적이지만 동일한 호스트에서 컨테이너를 네트워크에 빠르고 비교적 쉽게 연결할 수있는 방법을 제공합니다. 이 문제를 해결하는 데 사용할 소프트웨어가 실제로 내부에서 수행하는 작업에 대한 아이디어를 얻는 좋은 방법입니다.또한 Docker의 초기
network
, Hashicorpconsul
, Weaveworksweave
, Jeff Lindsay 'sprogrium/consul
&gliderlabs/registrator
, Google을 확인하고 싶을 것입니다Kubernetes
.이 또한의 CoreOS의 활용 제품
etcd
,fleet
및flannel
.정말 파티를하고 싶다면 클러스터를 가동하여
Mesosphere
, 또는Deis
, 또는 을 실행할 수 있습니다Flynn
.네트워킹이 처음이라면 (나와 같은) 돋보기를 꺼내서 Wi-Hi-Fi에서 "Paint The Sky With Stars — The Best of Enya" 를 팝업 하고 맥주를 크래킹해야합니다. 당신이하려는 것이 무엇인지 정확히 이해하기 전에. 힌트 : 당신은을 구현하기 위해 노력하고
Service Discovery Layer
당신에Cluster Control Plane
. 토요일 밤을 보내는 아주 좋은 방법입니다.그것은 많은 재미 있어요,하지만 난 다이빙 직전에 일반적으로 네트워킹에 대한 더 나은 자신을 교육하는 시간을 가지고 좋겠 나는 결국 호의적 인 디지털 오션 튜토리얼 신에서 몇 게시물을 발견.
Introduction to Networking Terminology
및Understanding ... 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
용기에 연결되어 API
와 Nginx
모두 연결되어 API
및 App
.
그 결과 및 컨테이너 내에있는 env
vars 및 /etc/hosts
파일 이 변경됩니다 . 결과는 다음과 같습니다.API
App
/ 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
vars를 활용 하고 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_IP
upstream
api.myapp.conf
app.myapp.conf
이 ask.ubuntu.com 질문은 매우 잘 설명합니다. 명령을 사용하여 파일 내에서 텍스트 찾기 및 바꾸기
GOTCHA OSX에서
sed
옵션, 특히-i
플래그를 다르게 처리합니다 . 우분투에서는-i
플래그가 'in place'교체를 처리합니다. 파일을 열고 텍스트를 변경 한 다음 동일한 파일을 '저장'합니다. OSX에서-i
플래그 에는 결과 파일에 적용 할 파일 확장자 가 필요 합니다. 확장자가없는 파일로 작업하는 경우-i
플래그 값으로 ''를 입력해야합니다 .GOTCHA
sed
교체하려는 문자열을 찾는 데 사용 하는 정규식 내에서 ENV vars를 사용하려면 var를 큰 따옴표로 묶어야합니다. 따라서 엉뚱 해 보이지만 올바른 구문은 위와 같습니다.
따라서 docker는 컨테이너를 시작하고 Nginx-Startup.sh
스크립트를 실행 하여 명령 에서 제공 한 해당 변수로 sed
값 APP_IP
을 변경하는 데 사용 되었습니다 . 이제 컨테이너를 시작할 때 docker가 설정 한 변수 의 IP 주소가 있는 conf 파일이 디렉터리 내에 있습니다. 파일 내 에서 블록이 다음과 같이 변경된 것을 볼 수 있습니다 .ENV
sed
/etc/nginx/sites-enabled
ENV
api.myapp.conf
upstream
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
서비스 와 사용 가능성이 있습니다 . 이것이 제가 설정과 함께 놀게 될 다음 장난감입니다.ENV
CoreOS
옵션 B : /etc/hosts
파일 항목 사용
이 작업을 수행하는 더 빠르고 쉬운 방법 이어야 하지만 작동하지 못했습니다. 표면적으로는 /etc/hosts
항목 의 값을 api.myapp.conf
및 app.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"
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.
'Programing' 카테고리의 다른 글
Twitter Bootstrap 탭이 작동하지 않음 : 클릭해도 아무 일도 일어나지 않습니다. (0) | 2020.10.07 |
---|---|
일관성없는 접근성 : 속성 유형에 대한 접근성이 떨어짐 (0) | 2020.10.07 |
내 수업에 스왑 기능을 제공하는 방법은 무엇입니까? (0) | 2020.10.06 |
Numpy : newaxis 또는 None을 사용해야합니까? (0) | 2020.10.06 |
git 저장소를 다른 디렉토리로 이동하고 해당 디렉토리를 git 저장소로 만드는 방법은 무엇입니까? (0) | 2020.10.06 |