Как настроить сопоставление портов Docker для использования Nginx в качестве восходящего прокси-сервера?

обновление II

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

обновление

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

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

кроме того, вы, вероятно, захотите также проверить docker's nascent 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"]



А потом ... --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"

Docker docs


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

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