За последний год в Docker Hub стало доступно уже более 100 000 образов, а загружались образы с Docker Hub уже более 300 миллионов раз. Из них более 20 миллионов загрузок пришлись на 70 официальных образов разработчиков Docker, таких как Oracle, CentOS и NGINX.

NGINX используется на более 40% самых больших сайтов в мире, не только как веб-сервер, но и как реверс-прокси сервер, балансировщик нагрузки и HTTP кэш. Официальный образ NGINX был загружен 3.4 миллиона раз.



В этой статье вы узнаете:
  • как развернуть и использовать Docker-образ с NGINX.
  • как быстро развернуть реверс-прокси на NGINX и несколько сайтов в Docker
  • как развернуть геораспределенную инсталляцию, состоящую из нескольких сайтов и реверс-прокси в каждом из 3х регионов InfoboxCloud.

Если раньше вы не использовали Docker, рекомендуется к прочтению:
Используем Docker и не волнуемся о vendor-lock
Погружаемся в Docker: Dockerfile и коммуникация между контейнерами
Обзор новшеств Docker Engine с 1.0 до 1.8. Введение в Docker Compose

В конце статьи мы раздаем пробные версии InfoboxCloud бесплатно.

Подготовка окружения


1. Создайте сервер с CentOS 7 для установки Docker в InfoboxCloud. Для работы Docker сейчас необходима именно виртуальная машина, поэтому при создании сервера обязательно установите галочку «Разрешить управление ядром ОС».

Как правильно создать сервер в InfoboxCloud для Docker
Если у вас еще нет доступа в InfoboxCloud – закажите его.

После регистрации вы получите данные для доступа к панели управления на email. Войдите в панель управления по адресу: https://panel.infobox.ru

В разделе «Облачная инфраструктура» вашей подписки нажмите «Новый сервер» (при необходимости подписка меняется в правом верхнем углу в выпадающем меню).



Задайте необходимые параметры сервера. Обязательно выделите серверу 1 публичный IP–адрес и установите галочку «Разрешить управление ядром ОС», как показано на скриншоте ниже.



В списке доступных операционных систем выберите CentOS 7 и завершите создание сервера.



После этого данные для доступа к серверу придут к вам на электронную почту.

После создания сервера с CentOS 7 подключитесь к нему по SSH.

Мы подготовили скрипт, который позволит вам установить Docker и полезные утилиты для работы с Docker на такой сервер. Необходимые настройки будут выполнены автоматически.

Выполните команду для установки Docker и Compose:
bash <(curl -s http://repository.sandbox.infoboxcloud.ru/scripts/docker/centos7/install.sh)

После этого docker и compose будут установлены. Можно создать образ с установленным docker в панели управления, нажав на сервер и далее «Создать образ».

После этого из образа с Docker можно будет создавать новые сервера и не выполнять этот шаг повторно.

Создание переносимого окружения


Наше переносимое окружение состоит из:
  • Dockerfile – файла, описывающего процесс построения контейнера
  • docker-compose.yml — файла, описывающего процесс запуска контейнера или набора контейнеров
  • файлов сайта в директории html
  • файлов конфигурации nginx в директории conf

Лучше держать переносимое окружение в репозитории например на github, при обновлении файлов сайта или конфигурации перестраивать контейнер. Это позволит быть уверенными, что при необходимости вы сможете переразвернуть настроенный сайт за считанные минуты. Также вы можете быстро поднимать сайт в отдельном контейнере для разработки.

Для работы с git установите его на сервере.
yum install -y git

Скопируйте наше простое переносимое окружение из github командой:
git clone https://github.com/InfoboxHosting/DockerNginxSimpleStaticSite.git

Перейдите в директорию окружения командой:
cd DockerNginxSimpleStaticSite/

Постройте образ Docker с помощью команды
docker-compose build

Разверните образ в контейнер командой
docker-compose up -d

Попробуйте зайти на сервер по IP. Преднастроенный статический сайт был успешно развернут.



Если выполнить
docker ps
можно увидеть сайт в списке контейнеров.



Давайте разберемся, из чего состоит переносимое окружение.



В файле conf/nginx.conf находится конфигурация nginx:
nginx.conf
user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
    worker_connections 4086;
    use epoll;
    multi_accept on;
}

http {

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    server {
        listen 80;
        server_name  domain.tld  www.domain.tld;

        location / {
            root /usr/share/nginx/html;
        }
    }
}


, где domain.tld нужно заменить на домен вашего сайта.

Конфигурация веб-сервера для сайта хранится в переносимом окружении, благодаря чему при развертывании не нужно заново настраивать веб-сервер каждый раз.

В корне переносимого окружения находится Dockerfile, который использует официальный образ NGINX и добавляет в него ваш сайт из папки html и конфигурацию NGINX из папки conf.

FROM nginx

MAINTAINER Yuri Trukhin "trukhinyuri@infoboxcloud.com"

COPY conf/nginx.conf /etc/nginx/nginx.conf
COPY html/ /usr/share/nginx/html


Подробнее о Dockerfile было рассказано в этой статье.

Также в корне папки переносимого окружения создайте файл docker-compose.yml со следующим содержимым:
sitename:
  build: .
  ports:
  - 80:80
  restart: always

В нем сказано, что нужно разворачивать окружение sitename, сперва построив его из Dockerfile в той же директории. Порт 80 контейнера необходимо пробросить на порт 80 хоста. В случае падения NGINX рестартовать его.

Подробнее о Compose было рассказано в этой статье.
Если вы измените сайт или файл конфигурации nginx – просто перестройте образ командой
docker-compose build

И затем разверните образ в контейнер:
docker-compose up -d


Нам не нужно каждый раз волноваться о настройке сервера. Однажды разработанное переносимое окружение с Docker позволит быстро делать развертывание.

Для выполнения рекомендаций из следующего раздела остановите и удалите развернутый контейнер, т.к. он занимает порт 80 на хосте, который нам потребуется.

Для этого выполните:
docker ps

Скопируйте в буфер обмена container_id.
Остановите контейнер командой:
docker stop bc88ee61a933

, где вместо bc88ee61a933 вставьте ваш container_id.
Удалите контейнер:
docker rm bc88ee61a933

, где вместо bc88ee61a933 вставьте ваш container_id.

Разворачиваем несколько сайтов с реверс-прокси


В данном разделе мы развернем несколько статических сайтов с разными доменами и реверс-прокси. Для выполнения этой части статьи вам понадобится направить на ip–адрес сервера ваши домены в DNS:
  • А-запись domain1.tld нужно направить на выделенный публичный IP–адрес вашего сервера. domain1.tld – домен первого сайта.
  • А-запись domain2.tld нужно направить на выделенный публичный IP–адрес вашего сервера. domain2.tld – домен второго сайта.

Необходимые ip–адреса можно найти в панели управления InfoboxCloud.



Что делать, если у вас нет доменов
Вариант 1. Настройте hosts

Этот вариант отлично подходит для тестирования, но будет работать только с вашего компьютера.

Добавьте записи о доменах в файл hosts вашего компьютера.
В OS X и Linux добавить записи можно в файл /etc/hosts.



В Windows нужно запустить блокнот от имени администратора. Для этого в поле поиска введите Notepad или «Блокнот» (в русской версии Windows) и выберите пункт запуска от имени администратора.



Откройте файл C:\Windows\System32\drivers\etc\hosts. Если в блокноте он будет не виден — выберите рядом с кнопкой «Открыть» тип файлов «Все файлы».



Добавьте необходимые записи и сохраните изменения. Не забудьте в качестве ip–адресов использовать адреса именно вашего сервера из панели управления.



После тестов не забудьте удалить эти записи из файла hosts.

Вариант 2. Приобретите необходимые домены

Например это можно сделать тут.


Теперь подключитесь к серверу с Docker в InfoboxCloud по SSH.
Клонируйте подготовленный репозиторий для 2х сайтов с балансировщиком нагрузки.
cd ~

git clone https://github.com/InfoboxHosting/DockerNginxSimpleBalancer.git




Перейдите в директорию переносимого окружения балансировщика:
cd ~/DockerNginxSimpleBalancer/balancer

Запустите построение балансировщика и зависимых образов одной командой:
docker-compose build

Разверните балансировщик и зависимые образы:
docker-compose up -d

Примечание: файлы docker-compose.yml в папках каждого из фронтендов в данном примере не используются.

Откройте в браузере домен первого сайта:



Теперь проверьте, что корректно открывается и второй сайт:



Чтобы сайты открывались не с прописанным domain1.com и domain2.com в ваших /etc/hosts, нужно поправить файл ~/DockerNginxSimpleBalancer/balancer/conf/nginx.conf:

nginx.conf
user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
    worker_connections 4086;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    server {
        listen 80;
        server_name domain1.com  www.domain1.com;

        location / {
            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_pass http://frontend1:80;
        }
    }
    server {
        listen 80;
        server_name domain2.com  www.domain2.com;

        location / {
            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_pass http://frontend2:80;
        }
    }
}


Замените domain1.com и domain2.com на адреса ваших сайтов, пересоберите образ и переразверните контейнер:
cd ~/DockerNginxSimpleBalancer/balancer

docker-compose build

docker-compose up -d


Разворачиваем несколько геораспределенных сайтов


Создайте по серверу с docker в каждом из регионов InfoboxCloud: Москва, Санкт-Петербург, Амстердам как показано в разделе «Подготовка окружения» и установите git командой:
yum install -y git

Как подключить дополнительные регионы облака
В панели управления перейдите на главную страницу и нажмите «Заказать новую услугу».



Выберите услугу «Облачные серверы».



Выберите нужный регион и завершите процесс заказа до конца.



Подключение дополнительных регионов бесплатно, но требуется, чтобы на счету было более 500 рублей.

Переключаться между регионами можно в правом верхнем углу в панели управления в выпадающем меню.



Для выполнения этой части статьи вам понадобится направить на ip–адрес сервера ваши домены в DNS:
  • 3 записи A для вашего домена первого сайта, каждая из которых будет указывать на сервер в Москве, Амстердаме и Санкт-Петербурге соответственно.
  • 3 записи A для вашего домена второго сайта, каждая из которых будет указывать на сервер в Москве, Амстердаме и Санкт-Петербурге соответственно.
  • запись А вида spb.domain.com, указывающую на сервер в Санкт-Петербурге. Вместо domain.com нужно использовать ваш служебный домен.
  • запись А вида msk.domain.com, указывающую на сервер в Москве. Вместо domain.com нужно использовать ваш служебный домен.
  • запись А вида ams.domain.com, указывающую на сервер в Амстердаме. Вместо domain.com нужно использовать ваш служебный домен.



Необходимые ip–адреса можно найти в панели управления InfoboxCloud.

Сохраните подготовленные переносимые окружения на каждый из серверов:
git clone https://github.com/InfoboxHosting/DockerNginxGeoRedundantBalancer.git


На каждом из серверов отредактируйте файл ~/DockerNginxGeoRedundantBalancer/balancer/conf/nginx.conf и замените domain1.com на имя домена первого сайта, domain2.com на имя домена второго сайта, domain.com на имя служебного домена.

Вместо ручного переименования можно выполнить команду на каждом из серверов:
bash ~/DockerNginxGeoRedundantBalancer/rename.sh domain.com domain1.com domain2.com

, в которой вместо domain.com укажите имя служебного домена, вместо domain1.com – имя первого сайта, domain2.com – имя второго сайта.

Оригинальный nginx.conf
user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
    worker_connections 4086;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    upstream frontend1  {
        #!!!replace domain.com
        #!!!remove backup word in your location
	      server spb.domain.com:8000 backup;
        server msk.domain.com:8000 backup;
        server ams.domain.com:8000 backup;
	  }
    upstream frontend2  {
        #!!!replace domain.com
        #!!!remove backup word in your location
        server spb.domain.com:8001 backup;
        server msk.domain.com:8001 backup;
        server ams.domain.com:8001 backup;
	  }

    server {
        listen 80;
        #!!!replace domain1.com
        server_name domain1.com  www.domain1.com;

        location / {
            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_pass http://frontend1;
        }
    }
    server {
        listen 80;
        #!!!replace domain2.com
        server_name domain2.com  www.domain2.com;

        location / {
            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_pass http://frontend2;
        }
    }
}


nginx.conf после внесения изменений для Амстердама
user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
    worker_connections 4086;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    upstream frontend1  {
        #!!!replace domain.com
	      server spb.plugndo.com:8000 backup;
        server msk.plugndo.com:8000 backup;
        server ams.plugndo.com:8000;
	  }
    upstream frontend2  {
        #!!!replace domain.com
        server spb.plugndo.com:8001 backup;
        server msk.plugndo.com:8001 backup;
        server ams.plugndo.com:8001;
	  }

    server {
        listen 80;
        #!!!replace domain1.com
        server_name site1.plugndo.com  www.site1.plugndo.com;

        location / {
            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_pass http://frontend1;
        }
    }
    server {
        listen 80;
        #!!!replace domain1.com
        server_name site2.plugndo.com  www.site2.plugndo.com;

        location / {
            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_pass http://frontend2;
        }
    }
}



nginx.conf после внесения изменений для Санкт-Петербурга
user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
    worker_connections 4086;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    upstream frontend1  {
        #!!!replace domain.com
	server spb.plugndo.com:8000;
        server msk.plugndo.com:8000 backup;
        server ams.plugndo.com:8000 backup;
	  }
    upstream frontend2  {
        #!!!replace domain.com
        server spb.plugndo.com:8001;
        server msk.plugndo.com:8001 backup;
        server ams.plugndo.com:8001 backup;
	  }

    server {
        listen 80;
        #!!!replace domain1.com
        server_name site1.plugndo.com  www.site1.plugndo.com;

        location / {
            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_pass http://frontend1;
        }
    }
    server {
        listen 80;
        #!!!replace domain1.com
        server_name site2.plugndo.com  www.site2.plugndo.com;

        location / {
            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_pass http://frontend2;
        }
    }
}



nginx.conf после внесения изменений для Москвы
user www-data;
worker_processes 1;
pid /run/nginx.pid;

events {
    worker_connections 4086;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 1000;
    types_hash_max_size 2048;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_min_length 10240;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "msie6";

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    upstream frontend1  {
        #!!!replace domain.com
	server spb.plugndo.com:8000 backup;
        server msk.plugndo.com:8000;
        server ams.plugndo.com:8000 backup;
	  }
    upstream frontend2  {
        #!!!replace domain.com
        server spb.plugndo.com:8001 backup;
        server msk.plugndo.com:8001;
        server ams.plugndo.com:8001 backup;
	  }

    server {
        listen 80;
        #!!!replace domain1.com
        server_name site1.plugndo.com  www.site1.plugndo.com;

        location / {
            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_pass http://frontend1;
        }
    }
    server {
        listen 80;
        #!!!replace domain1.com
        server_name site2.plugndo.com  www.site2.plugndo.com;

        location / {
            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_pass http://frontend2;
        }
    }
}


Теперь для Москвы передите в соответствующую папку:
cd DockerNginxGeoRedundantBalancer/balancerMSK/

Для Амстердама передите в соответствующую папку:
cd DockerNginxGeoRedundantBalancer/balancerAMS/

Для Санкт-Петербурга:
cd DockerNginxGeoRedundantBalancer/balancerSPB/


На каждом из серверов запустите команды
docker-compose build

и
docker-compose up -d


Теперь можно зайти на каждый из сайтов и проверить их доступность:





Теперь из панели управления выключите сервер в любом из регионов. Сайты по-прежнему доступны.
Выключите сервер во втором регионе. Сайты по-прежнему доступны.

Пока доступен хоть один сервер — сайты будут работать. Если запрос попал на выключенный сервер, все современные браузеры делают попытку послать запрос на другой сервер из DNS. В итоге через несколько секунд сайт откроется.

Сделать процесс развертывания серверов и сайтов в нескольких регионах полностью автоматическим можно с помощью Ansible.
Часть 1.
Часть 2.
Часть 3.
Часть 4.
Часть 5.

Как получить пробную версию InfoboxCloud бесплатно?


Пришлите нам ваш адрес электронной почты и ФИО на trukhinyuri@infoboxcloud.com, в ответ получите данные для доступа к панели управления. Вы можете тестировать новый регион облака в течение 15 дней, далее можно перейти на полную версию облака. Запросить бесплатную пробную версию можно до 5 сентября 2015 года.

Если у вас есть вопросы или замечания, напишите нам и мы с радостью ответим.

Если вы не можете оставлять комментарии на Хабре, напишите нам в Сообществе.

Успешного использования NGINX и Docker в InfoboxCloud!

Комментарии (5)


  1. esinev
    22.08.2015 03:24

    А как же предупреждение на сайте docs.docker.com/compose, что composer пока еще не рекомендуется использовать для production

    Compose is great for development environments, staging servers, and CI. We don’t recommend that you use it in production yet.


    1. Bal
      22.08.2015 05:59

      Уйма компаний сегодня использует Composer в продакшне под большими нагрузками. Просто нужно отдавать себе отчёт и иметь определённый навык решения проблем, если таковые возникнут.


    1. infobox
      22.08.2015 08:07
      +2

      Compose – способ описания и запуска контейнеров. Самое страшное, что может произойти — окружение просто не запустится и compose вылетит с ошибкой. Такое бывало в 1.3.1 (с флагом restart: always), в 1.3.2 и выше пока не замечено. После того, как compose запустит контейнеры, он не участвует в работе Docker, поэтому его использование совсем не опасно. Если продакшн критичен к доступности и подобным ошибкам, можно в Compose описывать dev окружения, а развертывать продакшн окружения скриптом без compose. В случае использования геораспределенных систем неразвертывание одного хоста совершенно некритично — у вас будет время запустить окружение вручную.


  1. dimoclus
    24.08.2015 15:27

    bash <(curl -s http://repository.sandbox.infoboxcloud.ru/scripts/docker/centos7/install.sh)
    Кхм…
    curl -s http://repository.sandbox.infoboxcloud.ru/scripts/docker/centos7/install.sh | bash -e


    1. infobox
      24.08.2015 21:12

      Наш вариант на 2 символа короче, а суть та же.