Как настроить Докер порт-маппинга использовать Nginx в качестве прокси-сервера верхнего уровня?


обновление II

сейчас 16 июля 2015 года, и все снова изменилось. Я обнаружил этот автоматический контейнер из Джейсон Уайлдер: https://github.com/jwilder/nginx-proxy и это решает эта проблема примерно до тех пор, как это займет docker run в контейнер. Теперь это решение, которое я использую для решения этой проблемы.

обновление

сейчас июль 2015 года, и все изменилось резко с уважением для сетевых контейнеров Docker. Теперь есть много разных предложения, которые решают эту проблему (различными способами).

вы должны использовать этот пост, чтобы получить общее представление о docker --link подход к открытию сервиса, который является примерно таким же основным, как и он, работает очень хорошо и на самом деле требует меньше фантазии, чем большинство других решений. Он ограничен тем, что довольно сложно объединять контейнеры в сеть на отдельных узлы в любом кластере, а контейнеры не могут быть перезапущены после подключения к сети, но предлагают быстрый и относительно простой способ подключения контейнеров к сети на том же узле. Это хороший способ получить представление о том, что программное обеспечение, которое вы, вероятно, будете использовать для решения этой проблемы, на самом деле делает под капотом.

кроме того, вы, вероятно, захотите также проверить зарождающийся Докер network, Hashicorp это consul, Weaveworks weave, Джефф Линдси progrium/consul & gliderlabs/registrator, и Google Kubernetes.

есть еще 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 77

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"

Docker docs

нашел статьи от Ананда Мани Санкара, который показывает простой способ использования прокси-сервера nginx upstream с Docker composer.

в основном необходимо настроить привязку экземпляра и порты в файле docker-compose и обновить вверх по течению в nginx.конф соответственно.