Разработка пользовательских плагинов для APISIX с использованием Lua и ChatGPT
June 12, 2023
Одной из ключевых особенностей Apache APISIX является его расширяемость через плагины. APISIX позволяет создавать собственные пользовательские плагины для добавления дополнительных функций и более эффективного управления трафиком API. Часто для реализации новых плагинов используется язык программирования Lua, или можно использовать плагин-раннеры для разработки плагинов на предпочитаемом языке программирования. Однако APISIX лучше всего поддерживает Lua. После написания нескольких плагинов для APISIX на Lua я понял, что вам не нужно знать основы программирования на Lua или быть экспертом в этом языке, если ваш друг ChatGPT всегда с вами. Например, с моим опытом в Java и C#, я могу понять код и логику, написанные на Lua, и я уверен, что вы тоже сможете.
Эта статья проведет вас через процесс разработки нового пользовательского плагина под названием file-proxy для APISIX с использованием Lua и ChatGPT (мы используем его для написания кода на Lua). Этот плагин будет использоваться для предоставления статических файлов через API и получения файла по указанному URL.
APISIX был создан для расширения существующих функций Nginx, и Nginx предоставляет набор повторно используемых модулей Lua, которые использует APISIX.
Цели обучения
В этой статье вы узнаете следующее:
- Как разработать новый плагин file-proxy.
- Как эффективно использовать ChatGPT для генерации кода на Lua.
- Шаги для создания собственного плагина для APISIX.
Пример использования нового плагина file-proxy
Прежде чем перейти к фактической реализации плагина, давайте сначала поймем, зачем нам нужен этот плагин. На момент написания этой статьи APISIX может не предоставлять встроенного плагина для подобного случая. Именно поэтому мы собираемся создать новый. Часто мы хотим предоставить статический файл (Yaml, JSON, JavaScript, CSS или файлы изображений) через API.
Например, API-шлюз APISIX выступает в роли входной двери в вашем приложении для маршрутизации входящих запросов к нескольким конечным точкам API, это идеальное место для определения всех URL-адресов серверов, путей, параметров, описаний каждой конечной точки API и их входных и выходных данных. И вы создаете спецификации OpenAPI для документирования API. Файл OpenAPI .yaml похож на карту, которая помогает пользователям вашего API понять и взаимодействовать с ним. Указав путь к файлу openapi.yaml (где он хранится на вашем сервере) в плагине, вы можете получить и предоставить файл напрямую через ваш API-шлюз, обеспечивая единообразный интерфейс для потребителей API. Затем пользователи вашего API смогут получить доступ к файлу .yaml по указанному URL (https://example.com/openapi.yaml).
Есть и другие случаи использования, например, вы можете использовать этот плагин file-proxy в качестве простой замены Content Delivery Network (CDN). Если у вас небольшое приложение и вы не хотите использовать полноценный CDN, вы можете использовать плагин file-proxy для предоставления статических файлов из определенного места. Плагин file-proxy также можно использовать в качестве кэширующего слоя для файлов. Если у вас есть файлы, которые дорого получать или генерировать, вы можете использовать плагин для получения файла один раз, а затем предоставлять кэшированную версию для последующих запросов.
Шаги разработки плагина file-proxy
Мы будем запускать APISIX локально, и наш API-шлюз будет размещен на
http://localhost:9080. Когда разработка будет завершена, вы сможете развернуть его на своем сервере или у любого облачного провайдера. По сути, мы хотим разместить файл openapi.yaml по пути http://localhost:9080/openapi.yaml. Вы узнаете, как этого добиться.
Предварительные требования
- Перед началом работы желательно иметь базовое понимание APISIX. Знакомство с API-шлюзом и его ключевыми концепциями, такими как маршруты, upstream, Admin API, плагины. Базовое понимание протокола HTTP также будет полезным.
- Docker используется для установки контейнеризованных etcd и APISIX.
- curl используется для отправки запросов к Admin API APISIX. Вы также можете использовать такие инструменты, как Postman, для взаимодействия с API.
Понимание демонстрационного проекта и файлов
Мы будем использовать существующий демонстрационный проект file-proxy на GitHub. Он имеет структуру, похожую на существующий репозиторий Apisix docker example, только мы удалили ненужные файлы, чтобы упростить демонстрацию. Проект состоит из 3 папок, docker-compose.yml и пример файла openapi.yaml.
- docker-compose.yml определяет два контейнера: один для APISIX, а другой для etcd (который является хранилищем конфигураций для APISIX).
- Папка custom-plugins содержит реализацию плагина file-proxy на Lua. Мы рассмотрим ее в следующих разделах.
- openapi.yaml — это просто пример спецификации OpenAPI, которую мы предоставляем.
Реализация плагина file-proxy
Мы начнем с того, что спросим ChatGPT, как реализовать пользовательский плагин file-proxy для APISIX на Lua. ChatGPT генерирует руководство, почти похожее на фактическую реализацию, но ответ слишком абстрактный, и если вы будете следовать процессу, вы получите нерабочий плагин. Однако это помогает нам извлечь полезный код на Lua. Если мы знаем реальный процесс разработки плагинов, будет проще объединить оба знания на практике.

1. Создание файла Lua
Мы создаем новый пустой файл Lua в директории /custom-plugins проекта. Имя файла должно совпадать с именем нашего плагина. Например, если ваш плагин называется file-proxy, вы должны создать файл с именем file-proxy.lua.
2. Регистрация плагина в APISIX
APISIX должен знать, где находится этот файл плагина, и иметь возможность запускать его соответствующим образом. Для этого мы должны сначала определить путь к файлу, где APISIX найдет файл file-proxy.lua, добавив путь к файлу в атрибут extra_lua_path APISIX в файле config.yaml.
apisix: extra_lua_path: "/opt/?.lua" node_listen: 9080
Теперь вы можете спросить, почему путь к файлу установлен на /opt/?.lua. Потому что мы запускаем APISIX с помощью Docker. Вы можете заметить это в файле docker-compose.yml, где есть 3 тома: ./custom-plugins:/opt/apisix/plugins:ro
volumes: - ./apisix_conf/config.yaml:/usr/local/apisix/conf/config.yaml:ro - ./openapi.yaml:/usr/local/apisix/conf/openapi.yaml:ro - ./custom-plugins:/opt/apisix/plugins:ro
Это монтирует локальную директорию ./custom-plugins, где находится наш файл file-proxy.lua с реализацией пользовательского плагина, как доступный только для чтения том в контейнере Docker по пути /opt/apisix/plugins. Это позволяет добавить пользовательский плагин в APISIX во время выполнения в другой путь в Docker, который находится внутри /opt/?.lua. Аналогично, два других файла мы скопировали в папки Docker.
Следующий шаг — включение плагина в список плагинов APISIX. Это делается путем добавления имени плагина в список plugins в конфигурационном файле APISIX (config.yaml):
plugins: - file-proxy
Обратите внимание, что это действие переопределит все существующие плагины по умолчанию, указанные в config-default.yaml. Вам нужно будет вручную добавить другие плагины по их именам, если вы хотите использовать ваш пользовательский плагин в сочетании с ними.
3. Разбор кода плагина file-proxy на Lua
До этого момента мы только зарегистрировали плагин, который просто ничего не делает. Пришло время его реализовать. Логика плагина реализована в виде функций на Lua. Вы можете посмотреть, как это сделано в файле file-proxy.lua.
Давайте разберем файл file-proxy.lua, чтобы лучше понять структуру кода и поток, который поможет вам создавать новые плагины самостоятельно. Вы можете просто попросить ChatGPT объяснить код на Lua:

На самом деле, мы получили довольно хорошее объяснение кода (потому что он был частично написан ChatGPT).

Я только проведу вас по важным частям этого кода, чтобы вы не потерялись или не полагались полностью на ИИ для написания ваших плагинов.
4. Структура файла плагина
Каждый файл плагина на Lua должен иметь следующую структуру:
1. Модули: Вы импортируете необходимые модули/библиотеки, которые нам нужны для плагина.
local core = require("apisix.core") ...
2. Имя плагина: У каждого плагина есть уникальное имя, оно может совпадать с именем нашего файла Lua.
local plugin_name = "file-proxy"
3. Схема плагина: У каждого плагина есть схема плагина, где мы обычно указываем входные данные для плагина. Входные данные мы будем передавать из конфигурации маршрута APISIX, что вы увидите позже, когда будем тестировать плагин. Для плагина file-proxy плагину нужен путь к файлу для чтения файла и возврата ответа, поэтому наш параметр — это path, который имеет тип string. Вы можете понимать схему как объявление метода с параметрами в других языках программирования.
local plugin_schema = { type = "object", properties = { path = { type = "string" -- Путь к файлу, который будет предоставлен }, }, required = {"path"} -- Поле path является обязательным }
4. Определение плагина: Это действительно важная часть реализации плагина, которую мы определяем как таблицу со свойствами для version, priority, name и schema. name и schema — это имя и схема плагина, определенные ранее. version и priority используются APISIX для управления плагином. Версия обычно относится к версии, которая используется в данный момент, как версия API. Если вы публикуете и обновляете логику вашего плагина, она станет 1.1 (вы можете установить любую версию, которую пожелаете). Но вам нужно быть очень осторожным при выборе приоритета. Поле priority определяет, в каком порядке и на каком этапе ваш плагин должен быть выполнен. Например, плагин 'ip-restriction' с приоритетом 3000 будет выполнен перед плагином 'example-plugin', который имеет приоритет 0. Это связано с более высоким значением приоритета плагина 'ip-restriction'. Если вы разрабатываете свой собственный плагин, убедитесь, что вы следуете порядку плагинов, чтобы не нарушить порядок существующих плагинов. Вы можете проверить порядок существующих плагинов в файле config-default.yaml и открыть Руководство по разработке плагинов Apache APISIX, чтобы определить.
local _M = { version = 1.0, priority = 1000, name = plugin_name, schema = plugin_schema }
5. Проверка схемы: Функция check_schema на Lua используется для проверки конфигурации плагина в маршруте (вы увидите это в разделе тестирования) на соответствие схеме плагина, которую мы определили ранее.
-- Функция для проверки правильности конфигурации плагина function _M.check_schema(conf) -- Проверка конфигурации на соответствие схеме local ok, err = core.schema.check(plugin_schema, conf) -- Если проверка не прошла, возвращаем false и ошибку if not ok then return false, err end -- Если проверка прошла успешно, возвращаем true return true end
6. Логика плагина: Функция access — это основная функция, где мы можем написать основную логику плагина. Она вызывается на этапе доступа в конвейере обработки запросов Nginx, и мы управляем трафиком и пишем пользовательские инструкции. Для file-proxy нам нужно открыть файл, указанный в конфигурации плагина, прочитать его содержимое и вернуть содержимое в качестве ответа. Если файл не может быть открыт, он логирует ошибку и возвращает статус 404 Not Found. Это именно то место, где мы поручаем эту работу ChatGPT:

После того, как мы структурировали и рефакторили код, он выглядит следующим образом:
function _M.access(conf, ctx) -- Открываем файл, указанный в конфигурации local fd = io.open(conf.path, "rb") -- Если файл успешно открыт, читаем его содержимое и возвращаем его в качестве ответа if fd then local content = fd:read("*all") fd:close() ngx.header.content_length = #content ngx.say(content) ngx.exit(ngx.OK) else -- Если файл не может быть открыт, логируем ошибку и возвращаем статус 404 Not Found ngx.exit(ngx.HTTP_NOT_FOUND) core.log.error("Файл не найден: ", conf.path, ", информация об ошибке: ", err) end end
7. Логирование: Всегда предпочтительно логировать конфигурацию плагина, чтобы мы могли отлаживать и проверять, работает ли плагин так, как мы ожидали. Мы можем логировать запросы к плагину и ответы.
-- Функция, вызываемая на этапе логирования function _M.log(conf, ctx) -- Логируем конфигурацию плагина и контекст запроса core.log.warn("conf: ", core.json.encode(conf)) core.log.warn("ctx: ", core.json.encode(ctx, true)) end
Установка Apache APISIX
После того, как мы узнали, как разработать наш пользовательский плагин file-proxy и зарегистрировать его в APISIX, пришло время протестировать плагин. Вы можете легко установить проект apisix-file-proxy-plugin-demo, выполнив команду docker compose up из корневой папки проекта после того, как вы форкнете/клонируете проект.
Создание маршрута с плагином file-proxy
Чтобы использовать и протестировать наш новый плагин file-proxy, нам нужно создать маршрут в APISIX, который использует этот плагин:
curl "http://127.0.0.1:9180/apisix/admin/routes/open-api-definition" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' { "name":"OpenAPI Definition", "desc":"Маршрут для файла OpenAPI Definition", "uri":"/openapi.yaml", "plugins":{ "file-proxy":{ "path":"/usr/local/apisix/conf/openapi.yaml" } } }'
Вы можете попросить ChatGPT объяснить эту конфигурацию:

Тестирование плагина
Затем вы можете отправить запрос cURL к маршруту или открыть ссылку http://127.0.0.1:9080/openapi.yaml в вашем браузере. Ответом должно быть содержимое файла openapi.yaml по указанному URL.
curl -i http://127.0.0.1:9080/openapi.yaml
Плагин работает так, как мы ожидали. С этой конфигурацией плагина вы теперь можете получить доступ к любым файлам, используя указанный маршрут.
Итог
Разработка пользовательских плагинов для APISIX на Lua — это мощный способ расширения функциональности API-шлюза. В этом посте мы продемонстрировали, как создать плагин file-proxy, определили определение и схему плагина, проверили конфигурацию плагина и реализовали пользовательскую логику на этапах доступа и логирования в конвейере обработки запросов в APISIX. ChatGPT помог нам написать код на Lua для основной функциональности, заполнив наши пробелы в знаниях этого языка программирования. Удачного кодирования!