[nginx] 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
변수를 활용 하고 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 변수를 사용하려면 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
가상 호스트 설정
마지막 세부 사항은 가상 호스팅 파일을 설정하여 프록시가 일치를 설정하려는 방식에 따라 트래픽을 전달할 수 있도록하는 것입니다.
가상 호스팅 구성을위한 sample-site.conf :
server {
listen 80;
listen [::]:80;
server_name my.domain.com;
location / {
proxy_pass http://sample-site;
}
}
프록시 설정 방법 에 따라 파일 conf.d
의 volumes
선언을 통해 마운트 한 로컬 폴더 아래에이 파일을 저장해야 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"
답변
방금 Anand Mani Sankar 의 기사 에서 docker composer와 함께 nginx 업스트림 프록시를 사용하는 간단한 방법을 보여줍니다.
기본적으로 docker-compose 파일에서 인스턴스 링크 및 포트를 구성하고 그에 따라 nginx.conf에서 업스트림을 업데이트해야합니다.