Мы используем контейнеры Linux в Univers Labs с 2013 года, когда мы впервые начали развертывать приложения на платформе «программное обеспечение как услуга» Heroku. В то время Heroku предлагал нам ряд преимуществ по сравнению с развертыванием на виртуальных машинах в облаке или развертыванием на «голом железе». Предпосылка проста: создайте приложение, убедитесь, что оно может работать в среде Heroku, и поместите его в репозиторий Heroku Git; Heroku берет на себя управление приложением, сервером, на котором оно работает, и сетью, от которой оно зависит, сводя к минимуму расходы на системное администрирование и хостинг. В 2017 году Univers Labs перешла с Heroku на Kubernetes, управлялась с помощью Deis и развертывалась на Google Container Engine. При этом мы укрепили нашу приверженность предложению нашим клиентам доступного, надежного, масштабируемого хостинга на основе технологии контейнеризации от ведущих мировых поставщиков облачных услуг.

Наша инфраструктура является передовой, но это может усложнить разработку приложений. Настройка среды разработки может быть сложной задачей сама по себе. В течение последних шести месяцев я работал над заменой нашей предыдущей практики разработки с использованием организованных виртуальных машин Linux на решение, полностью основанное на Docker. При этом я сэкономил кучу дискового пространства на своем ноутбуке с Ubuntu, ускорил рабочий процесс разработки и усилил безопасность своего устройства.

Настройка среды для разработки PHP-приложений — основная проблема в нашем рабочем процессе разработки. Нашим PHP-приложениям нужен веб-сервер, среда выполнения PHP, сервер MySQL, сервер Memcached и Grunt. Раньше мы организовывали все эти движущиеся части с помощью Vagrant, Ansible и просто устанавливали и запускали службы на хост-системе. С Docker мы можем покончить со всем этим. Ядром этого нового рабочего процесса Docker является пользовательский образ Docker, основанный на образе Docker Heroku Cedar-16. Установив Heroku PHP Buildpack и средство запуска Procfile в образ Heroku Cedar-16, мы создаем среду для запуска и обслуживания PHP-приложений, которая отражает нашу среду Deis. Этот образ весит около 500 МБ: здоровенный, но часть размера наших виртуальных машин Ubuntu.

FROM heroku/heroku:16
# To compile this Dockerfile, run `composer update — ignore-platform-reqs && docker build -t phpslug .`.
ADD ./composer.json /app/composer.json
ADD ./composer.lock /app/composer.lock
ADD ./vendor /vendor
# Shoreman is a Procfile runner written in Bash: https://github.com/chrismytton/shoreman.
ADD ./shoreman /heroku/shoreman
# Run symlinks the output from the buildpack’s compile script into your working directory, so that your working directory functions like a compiled PHP Heroku slug.
ADD ./run /heroku/run
# Create non-root user and give this user ownership of all assets; this user will compile the buildpack and invoke its start script.
RUN useradd -ms /bin/bash heroku
RUN chown -R heroku:heroku /app
RUN chown -R heroku:heroku /heroku
RUN chown -R heroku:heroku /vendor
USER heroku
WORKDIR /app
RUN /vendor/heroku/heroku-buildpack-php/bin/compile /app /tmp/app-build
RUN chmod +x /heroku/run
RUN chmod +x /heroku/shoreman
# Copy everything out of /app into a backup directory.
RUN cp -ra /app/. /heroku
RUN rm -r /app/*
RUN rm -r /vendor/*
# Set PATH to traverse the right folders in /app first.
ENV PATH “$PATH:/app/.heroku/php/sbin:/app/.heroku/php/bin”
ENV PORT 5000
ENV HOME_URL http://localhost:5000
ENV SITE_URL http://localhost:5000
# To run this container in your working directory, run `docker run — rm -it -p 80:5000 -p 5000:5000 -v $(pwd):/app phpslug`. This would be a useful command to create a shell alias for.
CMD /heroku/run

С помощью Docker Compose этот образ Docker можно запустить в сочетании с контейнерами MySQL и Node.js, чтобы предоставить базу данных и скомпилировать наш исходный код с помощью Grunt.

version: "3"
 services:
     wordpress:
         image: phpslug
         volumes:
             - .:/app
         networks:
             - wordpress
         depends_on:
             - mysql
             - memcached
     mysql:
         image: mysql
         networks:
             - wordpress
         environment:
             MYSQL_ROOT_PASSWORD: root
             MYSQL_DATABASE: projectdb
             MYSQL_USER: projectuser
             MYSQL_PASSWORD: projectpassword
     memcached:
         image: memcached:alpine
         command: memcached -m 512
         networks:
             - wordpress
 networks:
     wordpress:
         driver: bridge

И это все, что вам нужно для запуска WordPress!

Мне больше не нужны PHP, Nginx, MySQL, PostgreSQL, MongoDB, Memcached, ElasticSearch, Neo4j, Grunt, Webpack, Vagrant, Virtualbox или любой из тысячи пакетов, которые я устанавливал на Ubuntu раньше. Я удалил их все и заменил в своих проектах контейнерами Docker, организованными с помощью Docker Compose. «Совершенство в конце концов достигается не тогда, когда уже нечего добавить, а тогда, когда уже нечего убрать».

Эта настройка работает для запуска одной установки WordPress. Контейнеры Docker запускаются и останавливаются за несколько секунд, работают быстро и требуют мало ресурсов. Тем не менее, мы также поддерживаем многосайтовые установки WordPress, доступ к которым возможен только через определенные доменные имена. Как нам подключиться к контейнеру PHP, используя доменное имя?

Docker имеет встроенный DNS-сервер для облегчения обнаружения служб внутри сетей Docker; Например, контейнеры, запущенные с помощью Docker Compose, могут находить и подключаться друг к другу, используя имена своих контейнеров или сетевые псевдонимы. Вот как WordPress может подключиться к базе данных MySQL по адресу `mysql:3306`; DNS-сервер Docker заботится о преобразовании имени хоста mysql в IP-адрес контейнера MySQL. Если мы хотим, чтобы наш хост Docker использовал этот DNS-сервер, нам нужно изменить конфигурацию DNS Docker, и нам нужен прокси-сервер DNS, работающий внутри сети Docker. Чтобы настроить демон Docker, отредактируйте файл `/etc/docker/daemon.json`.

{
  "dns": [
   "208.67.222.222",
   "208.67.220.220"
   ]
}

Для нашего DNS-прокси мы будем использовать pdnsd.

FROM alpine
ADD ./pdnsd.conf /etc/pdnsd.conf
RUN apk add -U pdnsd && rm -rf /var/cache/apk/*
EXPOSE 53/tcp 53/udp
CMD [“pdnsd”]

И мы запустим его с помощью Docker Compose.

version: "3"
 services:
     pdnsd:
         build: ./pdnsd
         restart: always
         volumes:
             - pdnsd-cache:/var/cache/pdnsd
         ports:
             - 127.0.0.1:53:53/tcp
             - 127.0.0.1:53:53/udp
         networks:
             - web-apps
 networks:
     web-apps:
         external: true
 volumes:
     pdnsd-cache: {}

Теперь мы можем настроить Ubuntu для использования «127.0.0.1» в качестве DNS-сервера. Chrome будет консультироваться с демоном pdnsd, работающим в контейнере pdnsd; `pdnsd` будет консультироваться с DNS-сервером Docker; и DNS-сервер Docker будет консультироваться с DNS-серверами, указанными в `/etc/docker/daemon.json`, а также с сетью Docker. Таким образом, наш хост Docker настроен на преобразование имен контейнеров Docker в IP-адреса. `pdnsd` также кэширует мои DNS-запросы, что в целом ускоряет просмотр веб-страниц.

Теперь мы можем подключиться к нашей мультисайтовой установке WordPress!

Это лишь малая часть возможностей, которые предлагают контейнеры Docker и Linux. Я надеюсь, что со временем мы сможем найти надежный способ организовать наши развертывания в Deis и Kubernetes с помощью декларативного метода, такого как файлы Compose. А пока я надеюсь протестировать этот новый рабочий процесс на macOS, чтобы другие участники команды Univers Labs могли воспользоваться преимуществами разработки с использованием контейнеров.