Ответ @T0xicCode правильный, но я подумал, что расскажу подробнее, поскольку на самом деле мне потребовалось около 20 часов, чтобы наконец реализовать рабочее решение.
Если вы хотите запустить Nginx в собственном контейнере и использовать его в качестве обратного прокси для балансировки нагрузки нескольких приложений на одном экземпляре сервера, вам необходимо выполнить следующие шаги:
Свяжите свои контейнеры
Когда вы используете docker runсвои контейнеры, обычно путем ввода сценария оболочки 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
Я усек многие фактические вары, но это ключевые значения, необходимые для прокси-трафика в ваши контейнеры.
Чтобы получить оболочку для выполнения вышеуказанных команд в работающем контейнере, используйте следующее:
sudo docker exec -i -t Nginx bash
Вы можете видеть, что теперь у вас есть как /etc/hostsзаписи файлов, так и envвары, содержащие локальный IP-адрес для любого из связанных контейнеров. Насколько я могу судить, это все, что происходит, когда вы запускаете контейнеры с объявленными параметрами ссылки. Но теперь вы можете использовать эту информацию для настройки nginxв своем Nginxконтейнере.
Настройка Nginx
Здесь все становится немного сложнее, и есть несколько вариантов. Вы можете настроить свои сайты так, чтобы они указывали на запись в созданном /etc/hostsфайле docker, или вы можете использовать ENVvars и запустить замену строки (я использовал sed) в вашем nginx.confи любых других файлах conf, которые могут быть в вашей /etc/nginx/sites-enabledпапке, чтобы вставить IP ценности.
ВАРИАНТ А. Настройка Nginx с использованием переменных ENV
Это вариант, который я выбрал, потому что я не мог заставить
/etc/hostsработать параметр файла. Вскоре я попробую вариант Б и дополню этот пост любыми выводами.
Ключевое различие между этой опцией и использованием /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 очень хорошо объясняет:
поиск и замена текста в файле с помощью команд
GOTCHA
В OSX sedпараметры обрабатываются по-другому, особенно -iфлаг. В Ubuntu -iфлаг будет обрабатывать замену «на месте»; он откроет файл, изменит текст, а затем «сохранит» тот же файл. В OSX для -iфлага требуется расширение файла, который должен иметь полученный файл. Если вы работаете с файлом без расширения, вы должны ввести '' в качестве значения -iфлага.
GOTCHA
Чтобы использовать переменные ENV в регулярном выражении, которое sedиспользуется для поиска строки, которую вы хотите заменить, вам необходимо заключить переменную в двойные кавычки. Таким образом, правильный, хотя и нечеткий синтаксис такой, как указано выше.
Итак, докер запустил наш контейнер и запустил Nginx-Startup.shскрипт для запуска, который использовался sedдля изменения значения APP_IPсоответствующей ENVпеременной, которую мы указали в sedкоманде. Теперь у нас есть файлы conf в нашем /etc/nginx/sites-enabledкаталоге, которые имеют IP-адреса из ENVпеременных, которые докер установил при запуске контейнера. В вашем api.myapp.confфайле вы увидите, что upstreamблок изменился на этот:
upstream api_upstream{
server 172.0.0.2:3000;
}
Видимый вами IP-адрес может быть другим, но я заметил, что это обычно 172.0.0.x.
Теперь у вас должна быть правильная маршрутизация.
GOTCHA
Вы не можете перезапустить / повторно запустить какие-либо контейнеры после запуска первого экземпляра. Docker предоставляет каждому контейнеру новый IP-адрес при запуске и, похоже, не использует повторно тот, который использовался ранее. Таким api.myapp.comобразом, в первый раз будет получено 172.0.0.2, а в следующий раз - 172.0.0.4. Но Nginxон уже установил первый IP-адрес в своих файлах conf или в своем /etc/hostsфайле, поэтому он не сможет определить новый IP-адрес для api.myapp.com. Решение этой проблемы, скорее всего, будет использовать CoreOSи его etcdсервис, который, в моем ограниченном понимании, действует как общий ENVдля всех машин, зарегистрированных в одном CoreOSкластере. Это следующая игрушка, с которой я собираюсь поиграться.
ВАРИАНТ Б: Использование /etc/hostsфайловых записей
Это должен быть более быстрый и простой способ сделать это, но я не мог заставить его работать. Якобы вы просто ввести значение /etc/hostsвступления в ваших api.myapp.confи app.myapp.confфайлов, но я не мог получить этот метод работы.
ОБНОВЛЕНИЕ:
см. Ответ @Wes Tod, чтобы узнать, как заставить этот метод работать.
Вот попытка, которую я предпринял api.myapp.conf:
upstream api_upstream{
server API:3000;
}
Учитывая, что в моем /etc/hostsфайле есть такая запись : 172.0.0.2 APIя подумал, что она просто получит значение, но, похоже, это не так.
У меня также была пара дополнительных проблем с моими Elastic Load Balancerисточниками из всех АЗ, так что это могло быть проблемой, когда я пробовал этот маршрут. Вместо этого мне пришлось научиться обрабатывать замену строк в Linux, так что это было весело. Я попробую через некоторое время и посмотрю, как это пойдет.