Докер без Докера

ДокербезДокера

Мы Fly.io. Мы берем образы контейнеров и запускаем их на нашем оборудовании по всему миру. Это довольно красиво, и вы должны это проверить ; с уже работающим контейнером Docker, вы можете начать работать на Fly в минут.

Несмотря на то, что большинство наших пользователей поставляют нам программное обеспечение в виде контейнеров Docker, мы не используем Docker для их запуска. Docker – это здорово, но мы многопользовательские с высокой плотностью, и, несмотря на успехи, изоляция Docker недостаточно сильна для этого. Поэтому вместо этого мы преобразовываем образы контейнеров в микро-виртуальные машины Firecracker .

Давайте проясним это.

Что такое образ OCI?

Они делают они стараются сделать его намного более сложным, но образы OCI – OCI – это стандартизированный формат контейнера, используемый Docker – довольно простые. Образ OCI – это просто стопка архивов.

Резервное копирование: большинство людей создают образы из файлов Docker. Полезно рассматривать файл Dockerfile как серию команд оболочки, каждая из которых создает архивный файл; мы называем их «слоями». Чтобы регидратировать контейнер из его образа, мы просто запускаем первый слой и распаковываем один поверх следующего.

Вы можете написать сценарий оболочки, чтобы вытащить контейнер Docker из его реестр, и это может прояснить. Начнем с некоторой конфигурации; по умолчанию мы берем базовое изображение для голанг :

  изображение знак равно ) "  $ {  1  : -   голанг  }   "  register_url   знак равно  'https://registry-1.docker.io'   auth_url   знак равно  'https://auth.docker.io'   svc_url  ( знак равно  'registry.docker.io'   

Нам нужно пройти аутентификацию, чтобы вытащить общедоступные образы из реестра Docker – это скучно но относится к следующему разделу – и это легко:

   функция  auth_token  { локон  - fsSL   "  $ {  auth_url  }   / токен? service =   $ {  svc_url   } &сфера = репозиторий: библиотека /   $ { изображение}  : тянуть » |  jq 
 - необработанный вывод  .token }   

Этот токен позволит нам получить «манифест» для контейнера. , который является индексом JSON частей контейнера.

   функция  манифест  {  токен   знак равно  "  $ 1   " изображение знак равно  "  $ 2   "  дайджест  знак равно   "  $ {  3   :-последний 
}  
 " локон  - fsSL      -H   »Авторизация: предъявитель   токен $   "     - H   'Принять: utility / vnd.docker.distribution.m  anifest.record.v2 + json '     - H   'Принять: utility / vnd.docker.distribution.manifest.v1 + json'     -ЧАС  'Принять: utility / vnd.docker.distribution.manifest.v2 + json'      "  $ {  registry_url  }   / v2 / библиотека /   $ {изображение }   / манифесты /   $ {  дайджест  }   " }   

Первый запрос мы make дает нам «список манифестов», который дает нам указатели на изображения для каждой поддерживаемой архитектуры:

   «манифестирует»  :     .digest ' }   токен   знак равно  $ ( auth_token  "  $ изображение   " )   amd 071  ( знак равно  $ ( linux_version 
 $ ( манифест  " 
 токен $   "  "  $ изображение   " ))   мф  знак равно   $ ( манифест  "  токен $   "  "  $ изображение   "  "  $ amd 071   " )  язнак равно  0  для  L  в   $ ( слои  "  $ mf   " )  ;  делать  blob  "  токен $   "  "  $ изображение   "  "  $ L   " "слой_  $ {я 
}  . tgz "  i  знак равно  
 $ (( я 
 +   1  
))  Выполнено  

Распакуйте архивы по порядку, и вы получите структуру файловой системы. контейнер ожидает запуска. Вытяните «config» JSON, и у вас есть точка входа для запуска контейнера; я думаю, вы могли бы вытащить и запустить контейнер Docker, используя только сценарий оболочки, который я, вероятно, 1, 04 ого человека, на которого нужно указать . В любом случае, вот и все .

Vitally important system diagram

Вы, вероятно, придерживаетесь одного из двух мнений по этому поводу: (1) что это чрезвычайно Unixy и, следовательно, превосходный, или (2) то, что он чрезвычайно Unixy и, следовательно, ужасающий.

Unix tar проблематично. Подводя итоги Алекса Сарай : tar недостаточно стандартизирован, может быть непредсказуемым и плохо справляется с произвольный доступ и инкрементальные обновления. Небольшие изменения в больших файлах между слоями бессмысленно дублируют эти файлы; плохая работа tar делает управление хранилищем контейнеров одна из причин, по которой люди тратят так много времени на оптимизацию размеров образов контейнеров.

Еще одна интересная деталь заключается в том, что контейнеры OCI разделяют безопасность с репозиториями git: легко случайно встроить секрет в публичный контейнер, а затем непреднамеренно скрыть его с помощью обновления на более позднем изображении.

Мы придерживаемся третьего взгляда на изображения OCI: они ужасны, и это освобождает. Они неплохо работают на практике! Посмотри, как далеко они нас завели! Расслабьтесь и сделайте более дрянный дизайн; они все, что вам, вероятно, нужно.

Кстати говоря:

Многопользовательские репозитории

Вернуться на Fly.io. Наши пользователи должны предоставить нам контейнеры OCI, чтобы мы могли их распаковать и запустить. Для этого есть стандартные инструменты Docker, и мы их используем: мы размещаем Реестр Docker , который загружают наши пользователи.

Запуск экземпляра реестра Docker очень прост. Вы можете сделать это прямо сейчас; docker pull registry && docker run registry . Но наши потребности немного сложнее, чем стандартный реестр Docker: нам нужна мультитенантность и авторизация, которая распространяется на наш API. Это оказалось несложно, и мы можем помочь вам пройти через это.

Важно знать сразу: наши пользователи запускают Fly.io с помощью утилиты командной строки под названием flyctl . flyctl - это программа Go (с общедоступный исходный код ), работающий в Linux, macOS , и Home windows. При работе в Go в контейнерной среде хорошо то, что вся экосистема построена на одном языке, и вы можете быстро заставить множество вещей работать, просто импортировав их. Так, например, мы можем управлять нашими клиентами репозитория Docker с помощью flyctl просто позвонив в клиентскую библиотеку Docker.

Если вы создаете свою собственную платформу и у вас есть средства, я настоятельно рекомендую использовать метод CLI-first, который мы использовали . Это такой выбор. flyctl упростил добавление новых функций , например базы данных , частные сети , томов , а наши безумная система доступа SSH .

На стороне сервера мы начали с простого: мы запустили экземпляр стандартного реестра Docker с авторизирующим прокси перед ним. flyctl управляет токеном-носителем и использует Docker API-интерфейсы для запуска запросов Docker, которые передают этот токен; токен авторизует репозиторий на стороне сервера, используя вызовы нашего API.

То, что мы делаем сейчас, не намного сложнее этого. Вместо того, чтобы запускать обычный реестр Docker, мы создали собственный сервер репозитория. Как и в случае с клиентом, мы получаем реализацию реестра Docker, просто импортировав код реестра Docker в качестве зависимости Go.

Мы извлекли и упростили часть кода Go, который мы использовали для создания этого здесь на всякий случай, если кто-то захочет поэкспериментировать с той же идеей. Это не наш производственный код (в частности, вся фактическая аутентификация вырвана), но он недалеко, и, как видите, в этом нет ничего особенного.

Наш настраиваемый сервер архитектурно не отличается от прежней системы реестра / прокси-сервера. Мы обертываем обработчики API реестра Docker с помощью промежуточного программного обеспечения авторизатора, которое проверяет токены, ссылки и перезаписывает имена репозиториев. Есть несколько очень незначительных ошибок:

Фигуры на доске:

Что нам нужно d Теперь нужно расположить эти части так, чтобы мы могли запускать контейнеры как виртуальные машины Firecracker.

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

Между тем, Firecracker хочет набор блочных устройств, которые Linux будет монтировать при загрузке.

В Linux есть простой способ взять дерево каталогов и превратить его в блочное устройство: создать файл - с поддержкой устройство цикла и скопируйте в него дерево каталогов. Так мы и поступали. Когда наш оркестратор попросил загрузить виртуальную машину на одном из наших серверов, мы бы:

  • Вытяните соответствующий контейнер из реестра.

  • Leave a comment

    Your email address will not be published. Required fields are marked *