Как настроить Докер порт-маппинга использовать Nginx в качестве прокси-сервера верхнего уровня?
обновление II
сейчас 16 июля 2015 года, и все снова изменилось. Я обнаружил этот автоматический контейнер из Джейсон Уайлдер:
https://github.com/jwilder/nginx-proxy
и это решает эта проблема примерно до тех пор, как это займетdocker run
в контейнер. Теперь это решение, которое я использую для решения этой проблемы.
обновление
сейчас июль 2015 года, и все изменилось резко с уважением для сетевых контейнеров Docker. Теперь есть много разных предложения, которые решают эту проблему (различными способами).
вы должны использовать этот пост, чтобы получить общее представление о
docker --link
подход к открытию сервиса, который является примерно таким же основным, как и он, работает очень хорошо и на самом деле требует меньше фантазии, чем большинство других решений. Он ограничен тем, что довольно сложно объединять контейнеры в сеть на отдельных узлы в любом кластере, а контейнеры не могут быть перезапущены после подключения к сети, но предлагают быстрый и относительно простой способ подключения контейнеров к сети на том же узле. Это хороший способ получить представление о том, что программное обеспечение, которое вы, вероятно, будете использовать для решения этой проблемы, на самом деле делает под капотом.кроме того, вы, вероятно, захотите также проверить зарождающийся Докер
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"]
А потом api.myapp.com
файл 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
контейнеров. Результаты выглядят так:/ 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 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.
в: настроить nginx, используя переменные окруженияэто вариант, с которым я пошел, потому что я не мог получить
/etc/hosts
опции файл для работы. Я буду пробовать вариант B достаточно скоро и обновите этот пост с любым полученные данные.ключевое различие между этой опцией и использованием
/etc/hosts
опция файла-это то, как вы пишете свойDockerfile
чтобы использовать сценарий оболочки в качествеCMD
аргумент, который в свою очередь обрабатывает замену строки для копирования значений IP изENV
в ваш файл (ы) conf.вот набор конфигурационных файлов, которые я закончил с:
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 вопрос объясняет это очень красиво: найти и заменить текст в файле с помощью команды
понял На OSX,
sed
ручки варианты иначе, чем-i
флаг в частности. На Ubuntu, the-i
флаг будет обрабатывать замену "на месте"; это откроет файл, изменит текст, а затем "сохранит" то же самое файл. На OSX, the-i
флаг требует расширение файла, которое вы хотите, чтобы полученный файл имел. Если вы работаете с файлом, который не имеет расширения, вы должны ввести " как значение для-i
флаг.понял Чтобы использовать переменные окружения в регулярное выражение, что
sed
используется для поиска строки, которую вы хотите заменить вам нужно обернуть var в двойные кавычки. Таким образом, правильный, хотя и шаткий, синтаксис, как указано выше.так докер запустил наш контейнер и запустил
Nginx-Startup.sh
скрипт для запуска, который использовалsed
изменить значениеAPP_IP
соответствующейENV
переменная, которую мы предоставили в . Теперь у нас есть файлы conf в нашем/etc/nginx/sites-enabled
каталог с IP адресами из элементENV
vars, что докер установлен при запуске контейнера. Внутри вашего вот так:172.0.0.2 API
я подумал, что это просто потянет значение, но это, похоже, не так.у меня также было несколько вспомогательных проблем с моим
Elastic Load Balancer
поиск от всех АЗ, так что, возможно, были проблема, когда я попробовал этот маршрут. Вместо этого мне пришлось научиться обрабатывать замену строк в 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/
определить Сеть
прежде всего, нам нужна сеть, на которой все ваши услуги backend можно говорить. Я назвал свой
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; } }
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
настройка виртуального хоста
последняя деталь-настроить файл виртуального хостинга, чтобы прокси-сервер мог направлять трафик на основе того, как вы хотите настроить свое соответствие:
пример-сайте.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, которая возникает из-за того, что контейнеры не могут разговаривать с одним другой.
я надеюсь, что этот ответ спасает кого-то там от часов боли, так как получение контейнеров для разговора друг с другом было действительно трудно понять по какой-то причине, несмотря на то, что я ожидал, что это будет очевидный случай использования. Но опять же, я тупой. И, пожалуйста, дайте мне знать, как я могу улучшить этот подход.
AJB "вариант B" можно заставить работать с помощью базового образа 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 config (он же: 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 указал вверх по течению на второй контейнер docker, который открытый порт 3000.
ответ @ gdbj-отличное объяснение и самый актуальный ответ. Вот, однако, более простой подход.
так что если вы хотите, чтобы перенаправить весь трафик с nginx слушает
80
к другому контейнеру подвергая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"
нашел статьи от Ананда Мани Санкара, который показывает простой способ использования прокси-сервера nginx upstream с Docker composer.
в основном необходимо настроить привязку экземпляра и порты в файле docker-compose и обновить вверх по течению в nginx.конф соответственно.