Архитектура
Caddy — это единый, самодостаточный, статический бинарный файл без внешних зависимостей, так как он написан на Go. Эти значения составляют важную часть видения проекта, потому что они упрощают развертывание и уменьшают трудоёмкость устранения неполадок в производственной среде.
Если нет динамической компоновки, то как можно расширить функционал? Caddy обладает оригинальной архитектурой плагинов, расширяющей его возможности далеко за пределы любого другого веб-сервера, даже тех, которые имеют внешние (динамически подключаемые) зависимости.
Наша философия «меньше движущихся частей» в конечном итоге приводит к более надёжным, управляемым и менее дорогим сайтам, особенно в масштабе. Этот полутехнический документ описывает, как мы достигаем этой цели с помощью разработки программного обеспечения.
Обзор
Caddy состоит из команды, ядра библиотеки и модулей.
Команда предоставляет интерфейс командной строки, с которым, надеемся, вы знакомы. С его помощью вы запускаете процесс из своей операционной системы. Объем кода и логики здесь минимален и содержит только необходимое для загрузки ядра в нужном пользователю способе. Мы намеренно избегаем использования флагов и переменных среды для конфигурации, за исключением случаев, когда они относятся к загрузке конфигурации.
Основная библиотека, или «ядро» Caddy, главным образом управляет конфигурацией. Она может Run() новую конфигурацию или Stop() действующую конфигурацию. Она также предоставляет различные утилиты, типы и значения для использования модулями.
Модули выполняют всё остальное. Многие модули поставляются в Caddy, которые называются стандартными модулями. Они считаются наиболее полезными для большинства пользователей.
Ядро Caddy
В основе своей Caddy просто загружает начальную конфигурацию («конфигурация») или, если таковой нет, открывает сокет для последующего приёма новой конфигурации.
Конфигурация Caddy — это JSON-документ с некоторыми полями на верхнем уровне:
{
"admin": {},
"logging": {},
"apps": {•••},
...
}
Ядро Caddy знает, как работать с некоторыми из этих полей напрямую:
-
admin, чтобы настроить API администрирования и управлять процессом -
logging, чтобы можно было выводить логи
Но другие поля верхнего уровня (например, apps) невидимы для ядра Caddy. Фактически, всё, что знает Caddy с байтами в apps, это десериализовать их в тип интерфейса, к которому можно обратиться с двумя методами:
Start()Stop()
... и всё. Оно вызывает Start() для каждого приложения при загрузке конфигурации и Stop() для каждого приложения при выгрузке конфигурации.
Когда модуль приложения запускается, он инициирует жизненный цикл модуля приложения.
Жизненный цикл модуля
Существует два типа модулей: модули хоста и модули гостя.
Модули хоста (или «родительские» модули) — это те, которые загружают другие модули.
Модули гостя (или «дочерние» модули) — это те, которые загружаются. Все модули являются модулями гостя — даже модули приложений.
Модули загружаются, снабжаются и проверяются, используются, а затем очищаются в такой последовательности:
- Загружены
- Снабжены и проверены
- Используются
- Очищены
Caddy запускает жизненный цикл модуля при загрузке конфигурации, сначала инициализируя все настроенные модули приложений. Оттуда всё идёт по цепочке, так как каждый модуль приложения доводит дело до конца.
Фаза загрузки
Загрузка модуля подразумевает десериализацию его JSON-байтов в типизированное значение в памяти. Это… в основном всё. Это просто декодирование JSON в значение.
Фаза подготовки
В этой фазе выполняется большая часть работы по настройке. Все модули получают возможность подготовиться после загрузки.
Так как все свойства из JSON-кодирования уже были декодированы, здесь требуется только дополнительная настройка. Наиболее распространённая задача во время подготовки — настройка модулей гостя. Другими словами, подготовка модуля хоста также приводит к подготовке его модулей гостя, до самого низа.
Вы можете получить представление об этом, пройдясь по структуре JSON Caddy в наших документах. В любом месте, где вы видите {•••}, могут использоваться модули гостя; и по мере перехода вы можете продолжить изучение до тех пор, пока не останется больше никаких модулей гостя.
Другие распространённые задачи подготовки — настройка внутренних значений, которые будут использоваться в течение жизненного цикла модуля, или стандартизация входов. Например, модуль http.matchers.remote_ip использует фазу подготовки для разбора значений CIDR из строковых входов, полученных из JSON. Таким образом, ему не нужно делать это при каждом HTTP-запросе, и он становится более эффективным в результате.
В фазе подготовки также может происходить валидация. Если результирующая конфигурация модуля недействительна, здесь может быть возвращено сообщение об ошибке, что прерывает весь процесс загрузки конфигурации.
Фаза использования
После подготовки и проверки модуль гостя может быть использован модулем хоста. Что именно это значит, зависит от каждого модуля хоста.
Каждый модуль имеет идентификатор, который состоит из пространства имён и имени в этом пространстве имён. Например, http.handlers.reverse_proxy — это обработчик HTTP, потому что он находится в пространстве имён http.handlers, а его имя — reverse_proxy. Все модули в пространстве имён http.handlers удовлетворяют одному и тому же интерфейсу, известному модулю хоста. Таким образом, приложение http знает, как загружать и использовать эти виды модулей.
Фаза очистки
Когда настаёт время остановки конфигурации, все модули выгружаются. Если модуль выделил какие-либо ресурсы, которые необходимо освободить, у него есть возможность сделать это на фазе очистки.
Подключение
Модуль — или любой плагин Caddy — подключается к Caddy путём добавления import для пакета модуля. Импортируя пакет, модуль регистрируется в ядре Caddy, поэтому, когда начинается процесс Caddy, он знает каждый модуль по имени. Он может даже установить соответствие между значениями модуля и именами и наоборот.
Управление конфигурацией
Изменение активной конфигурации работающего сервера (часто называемого «перезагрузкой») может быть сложным при высоком уровне конкурентности и тысячах параметров, необходимых для серверов. Caddy элегантно решает эту проблему, используя дизайн, который имеет много преимуществ:
- Без прерывания работы служб
- Возможны гранулированные изменения конфигурации
- Требуется только одна блокировка (на заднем плане)
- Все перезагрузки являются атомными, согласованными, изолированными и в основном устойчивыми («ACID»)
- Минимальное глобальное состояние
Вы можете посмотреть видео о разработке Caddy 2 здесь.
Перезагрузка конфигурации работает путём подготовки новых модулей, и если все операции пройдут успешно, старые модули очищаются. В течение короткого времени одновременно работают две конфигурации.
Каждая конфигурация связана с контекстом, который содержит все состояния модулей, поэтому большинство состояний никогда не выходит за пределы области конфигурации. Это хорошая новость для корректности, производительности и простоты!
Однако иногда действительно глобальное состояние необходимо. Например, обратный прокси может отслеживать состояние доступности своих upstream; поскольку каждый upstream существует только один, было бы плохо, если бы он забывал о них каждый раз, когда происходили незначительные изменения конфигурации. К счастью, Caddy предоставляет средства, аналогичные сборщику мусора языкового времени выполнения, для поддержания чистоты глобального состояния.
Один очевидный подход к обновлениям конфигурации онлайн — синхронизировать доступ ко всем параметрам конфигурации, даже в горячих точках. Это невероятно плохо с точки зрения производительности и сложности, особенно в масштабе, поэтому Caddy не использует этот подход.
Вместо этого конфигурации рассматриваются как неизменяемые, атомные единицы: либо всё заменяется целиком, либо ничего не меняется. Конечные точки API администрирования, которые позволяют выполнять гранулированные изменения путём перехода по структуре, изменяют только представление конфигурации в оперативной памяти, из которого генерируется и загружается новый конфигурационный документ. Этот подход имеет огромные преимущества в плане простоты, производительности и согласованности. Поскольку требуется только одна блокировка, Caddy легко обрабатывает быстрые перезагрузки.
© 2015-2025 Matthew Holt and The Caddy Authors
Licensed under the Apache License 2.0.
Caddy is a registered trademark of Stack Holdings GmbH.
https://caddyserver.com/docs/architecture