Containerization is the new virtualization
The Docker Book
Что такое Docker?
В отличии от классических систем виртуализации, которые эмулируют работу компьютерного железа и ядра операционной системы поверх него, Docker использует виртуализацию на уровне ядра: все виртуализируемые им процессы делят ядро операционной системы хоста, что позволяет значительно сократить как требуемые ресурсы, так и время, необходимое на запуск/обслуживание таких систем. В идеале, каждый процесс изолируется в собственном контейнере (linux container, lxc), который содержит набор необходимых ему библиотек, что позволяет забыть о dependecy hell, а также легко переносить стек проекта между серверами. В статье ниже я проиллюстрирую, как можно использовать Docker для настройки среды разработчика, повторяющей среду продакшена: предположим, что там используется Ubuntu LTS, PHP 5.4, Nginx.
Установка Docker
Почитать об установке Docker на разные ОС можно на официальном сайте проекта: https://docs.docker.com/installation/#installation
Настройка контейнера
Прежде всего, мы должны написать инструкцию, по которой Docker должен сформировать образ (image), на основе которого будет работать наше приложение — Dockerfile.
# src: build/backend/Dockerfile
# Используем за основу контейнера Ubuntu 14.04 LTS
FROM ubuntu:14.04
# Переключаем Ubuntu в неинтерактивный режим — чтобы избежать лишних запросов
ENV DEBIAN_FRONTEND noninteractive
# Устанавливаем локаль
RUN locale-gen ru_RU.UTF-8 && dpkg-reconfigure locales
# Добавляем необходимые репозитарии и устанавливаем пакеты
RUN apt-get install -y software-properties-common
RUN add-apt-repository -y ppa:ondrej/php5-5.6
RUN add-apt-repository -y ppa:nginx/stable
RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y wget curl php5-fpm php5-mysql php5-gd php5-curl php-pear php-apc php5-mcrypt php5-imagick php5-memcache supervisor nginx
# Добавляем описание виртуального хоста
ADD astgo.ru /etc/nginx/sites-enabled/astgo.ru
# Отключаем режим демона для Nginx (т.к. запускать будем сами)
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# Отключаем режим демона для php-fpm
RUN sed -i -e "s/;daemonize\s*=\s*yes/daemonize = no/g" /etc/php5/fpm/php-fpm.conf
# Добавляем конфиг supervisor (описание процессов, которые мы хотим видеть запущенными на этом контейнере)
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Объявляем, какие директории мы будем подключать
VOLUME ["/var/www"]
# Объявляем, какой порт этот контейнер будет транслировать
EXPOSE 80
# Запускаем supervisor
CMD ["/usr/bin/supervisord"]
# src: build/backend/supervisord.conf
[supervisord]
nodaemon=true
loglevel=debug
[program:nginx]
command=/usr/sbin/nginx
autorestart=true
[program:php5-fpm]
command=/usr/sbin/php5-fpm
autorestart=true
- FROM — указывает название образа (image), который будет взят за основу.
- ENV — устанавливает переменную среды
- RUN — запустить команду в контейнере (все команды исполняются с полными правами в пределах контейнера)
- ADD — добавить файл в контейнер
- VOLUME — указать монтируемые директории (их можно монтировать на хост машину или на другие контейнеры)
- EXPOSE — указать транслируемые порты (их можно транслировать на хост машину или на другие контейнеры)
- CMD — запустить процесс (это и будет процесс, вокруг которого построен контейнер)
С полным списком инструкций, допустимых в Dockerfile, можно обратиться к руководству.
Сборка образа
По написанной нами инструкции необходимо собрать образ. Назовем его astgo.ru/dev
docker build -t astgo.ru/dev ~/PATH_TO_DOCKERFILE_DIR
Мы увидели пошаговую сборку нашего образа. Если в процессе сборки произошли ошибки, на этом этапе их можно исправить и снова попробовать собрать образ. Проверим, что всё прошло удачно и образ появился в системе:
docker images | grep 'astgo.ru/dev'
astgo.ru/dev latest d2444af3ee61 3 minutes ago 387.2 MB
Запуск контейнера
Теперь создадим контейнер, запустив образ. Мы будем запускать образ astgo.ru/dev, свяжем 80 порт хоста с 80 портом контейнера, а также директорию /var/www хоста с /var/www контейнера. Последнее позволяет нам хранить код проекта на самой хост машине, не теряя его каждый раз, когда мы, по каким-то причинам, пересоздаем контейнер.
docker run -v /var/www:/var/www -p 80:80 -t astgo.ru/dev
Все, контейнер запущен. Мы можем убедиться в том, что он работает, посмотрев в список запущенных контейнеров:
docker ps | grep 'astgo.ru/dev'
d8429cc192c0 astgo.ru/dev:latest "/usr/bin/supervisor 20 seconds ago
Up 19 seconds 0.0.0.0:80->80/tcp reverent_fermi
Так как мы не указали имя для нового контейнера, то он получил автоматически сгенерированное имя reverent_fermi, по которому мы теперь можем к нему обращаться.
Подключение к запущенному контейнеру
Попробуем зайти в контейнер и посмотреть, как у него дела. Это может потребоваться, например, для запуска каких-то консольных команд в среде приложения.
docker exec -i -t reverent_fermi bash
root@d8429cc192c0:/#
В следующих статьях я расскажу как создать контейнер для базы данных, а также как можно упростить процесс запуска стека контейнеров.