Docker: что там под капотом?

Kate

Administrator
Команда форума
Как работает Docker? Давайте постараемся получше понять скелет Docker, виртуализацию, и его дальнейшие перспективы.

В последнюю пару лет, Docker занял значительное место в технологическом процессе разработки. Существует множество статьей о том “Что такое Docker” и как начать с ним работу. Я нацелен на то, чтобы представить обзор того, как технология работает.

843ab2c3b9d4291963e0794674ed392a.png

Возможности Docker

Одной из наиболее важных возможностей Docker является мгновенное время запуска. Docker контейнер может быть запущен в течение миллисекунд, в то время как виртуальной машине требуется несколько минут для запуска. Docker пользуется возможностями Linux ядра для выполнения собственной магии. Так как он опирается на Linux ядро, необходимо заметить, что Docker работает только на Linux. К примеру, если вы разрабатываете на компьютере от Apple (который использует Darwin/BSD ядро), вам потребуется установить упрощённую виртуальную машину на Linux перед тем, как вы сможете использовать Docker.

Виртуализация в Docker против других подходов к виртуализации

Если вы уже знакомы с нижележащими технологиями, Docker покажется вам менее загадочным. Docker имитирует различные Linux дистрибутивы, окружения или установочные процессы вместо их запуска. Вы знали, что если бы вы захотели, то могли бы взять Ubuntu дистрибутив и устанавливать/удалять в нём ПО (программное обеспечение) до тех пор, пока дистрибутив не станет похож (внешне и по наполнению) на Gentoo? В конце концов, их будет объединять только использование Linux ядра. Различные Linux дистрибутивы отличаются пользовательским/пакетным менеджерами, работающими поверх Linux ядра!

Давайте вернёмся на предыдущий шаг. Операционная система — это ПО, которое работает на железе. Изначально операционную систему называли “диспетчером”, это слово является фантастической аналогией относительно того, чем операционная система занимается. Подумайте о представлении операционной системы как судьи или администратора, наблюдающего за программами. Операционная система позволяет другим программам работать, пока она составляет для них расписание и координирует их запуск. Помните, когда компьютеры могли делать только одну вещь за раз? В действительности, это всё ещё правда, это операционная система, которая переключает контекст туда-сюда очень быстро, делая вид, что несколько программ работают в одно и тоже время.

Что такое виртуализация?

74acb66e2468f8e77a6a9ebca04c8804.png

Давайте поговорим о виртуализации работы процессора. Процессор запускает машинный код (скомпилированный ассемблер код), когда запускает программу. Ассемблер и машинные языки должны предоставить процессору соответствующий набор инструкций, так процессор Intel запустит машинный язык для x86 архитектуры в то время, как ваш iPhone запустит машинный язык для ARM архитектуры.

Что случится, если мы запустим программу для x86 на ARM процессоре? Вот упрощённый пример:

390a68f96aab6031e16570161348d1e2.png

Операция для x86 sti или установка прерывающего флага (в hex, fb) будет не распознана процессором на ARM. Таким будет обычный результат при аварийном завершении программы.

e28ae80c0060257e723be50dee23ced6.png

Однако, процессор может отлавливать определённые ошибки, это значит если вы видите что-то типа этого, то выбросите эту ошибку выше. В таком случае процессор отловит её и отправит соответствующую инструкцию менеджеру виртуальной машины (VMM – Virtual Machine Manager).

c877e786b51b58bddee57279ec02fd5d.png

Теперь менеджер виртуальной машины знает, как эмулировать инструкцию sti, давайте продолжим дальше по программе.

Полная виртуализация: QEMU

QEMU (быстрый эмулятор) это ПО, которое выполняет виртуализацию оборудования (или попросту железа). QEMU эмулирует работу ЦП (центральный процессор) при помощи динамического бинарного перевода и предоставляет различные модели устройств, позволяя запускать их на исходных образах операционных систем. Недостатком является то, что это работает очень медленно. Инструкции из одного набора необходимо сопоставить с другим, при переводе инструкция для x86 sti (установка прерывающего флага) должна будет быть сопоставлена с множеством разных инструкций для ARM.

Виртуализация с аппаратной поддержкой (Технология виртуализации от Intel)

Операционные системы запускаются в привилегированном режиме для доступа к драйверам. У ядра Linux есть специальные инструкции, запуск которых предполагается в привилегированном режиме. Если бы эти специализированные инструкции запускались с уровнем доступа, как у приложений, то данные инструкции падали бы с ошибкой. Но это очень медленный процесс. Основная идея заключается в том, чтобы перехватывать исполняющиеся вызовы и отсылать их системе виртуализации. Цель этого выполнять большинство запросов на реальной аппаратуре (нативно) и перехватывать передавая менеджеру виртуальной машины только небольшое количество вызов.

Виртуализация с аппаратной поддержкой впервые появилась у IBM System/370 в 1972. Если вы используете ЦП Intel/AMD x86 купленный в течение последних 10 лет, у вас имеется эта технология, так как она была добавлена в 2005.

Паравиртуализация: Xen гипервизор

Приложения часто будут обращаться к ОС с такими запросами, как прослушивание сокета сети или прочтение файла. Это привилегированные системные вызовы, которые может обработать только ядро. Ядро, в свою очередь, воспользуется драйвером для того, чтобы выполнить запрос системы и вернуть информацию обратно приложению.

Xen гипервизор это как операционная система операционных систем. Он использует архитектуру миниядра и взаимодействует с гостями (такими как Ubuntu или Debian Linux) при помощи dom0 (или Xen гипервизор) через “гипервызов” (против системного вызова) использующий БИП (бинарный интерфейс приложения), в отличие от API. Так приложение, запускающееся внутри виртуальной Ubuntu, сделает запрос системе на открытие и прочтение файла, который потом будет послан Xen, как гипервызов. Xen затем использует драйвер для открытия и прочтения файла с жёсткого диска. Ниже представлен упрощённый пример:

Отличия ОС при использовании ядра и микроядра
Отличия ОС при использовании ядра и микроядра
Виртуализация на уровне другой операционной системы: FreeBSD Jails

8d1a3ee4ab304fa6f1ddc857c083ba2f.png

Идейно, FreeBSD Jails очень похожи на Docker. FreeBSD Jails были впервые представлены в 2000 году, задолго до того, как были выпущены LXC контейнеров (2008) или Docker (2013).

FreeBSD Jails часть ПО BSD для пользовательского пространства (в оригинале “userland software”), которое запускается в начале системного вызова chroot(2). Эти две технологии очень похожи, но FreeBSD Jails может использоваться только в FreeBSD, и таким образом, она даже близко так не популярна, как Docker.

Так как администрирование системы сложная задача, было разработано множество инструментов для того, чтобы упростить жизнь администратору. Эти инструменты часто улучшают процесс установки, настройки и обслуживания систем. Один из инструментов, который может быть использован для улучшения безопасности FreeBSD это jails (с английского “клетка”). Jails стали доступны с FreeBSD 4.X, и они продолжают улучшаться в своей полезности, производительности, надёжности и безопасности. – Руководство по FreeBSD, Глава 14. Jails

Инструменты & Терминология

Для Docker существует несколько инструментов.

Клиент Docker - это docker, которому будет отдаваться большинство ваших команд.

Если вы используете OS X в качестве основной системы, так же будет docker-machine. Это обёртка для OS X системы, помогающая настроить упрощённую виртуальную машину на Linux для выполнения docker команд в ней.

А Docker image (образ) это артефакт, созданный при работе docker build команды для предоставленного Dockerfile, который является скриптом, использующемся для создания docker образа. Артефакты или Docker images, могут храниться в частных или публичных репозиториях, называемых реестрами. Некоторые общеизвестные реестры Docker Hub, quay.io, AWS ECR.

Docker контейнер это среда выполнения или исполняемый экземпляр Dockerfile. Это работающая версия образа, и он записан/запущен в вашей файловой системе. Аналогией может быть: Docker образ это .jar файл, в то время как Docker контейнер - запущенный процесс этого .jar.

Технология

8012f13fffd8ed163f4f88182c20f524.png

cgroups & namespaces

Опорой технологии Docker является cgroups (сокращение от контрольных групп) и пространство имён ядра, обе эти функции уже содержатся в Linux ядре. При помощи cgroups, ОС Linux может с лёгкостью управлять и отслеживать выделение ресурсов для выбранного процесса и устанавливать ограничения на использование таких ресурсов, как ЦП, память и скорость в сети. Ядро сейчас может управлять максимально возможным количеством ресурсов, которые получает процесс. Это позволяет Docker engine использовать только 50% памяти компьютера, процессорного времени или скорости подключения к сети для запуска Docker контейнера.

Пространство имён очень полезно при изоляции групп процессов друг от друга. В Linux имеется шесть стандартных пространств имён: mnt, IPC, net, usr, pid и uts. У каждого контейнера будет своё пространство имён и процессы, запущенные внутри этого пространства имён, и эти контейнеры не будут иметь доступа к чему-либо, что находится снаружи их пространства имён.

Docker контейнеры так же изолированы от сети (через libnetwork), что позволяет разделять виртуальные интерфейсы и IP адресацию между контейнерами.

Файловая система Union

Docker использует файловую систему Union для создания и разделения на слои Docker образы. Это значит, что все образы надстраиваются над исходным образом, затем все действия добавляются к исходному образу. Например, run apt install curl создаёт новый образ. Под капотом, Docker позволяет файлам и каталогам раздельных файловых систем, называемых ветками, наложиться друг на друга, формируя единую связанную файловую систему. Когда содержимое ветки имеет один и тот же каталог, содержимое каталогов объединяется в один.

При построении образа, Docker сохранит эти ветки в своём кэше. Выгода в том, что если Docker обнаружит команду, которая создаёт ветку или слой, который уже существует в кэше, он заново использует соответствующую ветку, а не ту команду, которая приведёт к добавлению в кэш уже существующих данных. Это называется кэшированием слоёв докером (docker layer caching).

libcontainer / runC

Библиотека Cи, которая предоставляет нижележащий функционал Docker называется libcontainer, или так же известная как runC. При каждом запуске, каждый контейнер получает свою корневую файловую систему, /tmp/docker/[uuid]/, и низлежащая основная ОС не позволяет процессу покинуть этот каталог, так же называемый chroot jail. Один из переменных процессов, которые происходят при запуске ОС обращается к текущему рабочему каталогу. Тогда при помощи сhroot jail, ОС предотвращает этот стартовавший процесс от доступа к родительскому каталогу, такому как ../ .

Притворяясь им: udocker

Одним из недостатков Docker является то, что Docker engine требует доступ к максимальным привилегиям (root) для запуска контейнеров. Введём в рассказ udocker. Это проект с открытым исходным кодом, и он предоставляет такой же основной функционал что и у Docker engine, но не требует максимального уровня доступа.

Это работает так как создаётся chroot-подобное окружение поверх выделенного контейнера и используются реализации различных стратегий для имитации выполнения работы chroot с правами доступа пользователя. Одно из выполняющихся окружений вы можете использовать это runC, такое же используется самим Docker.

Например, представьте следующий скрипт:

#!/usr/bin/env bash
set -eou pipefail

if [[ ! -d ~/bin ]]; mkdir ~/bin; fi
PATH="${PATH}:~/bin"

curl \
https://raw.githubusercontent.com/skilbjo/lambdas/master/iris/resources/udocker \
>./udocker \
&& chmod 744 udocker \
&& mv ./udocker ~/bin

udocker install
udocker pull quay.io/skilbjo/iris:x86-debian # pull down image from docker repo
udocker create --name=_ quay.io/skilbjo/iris:x86 # 'create' a container / unpack the image
udocker setup --execmode=F1 _ # set the execution engine
udocker run \
--nosysdirs \
_ \
/bin/bash -c 'echo "hello from inside udocker!"

Он вернёт

Warning: running as uid 0 is not supported by this engine
Warning: non-existing user will be created

##############################################################################
# #
# STARTING e7818ced-28b7-3bb5-9bdf-c8586cf6ae3c #
# #
##############################################################################
executing: bash
hello from inside udocker!
done!

Данный скрипт запускает Docker образ и без установки Docker, и без необходимости получать права администратора.

cc0683673369fc6b8ec5da29d589c832.png

Будущее: Unikernel

Вернёмся на предыдущий шаг: большое количество интернет-трафика проходит через ЦОДы AWS, на виртуальных машинах известных как EC2 (акроним для Elastic Computer Cloud. Это предоставляемые виртуальные/физические машины с заранее созданными образами операционных систем). Множество веб сервисов и веб приложений, которые мы используем каждый день запущены на этих EC2 машинах внутри Docker контейнеров. В конечном итоге, получается множество различных промежуточных слоёв перед тем, как приложение может получить доступ к физическому процессору.

Идея, стоящая за unikernels это распотрошить ядро и удалить ненужное ПО (так как ОС предназначена для того, чтобы быть универсальной и делать большое количество различных вещей), чтобы иметь возможность просто запускать приложение с минимальным количеством модулей ядра и драйверов, необходимых для работы приложения. Если приложению не нужно подключение к сети, тогда нет потребности и в драйверах сети или части кода имеющегося в ядре.

Три года тому назад, Docker приобрёл компанию с названием Unikernel Systems для потенциальной реализации этого концепта, так как одна из целей Docker это предоставление высокачественных инструментов и документации для разработки ПО на их платформе.

Одним из невероятных преимуществ Docker является предоставление простой в использовании абстракции виртуализации, которя не влияет на производительность (поскольку технология виртуализации на самом деле не виртуализация). Теперь кажется, что Docker пытается получить такие же понятные для разработчиков инструменты, чтобы заставить разрабатываемые в Docker приложения работать быстрее, чем они могли бы работать в реальных ОС.

Изоляция и специализация с unikernels


Изоляция и специализация с unikernels

 
Сверху