• Docker: создание и запуск контейнера

    Docker

    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:/# 

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