업데이트 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.
그 결과 및 컨테이너 내에있는 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플래그 값으로 ”를 입력해야합니다 .GOTCHA
sed교체하려는 문자열을 찾는 데 사용
하는 정규식 내에서 ENV 변수를 사용하려면 var를 큰 따옴표로 묶어야합니다. 따라서 엉뚱 해 보이지만 올바른 구문은 위와 같습니다.
따라서 docker는 컨테이너를 시작하고 Nginx-Startup.sh스크립트를 실행 하여 명령 에서 제공 한 해당 변수로 sed값 APP_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.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에서 업스트림을 업데이트해야합니다.
답변
