Как настроить сопоставление портов Docker для использования Nginx в качестве восходящего прокси-сервера?
обновление II
сейчас 16 июля 2015 года, и все снова изменилось. Я обнаружил этот автоматический контейнер из Джейсон Уайлдер:
https://github.com/jwilder/nginx-proxy
и это решает эта проблема примерно до тех пор, пока она занимаетdocker run
в контейнер. Теперь это решение, которое я использую для решения этой проблемы.
обновление
сейчас июль 2015 года, и все изменилось резко касаемо для сетевых контейнеров Docker. Теперь есть много разных предложения, которые решают эту проблему (различными способами).
вы должны использовать этот пост, чтобы получить основное понимание
docker --link
подход к открытию сервиса, который примерно так же прост, как и он, работает очень хорошо и на самом деле требует меньше фантазии, чем большинство других решений. Он ограничен в том, что довольно сложно объединить контейнеры в сеть на отдельных узлы в любом кластере, и контейнеры не могут быть перезапущены после подключения к сети, но предлагают быстрый и относительно простой способ для сетевых контейнеров на том же узле. Это хороший способ получить представление о том, что программное обеспечение, которое вы, вероятно, будете использовать для решения этой проблемы, на самом деле делает под капотом.кроме того, вы, вероятно, захотите также проверить docker's nascent
network
, Hashicorp этоconsul
, Weaveworksweave
, Джефф Линдсейprogrium/consul
&gliderlabs/registrator
, и GoogleKubernetes
.есть еще по CoreOS предложения, использовать
etcd
,fleet
иflannel
.и если вы действительно хотите устроить вечеринку, вы можете создать кластер для запуска
Mesosphere
илиDeis
илиFlynn
.если вы новое в сети (как я), то вы должны получить свои очки для чтения, поп "Раскрась небо звездами-лучшее из Эньи" на Wi-Hi-Fi и взломать пиво - это будет некоторое время, прежде чем вы действительно поймете, что именно вы пытаетесь сделать. Подсказка: вы пытаетесь реализовать
Service Discovery Layer
в своемCluster Control Plane
. Это очень хороший способ провести субботний вечер.это очень весело, но я хотел бы, чтобы я взял время, чтобы лучше обучить себя о сети в общем, перед погружением. В конце концов я нашел пару сообщений от благожелательных богов цифрового океана:
Introduction to Networking Terminology
иUnderstanding ... Networking
. Я предлагаю прочитать несколько раз, прежде чем нырять.удачи!
Оригинальное Сообщение
я не могу понять отображение портов для Docker
контейнеров. В частности, как передать запросы от Nginx другому контейнер, прослушивающий другой порт, на том же сервере.
у меня есть Dockerfile для контейнера Nginx, например:
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"]
А потом ... --23--> файл config выглядит так:
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
И все это стоит просто отлично, но запросы не проходят через другие контейнеры/порты. И когда я ssh в контейнер Nginx и проверьте журналы, я не вижу ошибок.
помочь?
6 ответов
@T0xicCode это правильно, но я думал, что расширю детали, так как на самом деле мне потребовалось около 20 часов, чтобы, наконец, реализовать рабочее решение.
если вы хотите запустить Nginx в собственном контейнере и использовать его в качестве обратного прокси для балансировки нагрузки нескольких приложений на одном экземпляре сервера, то шаги, которые вам нужно выполнить, таковы:
Ваша Ссылка Контейнеры
когда вы docker run
ваши контейнеры, как правило, просто shell-скрипт в 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
Варс и /etc/hosts
файлы, которые находятся внутри API
и App
контейнеров. Результаты выглядят так:
/и т. д./хосты
под управлением 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 Vars
под управлением 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
я усек многие из фактических vars, но выше приведены ключевые значения, необходимые для прокси-трафика к контейнерам.
чтобы получить оболочку для выполнения вышеуказанных команд в работающем контейнере, используйте следующее:
sudo docker exec -i -t Nginx bash
вы можете видеть, что теперь у вас есть оба /etc/hosts
записи файла и env
vars, которые содержат локальный IP-адрес для любого из контейнеры, которые были связаны. Насколько я могу судить, это все, что происходит при запуске контейнеров с объявленными параметрами ссылок. Но теперь вы можете использовать эту информацию для настройки nginx
в своем Nginx
контейнер.
Настройка Nginx
здесь становится немного сложнее, и есть несколько вариантов. Вы можете настроить свои сайты так, чтобы они указывали на запись в это docker
создали, или вы может использовать ENV
vars и запустить замену строки (я использовал sed
) на nginx.conf
и любые другие файлы conf, которые могут быть в вашем /etc/nginx/sites-enabled
папка для вставки значений IP.
опция A: настройка Nginx с помощью ENV Vars
это вариант, с которым я пошел, потому что я не мог получить
/etc/hosts
опция file для работы. Я скоро попробую вариант B и обновите этот пост с любым полученные данные.
ключевое различие между этой опцией и использованием /etc/hosts
опция file-это то, как вы пишете свой Dockerfile
использовать скрипт как CMD
аргумент, который в свою очередь обрабатывает замену строки для копирования значений IP из ENV
в файл(ы) conf.
вот набор конфигурационных файлов, которые я закончил с:
файла Docker
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 вопрос объясняет это очень красиво: поиск и замена текста в файле с помощью команд
понял На OSX,
sed
ручки варианты по-другому,-i
флаг в частности. В Ubuntu-i
флаг будет обрабатывать замену "на месте"; это откроет файл, изменит текст, а затем "сохранит" то же самое файл. На OSX,-i
флаг требует расширение файла, которое вы хотите, чтобы полученный файл имел. Если вы работаете с файлом, который не имеет расширения, вы должны ввести " в качестве значения для-i
флаг.понял Использовать ENV vars внутри тестирую, что
sed
использует, чтобы найти строку, которую вы хотите заменить, вам нужно обернуть var в двойные кавычки. Таким образом, правильный, хотя и шаткий синтаксис, как указано выше.
Итак, докер запустил наш контейнер и запустил Nginx-Startup.sh
скрипт для запуска, который использовал sed
изменить значение APP_IP
соответствующей ENV
переменная, которую мы предоставили в . Теперь у нас есть файлы conf в нашем /etc/nginx/sites-enabled
каталог, в котором есть IP-адреса из the ENV
vars, которые docker установил при запуске контейнера. Внутри вашего будет уже установлен первый IP в его conf-файлы, или в его вот так: 172.0.0.2 API
я думал, что это просто вытянет значение, но, похоже, это не так.
у меня также было несколько дополнительных проблем с моим Elastic Load Balancer
sourcing от всех AZ так, что может быть проблема, когда я пробовал этот маршрут. Вместо этого мне пришлось научиться обрабатывать замену строк в Linux, так что это было весело. Я попробую через некоторое время и посмотрю, как пойдет.
используя docker links, вы можете связать восходящий контейнер с контейнером nginx. Добавленная функция заключается в том, что docker управляет файлом хоста, что означает, что вы сможете ссылаться на связанный контейнер, используя имя, а не потенциально случайный ip.
я попытался использовать популярный обратный прокси-сервер Джейсона Уайлдера, который волшебным образом работает для всех, и узнал, что он не работает для всех (т. е. для меня). И я новичок в NGINX, и мне не понравилось, что я не понял технологии, которые я пытался использовать.
хотел бы добавить мои 2 цента, потому что обсуждение выше linking
контейнеры вместе теперь датируются, так как это устаревшая функция. Итак, вот объяснение того, как это сделать с помощью networks
. Этот ответ полный пример настройки nginx в качестве обратного прокси-сервера для статически страничный сайт с помощью Docker Compose
и настройка nginx.
TL; DR;
добавьте службы, которые должны общаться друг с другом в предопределенной сети. Для пошагового обсуждения в Docker networks я узнал некоторые вещи здесь: https://technologyconversations.com/2016/04/25/docker-networking-and-dns-the-good-the-bad-and-the-ugly/
определить Сеть
прежде всего, нам нужна сеть, по которой все ваши бэкэнд-сервисы могут разговаривать. Я назвал свое web
но это может быть что угодно.
docker network create web
создать приложение
мы просто сделаем простое приложение для веб-сайта. Сайт представляет собой простой показатель.html-страница обслуживается контейнером nginx. Содержимое смонтированного на хост в папке content
DockerFile:
FROM nginx
COPY default.conf /etc/nginx/conf.d/default.conf
по умолчанию.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;
}
}
докер-сочинять.в формате 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/*
мы сбрасываем всю конфигурацию виртуального хоста, так как мы собираемся настроить его.
докер-сочинять.в формате 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
настройка виртуального хоста
последняя деталь-настроить файл виртуального хостинга, чтобы прокси-сервер мог направлять трафик на основе того, как вы хотите настроить соответствие:
пример-сайте.conf для нашего виртуального хостинга config:
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, так как большая часть моего опыта была с Apache.
этот ответ должен продемонстрировать, как убить ошибку 502 Bad Gateway, которая возникает из-за того, что контейнеры не могут разговаривать с одним другой.
я надеюсь, что этот ответ спасет кого-то от часов боли, так как получить контейнеры, чтобы поговорить друг с другом, было очень трудно понять по какой-то причине, несмотря на то, что я ожидал, что это будет очевидный случай использования. Но опять же, я тупой. И, пожалуйста, дайте мне знать, как я могу улучшить этот подход.
"вариант B" AJB можно заставить работать, используя базовый образ Ubuntu и настраивая nginx самостоятельно. (Это не сработало, когда я использовал изображение Nginx из Docker Hub.)
вот файл 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 (aka: 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-отличное объяснение и самый актуальный ответ. Вот, однако, более простой подход.
поэтому, если вы хотите перенаправить весь трафик с nginx на80
к другому контейнеру подвергая 8080
, минимальная конфигурация может быть всего лишь:
nginx.conf:
server {
listen 80;
location / {
proxy_pass http://client:8080; # this one here
proxy_redirect off;
}
}
докер-сочинять.в формате 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"
нашел статьи от Ананда Мани Санкара, который показывает простой способ использования nginx upstream proxy с Docker composer.
в основном необходимо настроить привязку экземпляра и порты в файле docker-compose и обновить вверх по течению в nginx.конф соответственно.