Как настроить Докер порт-маппинга использовать 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записи файла иenvvars, которые содержат локальный IP-адрес для любого из контейнеры, которые были связаны. Насколько я могу судить, это все, что происходит при запуске контейнеров с объявленными параметрами ссылок. Но теперь вы можете использовать эту информацию для настройкиnginxв своемNginxконтейнер.
Настройка Nginxэто где это становится немного сложнее, и есть несколько вариантов. Вы можете настроить свои сайты так, чтобы они указывали на запись в это
dockerсоздали, или вы можно использоватьENVvars и запустить замену строки (я использовал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 адресами из элементENVvars, что докер установлен при запуске контейнера. Внутри вашего вот так: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. Содержимое смонтированного на хост в папке
contentDockerFile:
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.конф соответственно.