2020-10 upd: we reached the first fundraising goal and rented a server in Hetzner for development! Thank you for donating !
Использование Docker на FreeBSD
Вступление
Решения на базе Docker достаточно прочно вошли в жизнь многих IT компаний. Более того, стали прослеживаться тенденции к Docker-lock-in ситуациям, когда компании полностью строят инфраструктуру с использованием Docker. У этой технологии, как и у любой другой, есть плюсы и минусы, однако факт остается фактом - в сегодняшнем мире Docker очень популярный - даже несмотря на то, что количество сил на его поддержку и обслуживание стали превышать силы, которые необходимо потратить инженерам на решение тех задач, которые изначально должен был решать Docker, но без Docker. Инженеры больше не тратят свои силы и время на реализацию методов доставки контента - сейчас это делает Docker, однако все силы и время инженеров теперь тратятся на сопровождение Docker и Docker-изацию. Спрос на это растет и у некоторых пользователей FreeBSD, уставших от простоты/KISS решений, и часто в BSD-мире звучит один и тот же вопрос: "Когда и мы наконец сможем начать все свое время тратить на решение проблем, вызванной применением Docker, ведь это так увлекательно!" ;-)
Как результат этих потребностей, даже такие серъезные FreeBSD-based решения как FreeNAS неуклюже пытаются дать своим пользователям Docker, полностью заменив им родную реализацию jail контейнеров. Например в этом сообщении, разработчики FreeNAS объясняют причины прекращения развития jail-based окружений и аргументируют переход на Docker. В первую очередь тем, что существует огромное количество Docker-based сервисов, которые вы можете просто взять и использовать. Однако надо понимать, что подобный шаг - это больше коммерческий ход со стороны компании IXSystem, которая продает NAS appliance и которая идет на поводу потенциальных потребителей, делая попытку привлечь их внимание. Но в реальности, технически эффективность такого решения крайне невелика и возможность применения очень ограничена. Почему?
Надо сказать, что Docker концентрируется и реализован с использованием Linux-only специфичных технологий - он базируется на многих функционалах ядра Linux, таких как cgroups и iptables и запускает контейнера с Linux окружением.
Иными словами - если вы хотите запускать production на Docker - вам ничего другое не подойдет кроме Linux, поскольку официально проект разрабатывается и рассчитан на Linux экосистему. Да, вы можете запустить Docker через прослойку, как это делают на платформах Windows или MacOS, но будьте готовы потерять при этом часть функциональности, гибкости и скорости в работе такого решения. Текущая реализация запуска Docker на MacOS базируется на гипервизоре xhyve (который в свою очередь, основан на наработках bhyve), но вы никогда не будете запускать большую production инфраструктуру в докерах, работающих на MacOS или Windows, или FreeNAS - в данных ситуациях, гипервизоры (хоть они и быстрые) - это ненужная прослойка, которая ничем не помогает инфраструктуре, а наоборот, только усложняет ее. Поэтому, подобные варианты нужно рассматривать только как возможность для разработчиков и тестировщиков проверить сервис или код, обойдясь ресурсами только своей локальной рабочей машины.
Из основных ограничений это, конечно, накладные ресурсы на гипервизор. Вам необходимо предварительно сконфигурировать bhyve-окружение, выдав определенное количество ресурсов (ядер, памяти), в рамках которых вы и будете запускать Docker. Рано или поздно, вы встретите проблему исчерпания ресурсов Docker внутри bhyve (или заметите, что это плохо масштабируется на виртуальных ядрах) и вам потребуется запустить еще один bhyve-based гипервизор для Docker. В этом случае, управлять окружениями в разных гипервизорах станет нелегко. Другими словами, подобные реализации как в MacOS и FreeNAS подходят только для игр и для локальной разработки, когда вы запускаете 2-5 докеров, чтобы что-то протестировать, но не более того - и это не подходит для использования в боевых условиях и больших инсталляциях. И если MacOS и Windows - это прекрасный выбор в качестве рабочей машины, за которой вы можете заниматься разработкой и на ней же запустить Docker, мало кто предпочтет установить на свою рабочую desktop-систему NAS.
По этим причинам, мы не планируем в ближайшее время реализовывать поддержку Docker в CBSD/ClonOS: если вы делаете что-то и строите production инсталляции на базе FreeBSD, для минимизации рисков, потерь в быстродействии и гибкости, мы рекомендуем вам пользоваться родным FreeBSD стеком: это jail, bhyve и xen. Если вам нужен Docker в большом окружении - используйте Linux в качестве хостера. Если вы используете FreeBSD как Desktop-OS и вам нужно протестировать сервис или вы разрабатываете код - вы можете достаточно легко сконфигурировать аналогичную MacOS схему запуска докер - используя bhyve в качестве docker-сервера и docker-клиент на FreeBSD. И именно на такое, локальное, применение ориентирована эта статья.
Существует неофициальный порт docker-freebsd, однако с точки зрения авторов статьи, это самый плохой вариант, поскольку здесь нет никакой официальной поддержки со стороны разработчиков Docker; Docker никогда не рассчитывался на запуск контейнеров через jail, чем сильно теряет в общем функционале. Кроме этого, порт ориентирован на Linuxator - прослойку в FreeBSD, пермаментно находящаяся в любой момент времени в состоянии "частично работает", поскольку пытается эмулировать самый минимальный набор системных вызовов ядра Linux, но догнать современное развитие ядра Linux для FreeBSD linuxator очень трудно, это постоянная игра в догонялки. Поэтому, вы можете потратить очень много времени, встретив неожиданное поведение приложения внутри docker-freebsd, которое вызвано никем не тестируемой, нигде не применяемой и не ориентированной на такой метод запуска Docker окружений в наполовину реализованной эмуляцией Linux.
Поэтому создадим реализацию, аналогичную MacOS/xhyve, но на FreeBSD/bhyve.
Использование Docker с FreeBSD через bhyve
Далее по шагам написана инструкция для тех, кто хочет запускать Docker, работая в FreeBSD. Здесь не рассмотрена проблема общей файловой системы для /var/lib/docker, поскольку для локальных эксперементов, файловой системы bhyve гостя вполне достаточно. Если же вы хотите использовать несколько bhyve для Docker на одном хостере и запускаете большое количество объемных Docker-образов, мы рекомендуем вам посмотреть на Docker docker-volume-netshare плагин, с помощью которого вы можете создавать volume на CIFS/NFS, либо на проект 9p и virtio-9p в bhyve.
- 1) Нам подходит bhyve с любым удобным для вас Linux, в котором может работать Docker. Создавайте виртуальную машину с достаточным количеством ресурсов для запуска в ней Docker окружений.
Для любителей минимилизации, существует проект Boot2Docker, который представляет из себя минимальную инсталляцию Linux окружения для запуска Docker. К сожалению, на момент написания статьи этот образ не поддерживает UEFI режим, поэтому мы предпочли устанавливать Linux Ubuntu 16.04 и дальнейшие инструкции ориентированы на него.
- 2) Переведем Linux в режим работы через bridge, поскольку через него же будем конфигурировать сеть запускаемых контейнеров.
Такой режим работы нам необходим, если мы хотим работать с контейнерами напрямую из сети FreeBSD хостера, а не только внутри bhyve. Для этого, установим внутри Linux гостя пакет для работы с bridge:
% apt-get install bridge-utils
В /etc/network/interfaces перепишем конфигурацию для физического интерфейса, поместив его в br0-бридж.
В нашем случае:
- * физический интерфейс bhyve: enp0s4
- * IP адрес bhyve c Docker: 192.168.0.233
- * Сеть, в которой будем запускать Docker и которая доступна на FreeBSD хостере: 192.168.0.0/24
- * Шлюз сети: 192.168.0.1
Тогда, полная конфигурация /etc/network/interfaces может выглядеть следующим образом:
source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback iface enp0s4 inet manual allow-hotplug enp0s4 auto br0 iface br0 inet static address 192.168.0.233 netmask 255.255.255.0 gateway 192.168.0.1 dns-nameservers 8.8.8.8 dns-search example.com bridge_ports enp0s4 bridge_fd 9 bridge_hello 2 bridge_maxage 12 bridge_stp off
- 3) Перезагрузим bhyve для применения новых сетевых настроек и установим docker:
apt-get install docker.io
- 4) Через аргументы, сконфигурируем Docker на сеть с bridge по-умолчанию, с соответствующими параметрами сети.
А также, добавим через ключ -H порт TCP, через который будет взаимодействовать с демоном Docker внешний клиент ( FreeBSD в нашем случае ). Для этого, откроем файл /etc/defaults/docker и допишем строчку:
DOCKER_OPTS="-H tcp://0.0.0.0:2375 --bridge=br0 --fixed-cidr=192.168.0.0/24 --default-gateway=192.168.0.1 -H unix:///var/run/docker.sock"
- 5) На FreeBSD устанавливаем клиент Docker:
% pkg install sysutils/docker
Для текущей сессии экспортируем корректное значение DOCKER_HOST:
% setenv DOCKER_HOST tcp://192.168.0.233:2375
Либо прописываем это глобально в файлах ~/.cshrc или /etc/profile or /etc/csh.cshrc
На этом, конфигурация гипервизора с bhyve закончена. Проверяем:
На FreeBSD:
% uname -a FreeBSD gizmo.my.domain 12.0-CURRENT FreeBSD 12.0-CURRENT #5 r315987: Sun Mar 26 20:00:24 MSK 2017 root@gizmo.my.domain:/usr/obj/usr/jails/src/src_12/src/sys/CBSD amd64
Скачаем образ ubuntu:
% docker pull ubuntu Using default tag: latest latest: Pulling from library/ubuntu d54efb8db41d: Pull complete f8b845f45a87: Pull complete e8db7bf7c39f: Pull complete 9654c40e9079: Pull complete 6d9ef359eaaa: Pull complete Digest: sha256:dd7808d8792c9841d0b460122f1acf0a2dd1f56404f8d1e56298048885e45535 Status: Downloaded newer image for ubuntu:latest
Запустим контейнер из образа ubuntu:
% docker run -it ubuntu root@de8c2a012278:/# uname -a Linux de8c2a012278 4.4.0-71-generic #92-Ubuntu SMP Fri Mar 24 12:59:01 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux root@de8c2a012278:/#
Смотрим на выданный IP адрес контейнера:
% docker inspect de8c2a012278 | grep IPAddress "SecondaryIPAddresses": null, "IPAddress": "192.168.0.2", "IPAddress": "192.168.0.2",
Пигнуем:
%# ping -c2 192.168.0.2 PING 192.168.0.2 (192.168.0.2): 56 data bytes 64 bytes from 192.168.0.2: icmp_seq=0 ttl=64 time=0.055 ms 64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=0.059 ms --- 192.168.0.2 ping statistics --- 2 packets transmitted, 2 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 0.055/0.057/0.059/0.002 ms
Как мы видим, все достаточно просто и для локальной разработки этого должно хватить. Успехов!