- PVSM.RU - https://www.pvsm.ru -
И снова здравствуйте! Почти пять лет уже не писал здесь новых статей, хотя, если честно, всегда знал, что рано или поздно начну это делать снова. Не знаю как вам, а мне все таки это дело всегда казалось довольно увлекательным.
Начинать написание нового материала после столь продолжительного отдыха от этого дела — труднее всего. Но раз цель поставлена — надо идти до конца. Начну немного издалека.
Всю свою сознательную жизнь основным родом моей деятельности была и остается по сей день веб-разработка. Именно поэтому, сознаюсь сразу, что данный материал стоит воспринимать именно как попытка построения Docker-кластера от системного администратора любителя, но никак не профессионала. В этой статье я не могу не претендовать на экспертное мнение в кластеризации и даже, более того, сам же хочу проверить достоверность собственного опыта.
Под хабракатом вы найдете Quick Start по использованию Docker на уровне, необходимом для решения конкретных задач, обозначенных ниже, без углубления в "дебри" виртуализации и прочих сопутствующих тем. Если вы до сих пор хотите начать успешно использовать эту современную технологию, тем самым значительно упростив целый ряд процесов: от разработки веб-продуктов и до разворачивания и переноса оных под какое-либо современное оборудование — прошу под кат!
Начнем, конечно же, с постановки задачи и определения основных технологий/методик, используемых в гайде.
С самого начала я заинтерисовался Docker'ом с целью быстрого создания небольшого, но довольно универсального кластера под собственные проекты (рабочие, учебные, etc). Так как системным администрированием я профессионально заниматься не собирался — я решил, что должен обучиться основам кластеризации ровно до того момента, когда я смог бы без особых затруднений разворачивать любой популярный программный стек для веб-проекта. Далее я рассмотрю разворачивание на Docker следующих конфигураций:
Первые две в представлении, думаю, не нуждаются. Третяя же состоит из MongoDB [1], Express.js [2], Node.js [3]. MEAN я чаще всего использовал для написания RESTful API [4], например, для дальнейшего разрабатывания на его основе мобильного приложения.
После этого я сам себе немного усложнил задачу, добавив следующие требования:
Docker [7] — программное обеспечение для автоматизации развёртывания и управления приложениями в среде виртуализации на уровне операционной системы.
Letsencrypt [8] — Бесплатный автоматический центр авторизации (CA). Предоставляет бесплатные сертификаты для включения поддержки HTTPS (SSL / TLS) на любом веб-сайте.
Проблем с установкой Docker и других пакетов не должно возникнуть. На официальном сайте этот процес расписан довольно подробно. Далее я распишу общий перечень команд, необходимых для начальной настройки.
Сразу уточню, что в этой статье я рассматриваю настройку Docker и всех сопутствующих программ на дистрибютиве CentOS 7, так как на этой ОС я уже давно привык работать, как на основной серверной системе. В целом на любом другом Linux-дистрибютиве действия будут примерно аналогичные, с той лишь разницей, что, например, для Ubuntu вы будете использовать apt-get вместо yum / dnf (для CentOS / Fedora).
Подготовка:
$ sudo yum update
$ sudo tee /etc/yum.repos.d/docker.repo <<-'EOF'
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/7/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF
Установка Docker Engine:
$ sudo yum install docker-engine
$ sudo systemctl enable docker.service
$ sudo systemctl start docker
Создание группы пользователей 'docker' и добавление туда текущего пользователя (это необходимо для того, чтобы работать с Docker без использования 'sudo' или root-доступа):
$ sudo groupadd docker
$ sudo usermod -aG docker your_username
Проверка успешности установки:
$ docker run --rm hello-world
Установка Docker Compose (утилита для объединения нескольких контейнеров в одно веб-приложение):
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
Утилита для автоматического получения/обновления SSL-сертификатов от Letsencrypt:
Перед установкой необходимо включить EPEL-репозиторий [10], если этого не было сделано ранее.
$ sudo yum install certbot
Docker представляет из себя дополнительный уровень абстракции; систему, автоматизирующую виртуализацию на уровне операционной системы.
"Виртуализация на уровне операционной системы — метод виртуализации, при котором ядро операционной системы поддерживает несколько изолированных экземпляров пространства пользователя, вместо одного. Эти экземпляры (часто называемые контейнерами или зонами) с точки зрения пользователя полностью идентичны реальному серверу. Ядро обеспечивает полную изолированность контейнеров, поэтому программы из разных контейнеров не могут воздействовать друг на друга."
From Wikipedia [11]
Основные преимущества использования Docker:
Далее расмотрим основные команды, которые нам понадобятся для создания кластера:
По сути основная команда, выполняющая запуск нового контейнера.
Основные параметры:
Команда, с помощью которой можно получить список запущенных контейнеров.
Команда, останавливающая работу контейнера.
Удаление определенного контейнера.
Внимание: прежде, чем удалить контейнер, его необходимо остановить (docker stop)!
Более подробно разобраться в работе каждой команды вы можете в официальной документации [13]. В этой статье я обратил внимание только на основные команды, необходимые для успешного начала работы с Docker.
Конкретные примеры использования docker run
вы увидите в этой статье немного далее.
Проблема: определенная сложности реализации кластера с использованием виртуальных хостов в различных контейнерах заключается в том, что один порт может "прослушиваться" только одним контейнером (настраивается через --publish). Получается, что по-умолчанию мы можем создать только один контейнер, который будет отвечать на запросы к серверу через порт 80 и/или 443 (http и https протоколы, соответственно).
Решение: в принципе, довольно очевидно использовать для решения этой проблемы Reverse Proxy, инкапсулированный в один контейнер, который и будет "прослушивать" порты 80 и 443. Функционал данного контейнера будет заключаться в автоматическом перенаправлении запросов, в соответствии с используемыми виртуальными хостами.
Такой контейнер существует в открытом доступе в Docker Hub — nginx-proxy [14].
Кроме решения проблемы с виртуальными хостами, он по-умолчанию поддерживает работу с SSL-сертификатами, что позволяет развернуть поддержку защищенного HTTPS-доступа к сайту.
Прежде, чем запустить данный Reverse Proxy контейнер, давайте получим SSL-сертификаты для доменов, которые мы хотим использовать в качестве виртуальных хостов.
Для получения SSL-сертификата будем использовать бесплатный сервис letsencrypt. Для этого на предыдущих этапах мы уже установили утилиту certbot. Я не буду останавливаться на подробностях использования этой утилиты (это все есть в официальной документации [9]).
Приведу лишь готовую команду для автоматического получения бесплатного SSL-сертификата для вашего домена:
$ sudo certbot certonly -n -d yourdomain.com --email your@email.com --standalone --noninteractive --agree-tos
--standalone --noninteractive --agree-tos
— данные параметры необходимы для того, чтобы certbot с одной стороны отработал в фоновом режиме, а с другой — сгенерировал сертификат без конкретной привязки к определенному веб-серверу.
В результате успешного выполнения данной команды будут сгенерированы два файла:
/etc/letsencrypt/live/yourdomain.com/fullchain.pem
/etc/letsencrypt/live/yourdomain.com/privkey.pem
Для корректной работы nginx-proxy нам необходимо поместить все файлы сертификатов в одну директорию, при этом используя для каждого доменного имени по два файла в формате: yourdomain.com.crt (файл сертификата) и yourdomain.com.key (приватный ключ).
В данном случае логично воспользоваться символьными ссылками. Пример:
$ mkdir ssl-certs
$ cd ssl-certs
$ ln -s /etc/letsencrypt/live/yourdomain.com/fullchain.pem ./yourdomain.com.crt
$ ln -s /etc/letsencrypt/live/yourdomain.com/privkey.pem ./yourdomain.com.key
На расширение .pem не стоит обращать особого внимания — суть файлов от этого не меняется.
Аналогичным образом мы можем получить сертификаты для любых, принадлежащих нам, доменных имен и далее использовать их в качестве виртуальных хостов. Единственное требование заключается в том, что A-записи этих доменных имен должны быть направленны на внешний IP-адрес сервера, на котором вы и выполняете certbot certonly ...
Сгенерировав сертификаты для каждого домена, мы готовы к запуску nginx-proxy контейнера.
$ docker run -d -p 80:80 -p 443:443
-v /full/path/to/ssl-keys:/etc/nginx/certs
-v /var/run/docker.sock:/tmp/docker.sock:ro
jwilder/nginx-proxy
Рассмотрим эту команду более подробно:
-p 80:80 -p 443:443
— привязываем к контейнеру порты 80 и 443. При чем 80-ый порт сервера отвечает 80-ому порту внутри контейнера и аналогично с портом 443. В формате PORT:PORT2 выполняется создание соответствий между реальным портом всей машины и портами внутри отдельного виртуального контейнера.-v /full/path/to/ssl-keys:/etc/nginx/certs
— первый volume, необходимый для настройки данного контейнера. Здесь мы выполняем связь стандартной директории /etc/nginx/certs внутри самого контейнера с директорией, в которую мы вручную поместили символьные ссылки на файлы сертификатов и приватных ключей для наших доменов (на предыдущем этапе).jwilder/nginx-proxy
— идентификатор контейнера внутри Docker Hub. Docker Engine автоматически скачает изображение данного контейнера, если оно еще не было загруженно ранее.Вот и все — первый контейнер запущен! И этим контейнером является Reverse Proxy, через который мы сможем далее задать любому контейнеру-приложению VIRTUAL_HOST.
Итак, наконец-то мы можем перейти к запуску контейнеров, в которых мы уже сможем разрабатывать наши веб-приложения.
В базе Docker Hub довольно много разных вариантов LAMP-контейнеров. Лично я использовал этот: tutum-docker-lamp [15].
Ранее, помимо Docker Engine, мы установили утилиту Docker Compose. И вот только с этого момента мы начинаем ее использовать. Docker Compose удобен для создания приложений, в которых несколько контейнеров объединены и именно совместно представляют собой разрабатываемое приложение.
Для того, чтобы запустить этот контейнер в связке с нашим nginx-proxy необходимо:
Загрузить в отдельную директорию исходники tutum-docker-lamp (удобнее всего это сделать с помощью git clone
);
web:
build: .
volumes:
- ./www:/var/www/html
environment:
- MYSQL_PASS=yourmysqlpassword
- VIRTUAL_HOST=yourdomain.com
Выполнить запуск с помощью docker-compose:
$ docker-compose up
Как видите в данном примере, управление виртуальными хостами при использовании nginx-proxy выполняется с помощью всего одной переменной окружения VIRTUAL_HOST.
Внимание на связку ./www:/var/www/html
. Очевидно, что рабочей директорией вашего сайта становится папка www (ее необходимо создать вручную). Все файлы в этой директории автоматически попадают и в /var/www/html
внутри запущеного контейнера.
Разобраться более детально с синтаксисом файла настроек docker-compose.yml вы можете в официальной документации [16].
Запуск LEMP-контейнера принципиально ничем не отличается от примера выше.
Сначала находим контейнер в Docker Hub. Например: docker-lemp [17].
Скачиваем исходники контейнера и добавляем docker-compose.yml. Внутри этого файла настроек уже нашего кастомного контейнера вы можете не только задавать переменную окружения VIRTUAL_HOST, но и настраивать всё, что позволяет файл Dockerfile. Например в Dockerfile определено:
VOLUME /var/www/
Следовательно вы можете в docker-compose.yml выполнить связку с этим томом примерно так:
volumes:
- ./www:/var/www
Пример такой конфигурации: docker-nodejs-mongodb-example [18].
Файл docker-compose.yml выглядит следующим образом:
web:
build: .
volumes:
- "./api:/src/app"
environment:
- VIRTUAL_HOST=yourdomain.com
links:
- "db:mongo"
db:
image: mongo
ports:
- "27017:27017"
volumes:
- ./data/db:/data/db
В данном случае будет создано два связанных контейнера. Один — для базы (mongoDB), второй собственно для NodeJS приложения.
Для запуска этой связки контейнеров используется все та же команда docker-compose up
.
Некоторые, более сложные контейнеры, требуют дополнительной настройки для запуска с использованием nginx-proxy. К таким контейнерам относится и gitlab-ce.
Я сначала приведу полностью рабочую версию команды для запуска этого контейнера, с учетом той конфигурации, которая обсуждается в этой статье, а далее поясню ниже некоторые детали из этой команды.
Итак:
$ docker run --detach
--hostname gitlab.yourdomain.com
--publish 2289:22
--restart always
--name custom-gitlab
--env GITLAB_OMNIBUS_CONFIG="nginx['listen_port'] = 80; nginx['listen_https'] = false; nginx['proxy_set_headers'] = { "X-Forwarded-Proto" => "https", "X-Forwarded-Ssl" => "on" }; gitlab_rails['gitlab_shell_ssh_port'] = 2289; external_url 'https://gitlab.yourdomain.com'; gitlab_rails['smtp_enable'] = true; gitlab_rails['smtp_address'] = 'smtp.mailgun.org'; gitlab_rails['smtp_port'] = 2525; gitlab_rails['smtp_authentication'] = 'plain'; gitlab_rails['smtp_enable_starttls_auto'] = true; gitlab_rails['smtp_user_name'] = 'postmaster@mg.yourdomain.com'; gitlab_rails['smtp_password'] = 'password'; gitlab_rails['smtp_domain'] = 'mg.yourdomain.com';"
--env VIRTUAL_HOST="gitlab.yourdomain.com"
--volume /srv/gitlab/config:/etc/gitlab
--volume /srv/gitlab/logs:/var/log/gitlab
--volume /srv/gitlab/data:/var/opt/gitlab
gitlab/gitlab-ce:latest
Для того, чтобы схема с Reverse Proxy работала в данном случае, необходимо добавить:
nginx['listen_port'] = 80;
nginx['listen_https'] = false;
nginx['proxy_set_headers'] = { "X-Forwarded-Proto" => "https", "X-Forwarded-Ssl" => "on" };
Причина заключается в том, что nginx-proxy при работе с контейнерами обращается внутри них к порту 80, а не 443. Без дополнительных заголовков в настройке nginx внутри контейнера gitlab-ce (proxy_set_headers) запрос проходить не будет (ошибка 502 "Bad Gateway").
Кроме этого важно добавить:
external_url 'https://gitlab.yourdomain.com';
Суть в данных строках:
--publish 2289:22
Если работа с рабочей машиной производится через SSH-протокол, то мы не можем создавать связку напрямую "22:22", так как порт 22 уже занят сервисом sshd.
Решение этой проблемы описано в официальной документации gitlab-ce. Все просто: мы привязываем любой другой (кроме 22) порт внутри сервера к 22 порту внутри контейнера. В данном примере используется порт 2289.
Параллельно с этим важно не забыть добавить
gitlab_rails['gitlab_shell_ssh_port'] = 2289;
В настройки самого GitLab.
Таким образом после запуска gitlab-ce и создания в нем самом какого-либо репозитория работа с ним будет производится по адресу в стиле:
ssh://git@gitlab.yourdomain.com:2289/username/repository_name.git
Здесь тоже необходимо использовать специальные переменные окружения самого GitLab.
В моем случае (я использую Google Cloud Engine) по-умолчанию закрыты порты 25, 465 (т.е. стандартные порты SMTP-протокола). Одним из вариантов решения этой проблемы является использование стороннего сервиса (как например MailGun [19]) в качестве SMTP-сервера. Для этого используем настройки:
gitlab_rails['smtp_enable'] = true;
gitlab_rails['smtp_address'] = 'smtp.mailgun.org';
gitlab_rails['smtp_port'] = 2525;
gitlab_rails['smtp_authentication'] = 'plain';
gitlab_rails['smtp_enable_starttls_auto'] = true;
gitlab_rails['smtp_user_name'] = 'postmaster@mg.yourdomain.com';
gitlab_rails['smtp_password'] = 'password';
gitlab_rails['smtp_domain'] = 'mg.yourdomain.com';
Ну и наконец не забываем о --env VIRTUAL_HOST="gitlab.yourdomain.com"
— переменной окружения для самого nginx-proxy.
Вот и все. После выполнения этой инструкции Docker запустит полностью функционирующий контейнер с GitLab CE.
Это последний момент, который я хочу отдельно осветить в этом гайде.
Процесс обновления GitLab с помощью Docker упрощается до нескольких команд:
docker stop custom-gitlab
— останавливаем работающий контейнер;
docker rm custom-gitlab
— удаляем контейнер GitLab CE.
Важный момент: удаление контейнера не означает удаление данных, которые были созданы в процесе использования системы. Поэтому вы можете выполнять эту команду без каких-либо опасений.
docker pull gitlab/gitlab-ce
— собственно обновление изображения контейнера;
Вот и все. Выполнив эти 4 команды, GitLab автоматически обновится до последний версии и запустится через Docker Engine.
Итак, в результате выполнения этого гайда должен получится Docker-кластер, в основе которого лежит NGINX Reverse Proxy; каждое веб-приложение имеет свой виртуальный хост, который при этом поддерживает защищенный HTTPS-протокол.
Вместе с веб-приложениями функционирует GitLab-кластер, полностью настроенный, вплоть до доступа к SMTP-серверу.
Я очень надеюсь, что это моё небольшое исследование окажется полезным или, хотя бы, интересным, для многих читателей ХабраХабра. Конечно же, буду рад выслушать критику профессионалов, дополнения или усовершенствования к статье!
Спасибо за внимание!
Автор: Kyborg2011
Источник [20]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/open-source/221175
Ссылки в тексте:
[1] MongoDB: https://ru.wikipedia.org/wiki/MongoDB
[2] Express.js: https://ru.wikipedia.org/wiki/Express.js
[3] Node.js: https://ru.wikipedia.org/wiki/Node.js
[4] RESTful API: https://ru.wikipedia.org/wiki/REST
[5] виртуальных хостов: https://ru.wikibooks.org/wiki/VirtualHost
[6] GitLab CE: https://gitlab.com/gitlab-org/gitlab-ce
[7] Docker: https://www.docker.com/
[8] Letsencrypt: https://letsencrypt.org/
[9] официальный сайт: https://certbot.eff.org/
[10] включить EPEL-репозиторий: https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F
[11] Wikipedia: https://ru.wikipedia.org/wiki/%D0%92%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D0%BD%D0%B0_%D1%83%D1%80%D0%BE%D0%B2%D0%BD%D0%B5_%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D0%BE%D0%B9_%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B
[12] Docker Hub: https://hub.docker.com/
[13] официальной документации: https://docs.docker.com/
[14] nginx-proxy: https://github.com/jwilder/nginx-proxy
[15] tutum-docker-lamp: https://github.com/tutumcloud/lamp
[16] официальной документации: https://docs.docker.com/compose/gettingstarted/
[17] docker-lemp: https://github.com/stenote/docker-lemp
[18] docker-nodejs-mongodb-example: https://github.com/Kyborg2011/findme-api
[19] MailGun: http://mailgun.com/
[20] Источник: https://habrahabr.ru/post/317636/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.