В вопросе связанном с DNS попил мне Docker кровушки основательно, ибо столько там разных мест в которых тебе предлагают написать заветные цифры, что прямо-таки глаза разбегаются.
Итак, задача: необходимо поднять окружение разработчика для одновременной работы с несколькими веб-проектами висящими на доменах вида example.app. При этом данные домены должны быть доступны из контейнеров, с хоста, а также, например, из эмулятора Genymotion. Кроме того, из контейнеров должен быть доступен и внешний интернет. Все это усугубляется корпоративным Intranet со своим внутренним DNS сервером.
Для решения нам потребуется:
- docker — движок для работы с контейнерами
- docker-compose — работа с мульти-контейнерными решениями
- dnsmasq — легкий DNS (а также DHCP и TFTP) сервер
- laradock (опционально) — готовое мульти-контейнерное решение для разработчика
Установку пп.1-3 пропускаю, как очевидную. Обратите внимание на версию docker-compose, нам нужна версия 1.8 или выше (на момент написания в репозитариях лежала старая версия).
Для опытного работника дока докера нет никакой проблемы выбрать нужные образы, слинковать их, пробросить порты, установить дополнительные библиотеки — информации на эту тему достаточно. Но если вы хотите начать работу прямо сейчас, то давайте воспользуемся продуктом коллективного сознательного — laradock.
Из названия laradock можно выявить намек на смычку Laravel + Docker. Так и было изначально, но в данный момент такая направленность ушла и теперь проект ориентируется на любые веб-приложения.
Итак, laradock — это yml-файл и набор сопутствующих сконфигурированных образов для docker-compose
, позволяющий разворачивать набор контейнеров с nginx, mysql, mongoDB и еще кучей разных плюшек типа Memcached, Aerospike и т.д. (уже сейчас набор очень широкий и постоянно расширяется).
Немаловажным является то, что установка некоторых дополнительных плагинов или библиотек сводится к простой правке yml-файла, например:
- INSTALL_XDEBUG=true
и пересборке образа:
docker-compose build php-fpm
Кроме того, в laradock все готово, чтобы засунуть туда одновременно столько проектов, сколько душе угодно — просто обратите внимание на примеры конфигурации в ./nginx/sites
.
laradock прокидывает порт 80 из контейнера nginx/apache на хост-машину, поэтому чтобы после поднятия нужных контейнеров (набор вы выбираете самостоятельно)
docker-compose up -d nginx mysql phpmyadmin
увидеть сконфигурированные заранее в nginx/apache сайты example.app и mysite.app нужно просто прописать для них локальный IP в файле /etc/hosts
127.0.0.1 example.app
127.0.0.1 mysite.app
Контейнер phpmyadmin прокидывется на порт 8080, поэтому увидеть его в работе можно по адресу
http://localhost:8080
. Ну и имейте в виду, что контейнер с мускулом работает для всех остальных контейнеров на хостеmysql
, к которому и следует подключаться.
На самом деле, если у вас изолированные проекты и нет корпоративного intranet, то вы можете прерваться в данном месте и уже начать разработку. Проблема с DNS вас не коснулась.
Если вы читаете дальше, то вам видимо нужно:
- Из своего приложения обратиться к своему же отдельному backend на другом домене.
- Из приложения, запущенного в эмуляторе Android (iOS и т.д.) обратиться к своему backend.
- Из своего приложения обратиться к стороннему API, но вы сидите в intranet с местным DNS-сервером.
Итак, решаем пункты 1 и 2. Пункт 3 решится сам собой, добавлением всего одной строки — адреса вашего intranet DNS. Сделаем так, чтобы наши домены были доступны из контейнеров (в частности из php-fpm). Для этого нам потребуется dnsmasq.
Устанавливаем его, если вы еще этого не сделали:
sudo apt-get install dnsmasq
Для того, чтобы разрешить DNS имя dnsmasq заглядывает в /etc/resolv.conf в поисках IP вышестоящего DNS-сервера. В принципе, мы могли бы туда его и прописать, но в этом файле четко написано, что изменять его не стоит, т.к. он может быть перезаписан. Поэтому создадим собственный файл /etc/resolv.ext.conf со следующим содержимым:
# Гугловские DNS
nameserver 8.8.8.8
nameserver 8.8.4.4
# Корпоративный DNS (это и есть та самая срока, которая выведет вас из застенков интранет)
nameserver <IP корпоративного DNS>
Теперь нужно чтобы dnsmasq стал его использовать. В файле /etc/dnsmasq.conf нужно найти, раскомментировать и исправить параметр, указав там наш файл:
resolv-file=/etc/resolv.ext.conf
Однако не все так просто… хитрый dnsmasq не будет его использовать пока мы не выполним еще одну манипуляцию.
Здесь нужно сделать маленькую ремарку: можно не заморачиваться с собственным файлом конфигурации, а засунуть nameserver'а в оригинальный resolv.conf, но засунуть правильно. Засовывать их нужно в /etc/resolvconf/resolv.conf.d/head и тогда они будут автоматически добавляться в начале resolv.conf Однако имейте в виду, что там может быть только 3 неймсервера, а в своем файле — сколько угодно.
Но вернемся к нашему случаю. Для того, чтобы наш resolv.ext.conf всеже был прочитан необходимо в файле /etc/default/dnsmasq указать:
IGNORE_RESOLVCONF=yes
Что за бред, скажете вы… Игнорировать файл, чтобы его прочитать? Не совсем так. Комментарий перед этой опцией четко разъясняет что она делает. Мы заставляем dnsmasq игнорировать вывод утилиты
resolvconf
, если она установлена и обратить внимание именно на наш файл.
В целом это все. Осталось только объяснить Docker, что в нашем маленьком мирке за разрешение DNS отвечает dnsmasq. Открываем /etc/default/docker и указываем:
DOCKER_OPTS="--dns 127.0.0.1"
Рестартуем сервисы:
sudo service dnsmasq restart
sudo service docker restart
и...
… опять заминка:
все заработает только если в вашем линуксе используется система инициализации Upstart или SysVinit (об этом четко написано в данном файле). Но если вы используете, например, Ubuntu 15.04 или выше, то у вас используется уже более продвинутая systemd и нам потребуются дополнительные телодвижения. Но для начала проверим, что же мы используем:
$ sudo stat /proc/1/exe
Файл: '/proc/1/exe' -> '/lib/systemd/systemd'
Как видите, из вывода команды становится ясно что именно используется у нас. В данном случае systemd.
Ну что же, вылечим и этого. Конфигурация сервиса изначально лежит в /lib/systemd/system/docker.service. Можно его просто скопировать и подправить:
sudo cp /lib/systemd/system/docker.service /etc/systemd/system/docker.service
но мы поступим более порядочно — изменим только то, что следует изменить:
sudo [ ! -e /etc/systemd/system/docker.service.d/ ] && mkdir -p /etc/systemd/system/docker.service.d/
sudo cat << 'EOF' > /etc/systemd/system/docker.service.d/docker.conf
[Service]
EnvironmentFile=-/etc/default/docker
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// $DOCKER_OPTS
EOF
Как вы уже поняли, мы создали файл /etc/systemd/system/docker.service.d/docker.conf (так называемый drop-in) с изменениями стандартных параметров и передаем наши параметры dns, прописанные в /etc/default/docker
при старте сервиса.
Осталось только перезапустить сервисы:
sudo systemctl daemon-reload
sudo service docker restart
и убедиться что все в порядке:
sudo service docker status
В выводе этой команды вы увидите много уже знакомого: и подключенный drop-in, и стартовавший сервис с нашим dns. Вот теперь действительно ВСЕ!
Полезные ссылки:
- github.com/docker/docker/issues/9889
- docs.docker.com/engine/admin/systemd
- unix.stackexchange.com/questions/196166/how-to-find-out-if-a-system-uses-sysv-upstart-or-systemd-initsystem
Автор: dlnsk