Создаём систему развертывания приложений с помощью Docker

2
Сегодня речь пойдёт о замечательном инструменте, а именно о контейнерной системе развертывания приложений — Docker. Разработчиков для Raspberry Pi тема касается непосредственно. Добро пожаловать под кат.
Docker logo

1. Что такое Docker

Возможно не все знакомы с системами развертывания. Поэтому я поясню.
Говоря совсем простым языком, Docker — это такая система, которая позволяет один раз настроить приложение на одной машине, сохранить его окружение (не только конфигурацию, а именно и окружение тоже) и зависимости, дальше распространять его уже настроенным в виде контейнера. Т.е. для развертывания ничего не понадобится кроме образа.
Также вы можете где-нибудь увидеть слова «Docker» и «виртуализация» в одном предложении, это не значит что Docker эмулирует процессор, память, ядро ОС и т.д., виртуализация происходит на уровне ядра т.е. все «виртуализируемые» им процессы являются реальными процессами вашей ОС.
Как вы уже догадались можно придумать массу применений. Например, вы собираетесь сделать кластер Raspberry Pi, который будет майнить биткоины (кстати, это нерентабельно в наши дни) и на каждую из 1000 имеющихся в арсенале плат вы должны установить и настроить один и тот же софт. Да, можно скомпилировать свой образ ОС, но это во-первых не так быстро, во-вторых это не так гибко (конфигурация чуть-чуть поменялась и надо пересобирать весь образ ОС).
Или, например, вы хотите распространять ваше приложение под несколько модификаций одноплатных компьютеров: Rpi1, Rpi2, O-droid, Rpi3. Везде одна и та же структура приложения, один и тот же исполняемый код, но конфигурация отличается. Вы можете создать 3,4 отдельных мануала для пользователей по установке и настройке, а потом вам это надоест и вы создадите N различных, уже настроенных конфигураций вашего приложения под самые популярные платформы и будете распространять их виде контейнеров.
Или вы просто захотели поделиться с другом, с подписчиками данного сайте вашим приложением для которого уже не нужно ставить библиотеки, пакеты и прочее. Потребуется собрать для них контейнер.
Это то что я придумал навскидку. На самом деле Docker это очень-очень мощный инструмент, применений ему можно найти неограниченное количество.
Самым большим плюсом является то, что развернуть контейнер можно на абсолютно любой другой машине где установлен Docker.

Ладно, вводная часть что-то слишком затянулась. Перейдем к делу.

2. Установка

Если вы устанавливаете систему с нуля, то возможно рациональнее воспользоваться уже готовым образом от команды Hypriot.
Большинство пользователей не будет переустанавливать систему из-за того что хотят попробовать Docker. Поэтому ниже будет приведен процесс установки на Raspbian.
0. Если у вас старая версия Raspbian, обновляемся до новой т.к. с версии Debian 8 появилась поддержка ядра Docker «из коробки»:
$ sudo sed -i 's/wheezy/jessie/' /etc/apt/sources.list
$ sudo sed -i 's/wheezy/jessie/' /etc/apt/sources.list.d/raspi.list 
$ sudo apt-get update && sudo apt-get -y upgrade # answer 'y' to upcoming questions 
$ sudo sudo apt-get -y dist-upgrade # answer 'y' to upcoming questions
$ sudo init 6
$ sudo apt-get -y autoremove
$ sudo apt-get -y purge $(dpkg -l | awk '/^rc/ { print $2 }')
$ sudo init 6

1. На официальном сайте отсутствует мануал с описанием установки на Raspberry Pi, но команда Hypriotпроделала большую работу по автоматизации установки Docker на Raspberry. Воспользуемся плодами их труда:
$ git clone https://github.com/hypriot/rpi-docker-builder.git
$ cd rpi-docker-builder
$ sudo sh build.sh
$ sudo sh run-builder.sh

После этого пакет для установки Docker вы найдете в каталоге ./dist/docker-hypriot_1.10.3-1_armhf.deb. На данный момент это последняя версия.

Ленивые могут воспользоваться готовыми пакетами от Hypriot:
$ curl -sSL http://downloads.hypriot.com/docker-hypriot_1.10.3-1_armhf.deb >/tmp/docker-hypriot_1.10.3-1_armhf.deb
$ sudo dpkg -i /tmp/docker-hypriot_1.10.3-1_armhf.deb
$ rm -f /tmp/docker-hypriot_1.10.3-1_armhf.deb
$ sudo sh -c 'usermod -aG docker $SUDO_USER'
$ sudo systemctl enable docker.service


2. Проверка работоспособности
sudo docker info

или
docker version

Выведет информацию о версии, количестве контейнеров, версии ядра, драйверов и т.д.

3. Теперь любое приложение, которое есть в виде docker-контейнера для ARM, можно устанавливать с помощью docker run на Raspberry Pi.
Следующая команда скачает и развернёт небольшой уже настроенный веб-сервер:
docker run -d -p 80:80 hypriot/rpi-busybox-httpd

Список контейнеров можно посмотреть с помощью
docker ps

3. Использование

Можно, конечно, описывать основные команды и прочее, но за этим лучше обращаться к документации.
Поэтому мы рассмотрим на примере.
Предположим мы хотим собрать контейнер в котором будет веб сервер NGinx и PHP 5.4.
В начале пишется инструкция по сборке образа. Листинг файла с комментариями приведен ниже.
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 iloverpi.ru /etc/nginx/sites-enabled/iloverpi.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"]


Далее команды 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

Полный список команд с пояснениями доступен по ссылке.

Теперь, используя эту инструкцию, собираем образ iloverpi.ru.
sudo docker build -t iloverpi.ru ~/PATH_TO_DOCKERFILE_DIR


Образ iloverpi.ru надо запустить, тем самым создав контейнер. Помимо этого требуется связать 80 порт хоста с 80 портом контейнера. Для удобства и полноты примера также свяжем /var/www хоста и /var/www контейнера.
$ sudo docker run -v /var/www:/var/www -p 80:80 -м -t iloverpi.ru

Убеждаемся что контейнер запущен:
sudo docker ps | grep 'iloverpi.ru'

Имя контейнера не было указано явно, поэтому он получил автоматическое название, с помощью которого мы можем с ним взаимодействовать.
У меня вывод предыдущей команды выглядит так:
d8429cc192c0    astgo.ru/dev:latest    "/usr/bin/supervisor 20 seconds ago  
Up 19 seconds  0.0.0.0:80->80/tcp  container23

Здесь «container23» — имя контейнера.
Для взаимодействия с командной строкой контейнера существует команда
sudo docker exec -i -t container23 bash

После этого станет доступно обычное приглашение командной строки. Это и будет консоль нашего контейнера.

Итак, мы собрали и развернули свой контейнер, научились с ним взаимодействовать.
Статья получилась длинной, но надеюсь Вам было интересно. До новых встреч.
  • 0

Комментарии (3)

0
Надеюсь, что прочитал внимательно.
Во-первых, большое спасибо, полезно и интересно.
Во-вторых, никак не могу понять, docker — не эмулятор, как тогда удается запустить ubuntu в контейнере. Создается дополнительный эмулятор x86?
В-третьих, хотя, наверное, ближе ко второму вопросу. Я не собирал контейнер из докер файла, а попытался для тестов запустить тот же образ, что и вы:
sudo docker run -it --rm ubuntu:14.04

на что получил ответ:
docker: Error response from daemon: Cannot start container 39f41dacd535b40759348852e9d31b59c69035509eacef1fcce3fb7ab6c3136a: [9] System error: exec format error.

я так понимаю дело именно в архитектуре процессора, на стационаре под дебианом все нормально работает.

З.Ы. ну и дополнения ради: docker работает по принципу слоеного пирога (каждая команда в dockerfile — это слой), для уменьшения размера образа (images), по возможности, объединяйте команды (&&).
0
1) Мне действительно приятно :)
2) Docker не виртуальная машина. Он не эмулирует железо. Виртуализация основана на разделении процессорного времени между контейнерами (процессами). Докер работает на базе Linux containers (LXC). LXC — это такая система виртуализации на уровне для запуска нескольких изолированных экземпляров операционной системы Linux на одном узле. При этом все контейнеры используют один экземпляр ядра.
3) Ошибка связана с архитектурой, да. В силу п. 2 на Rpi можно запускать только контейнеры собранные для ARM архитектуры. А на x86 десктопе не получится запустить контейнер для ARM. Это стоит учитывать когда исользуете готовые образы с Docker hub, например. В описании должно быть написано, что образ собран для ARM или Rpi.
0
supervisor в docker это масло-масляное, для этих целей лучше использовать docker-compose
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.