В Kelda мы строим Blimp, версию Docker Compose, которая работает в облаке. Наша цель состоит в том, чтобы повысить производительность разработки, предоставив разработчикам альтернативу увязанности их локальных систем множеством контейнеров Docker, жаждущих ресурсов.
Мы приложили много инженерных усилий, чтобы поддержать все поля Docker Compose, обычно используемые во время локальной разработки, такие как тома
, порты
и сборка
Анкет В этом посте я немного расскажу о том, что мы получили от опыта, поскольку это связано с Docker Compose’s сборка
функциональность.
services: service: build: .
Когда у сервиса есть сборка
Field, Blimp строит ваши изображения локально и подталкивает их к облаку, чтобы их можно было извлечь в среду разработки. Этот толчок может быть разочаровывающим медленным, особенно в домашних сетях. Ожидание 30 минут для загрузки изображения, прежде чем начать развиваться, было просто неприемлемо для нас.
Чтобы быть справедливым, у Docker уже есть некоторые оптимизации изображений, но он не сделал именно то, что мы хотели от коробки. Итак, мы решили оптимизировать процесс толчка. Чтобы достичь этого, нам пришлось глубоко погрузиться в API изображения Docker.
В этом посте я расскажу:
- Что именно происходит, когда вы делаете
Docker push
- Как мы использовали это, чтобы создать нашу функцию предварительного толчка и уменьшить время толчки изображения на 90%.
Изображения — это слои
Прежде чем погрузиться в API Push, вам сначала нужно понять, что такое изображение Docker.
Разработчики обычно думают о изображениях Docker, таких как изображения операционной системы или ISO — статический снимок файловой системы, которая представляет контейнер. На самом деле, изображения Docker немного сложнее, чем это.
Изображение Docker состоит из слои файловых систем. Проще говоря, каждая линия в Dockerfile может рассматриваться как слой, а сумма всех слоев, которые определяет Dockerfile, является полученным изображением.
Например, в следующем, От Python
говорит Docker заложить основу нашего изображения с существующими слоями Python. Точно так же Копия Анкет
Создает новый слой, который содержит все файлы в Анкет
(то есть текущий рабочий каталог, который называется контекстом
FROM python COPY . . CMD python app.py
Базовое изображение Python — 934MB Анкет Предполагая, что пользователь копирует в 2 МБ файлов, базовое изображение будет составлять 99% полученного изображения!
Это дало нам действительно интересную возможность оптимизировать. Почему мы должны тратить драгоценную пропускную способность пользователя на то, что все это изображение, если часто подавляющее большинство его уже доступно из общественных источников?
Наше решение состоит в том, чтобы пользователи только выдвигали биты изображения, которые являются уникальными для их сборки, а затем автоматически извлекать остальные непосредственно из реестра базового изображения (например, Dockerhub), который имеет большую полосу пропускания.
Возвращая его к примеру Python выше, мы хотим сделать так, чтобы Python
Слои не загружаются по сети пользователя. Вместо этого наши серверы будут «предварительно подталкивать» слои с наших серверов с высокой пропускной способностью. Тогда пользователь Docker push
Просто нужно подтолкнуть слой для Копия Анкет
.
Хорошей новостью для нас было то, что из коробки Docker только толкает слои, которых еще не существует в реестре. Каждый слой имеет Digest
, который представляет содержимое слоя. Эти идентификаторы дайджеста используются перед тем, как настаивать на выяснении, есть ли у реестра этот слой — если это так, то клиент не удосужился подтолкнуть содержимое слоя.
Но нам все еще приходилось разработать способ предварительного пропадения базовых слоев изображения в реестре, чтобы Docker Push API повторно использовал их.
Docker Push API
Docker толкает изображения в две части: сначала он загружает слои описано выше. Затем, как только все слои загружаются, он загружает Подписанный манифест , который ссылается на слои и имеет несколько дополнительных метаданных.
Простое кэширование слоя
Каждая загрузка слоя начинается с Голова
Запросите, чтобы проверить, существует ли слой в реестре.
Если уровень уже существует в реестре, то реестр отвечает 200 ОК
Ответ, и клиент Docker не беспокоит его снова. В этих ситуациях Docker push
показывает следующий выход:
6b73f8ddd865: Layer already exists
Если слой не существует, тогда реестр отвечает 202 Принято
вместе с URL -адресом, который следует использовать для загрузки слоя. Затем клиент загружает изображение в куски через ПЛАСТЫРЬ
запросы или непосредственно через один Положить
запрос.
Эта проверка слоя работает только тогда, когда рассматриваемые слои существуют в том же репозитории, что и изображение, которое нажимается. Так БПИПП/БАКЕНД: 1
и БПИП/БАКЕНД: 2
может поделиться слоями, но БПИПП/БАКЕНД: 1
Не могу делиться слоями с БИЛЬМ/Еще одно изображение: 1
(Не используя другой API, который я сейчас опишу).
Крестные репозитории
Возможно, вы видели следующий выход при запуске Docker push
до. Этот выход означает, что толчок использует Крестные репозитории Mounts , что является классной особенностью для кэширования слоев по всему несколько картинки.
e1c75a5e0bfa: Mounted from library/ubuntu
Эта функция была введена в Docker Registry v2.3.0 Анкет Крестные хранилища репозитория позволяют клиентам сообщить реестру, который они знают о другом изображении в реестре, который может делиться одним и тем же уровнем, и что реестр должен попытаться использовать слой с этого изображения, а не проходить через полную загрузку.
Когда Docker получает этот запрос, он сначала гарантирует, что клиент имеет доступ к этому другому репозиторию. Если у клиента есть доступ, а слои совпадают, реестр отправляет обратно 201 создан
отклик. В противном случае он отправляет 202 Принято
Ответ, и клиент проходит процесс полной загрузки, описанный выше.
Оптимизация дирижабля
Если вы используете пользовательское изображение Docker для разработки, Blimp автоматически строит и нажимает изображение при запуске песочницы. Изображение для каждой службы подталкивается к blimp-registry.kelda.io/
где есть уникальный идентификатор для вашей песочницы, и это хэш, чтобы убедиться, что мы всегда запускаем последнюю версию вашего изображения.
В качестве напоминания, наша цель для изучения всего этого — сделать так, чтобы, когда вы продвигаете это изображение, вам нужно только выдвигать «уникальные» слои, которые нельзя извлечь из более эффективных источников.
Первоначальный дизайн
Сначала мы хотели использовать Крестные репозитории Mounts Анкет Это позволило бы всем нашим пользователям поделиться одними и теми же базовыми изображениями, поэтому нам пришлось бы только нажать базовое изображение для очень первый пользователь это ссылается на это. Кроме того, это заставило нас создать частные кэши изображения для команд, чтобы они могли поделиться слоями со своих Dockerfile, кроме базового изображения.
Мы надеялись сделать что -то вроде этого:
- Проанализируйте изображение Dockerfile, чтобы выяснить, каково его базовое изображение.
- Отправьте запрос нашему серверу, чтобы подтолкнуть это базовое изображение в реестр с именем
blimp-registry.kelda.io/public/
Анкет: - Отметьте базовое изображение локально с помощью
blimp-registry.kelda.io/public/
Так что Docker предоставил бы его как крепление репозитория.: - Нажмите изображение
Docker push
Анкет
К сожалению, шаг 3 на самом деле не заставил Docker предоставить предварительно проталкиваемое базовое изображение в качестве крепления репозитория. Docker только обновляет свой список изображений, используемых для крепления репозитория Cross на В первый раз слой выдвигается или вытянут Анкет
Мы подумали о том, чтобы предоставить пользователям доступ к общественному репо, но мы считали это слишком небезопасным. Мы также считали отказаться Docker push
полностью в пользу Go-ContainerRegistry , но это повлекло за собой внесение значительных изменений в Go-ContainerRegistry
Чтобы показать обновления Push Push.
Итак, мы вернулись на чертежную доску.
Пересмотренный дизайн
Отказавшись от приколов репозитория Cross, мы спросили: зачем беспокоиться о прикреплениях репозитория, когда мы могли бы просто подтолкнуть непосредственно к репозиторию пользователя?
Хотя нашим серверам придется протолкнуть копию базового изображения для каждый пользователь Это все еще гораздо более эффективно, чем заставить пользователя вытащить его непосредственно с своего ноутбука, так как пропускная способность между нашими серверами и реестрами намного выше.
В конечном счете, это то, на чем мы остановились. Репозиторий для каждой службы ( blimp-registry.kelda.io/
) всегда имеет основание
Обвяжите, что наши серверы нажимают на базовое изображение. Затем реестр автоматически ссылается на него во время обычного API, изложенного выше, когда пользователь выжимает свое изображение — никаких непристойных манипуляций с состоянием Докера не требуется.
Собрать все это вместе, это то, что происходит, когда Blimp нажимает на локально построенное изображение:
- Blimp Cli анализирует ссылку на базовое изображение из Dockerfile изображения.
- CLI Blimp сообщает серверам рисков, чтобы подтолкнуть базовое изображение к
blimp-registry.kelda.io/
Анкет/ :base - Blimp CLI создает изображение, используя то же базовое изображение.
- Blimp CLI подталкивает полное изображение к
blimp-registry.kelda.io/
Анкет/ : - Докер проходит через слои один за другим и толкает их. Если слой из базового изображения, реестр замечает и инструктирует CLI пропустить толчок.
- Для слоев, не в базовом изображении, Docker выполняет полный процесс загрузки.
Вывод
В Blimp мы хотим, чтобы перенести вашу среду разработки в облако как можно более бесперебойно. Один из наших Принципы дизайна заключается в том, что этот шаг должен использовать ту же конфигурацию и не требовать каких -либо изменений в вашем рабочем процессе. Хотя мы могли бы, чтобы пользователи работали вокруг медлительности путем предварительного построения и подталкивания изображений в общий общественный репозиторий, это нарушит наши цели дизайна. Создание этой функции было забавным глубоким погружением в Docker Instronals, и большой шаг к тому, чтобы процесс адаптации, чтобы безрассурить.
Рекомендации
Посмотрите, как быстро это сами! Попробуйте пример
Узнайте больше о Docker Internals — Посмотрите, как хранятся учетные данные реестра.
Прочитайте спецификацию для API Docker Push
По: Кристофер Купер
Оригинал: «https://dev.to/ethanjjackson/how-we-cut-our-docker-push-time-by-90-4o69»