Динамическая конфигурация/маршрутизация upstream в Nginx

Вопрос или проблема

Я экспериментировал с динамической конфигурацией upstream для nginx и не могу найти хорошее решение для реализации конфигурации upstream из стороннего источника, такого как Redis или MySQL.

Идея заключается в том, чтобы иметь единый файл конфигурации на основном сервере и проксировать запросы к различным серверам приложений на основе условий среды. Представьте себе динамические развертывания, когда у вас есть X серверов, которые запускают Y воркеров на разных портах. Например, я создаю новое приложение и разворачиваю его. Менеджер приложений выбирает сервер и затем разворачивает воркер (Ruby/PHP/Python), после чего сообщает IP:порт в центральную базу данных со статусом “включен”. В это время, когда я перехожу по данному URL, nginx должен проксировать все запросы на указанный IP:порт upstream. Весь процесс довольно похож на то, что делает heroku, за исключением того, что этот прототип не предназначен для работы в производственной среде, в основном для внутренних нужд.

Самое простое решение, которое я нашел, – это использование резолвера с DNS-сервером на Ruby. Это работает, nginx правильно получает IP-адрес, но единственная проблема в том, что вы не можете указать номер порта для этого IP.

Второе решение (которое я еще не пробовал) – это разработать что-то еще в качестве прокси-сервера, возможно, написанное на Erlang. В этом случае нам нужно использовать что-то для обслуживания статического контента.

Есть идеи, как реализовать это более гибким и стабильным способом?

П.С. Некоторые варианты для исследования:

Вот как именно упоминал Майкл Хэмптон – реализация динамического upstream с использованием Lua.

http://sosedoff.com/2012/06/11/dynamic-nginx-upstreams-with-lua-and-redis.html

Похоже, что предыдущий ответ Дэна больше соответствует тому, о чем вы думаете.

Но я написал обратный прокси на node.js, который позволит легко достичь этого:

Ответ или решение

Динамическая конфигурация upstream в Nginx: решение задачи

В современном мире разработки программного обеспечения, особенно в контексте динамической маршрутизации, Nginx обладает мощными возможностями, которые можно использовать для создания гибких архитектур. В вашем запросе озвучена необходимость динамического конфигурирования upstream-серверов для Nginx с использованием таких технологий, как Redis или MySQL. Рассмотрим несколько возможных решений, которые могут подойти для вашей задачи.

Проблема динамической конфигурации

Как упомянуто, необходимо, чтобы Nginx мог проксировать запросы на различные серверы приложений, основанные на данных, полученных из третьих источников. Ваша идея заключается в динамическом развертывании серверов, где информация о запущенных работниках (Ruby/PHP/Python) и их статусе записывается в централизованную базу данных. Это делает систему более эластичной и адаптивной к изменяющимся условиям работы.

Возможные решения

1. Использование Lua с OpenResty

Одним из самых функциональных подходов к решению вашей задачи является использование Lua в сочетании с Nginx через OpenResty. Это позволит вам динамически получать IP-адреса и порты из Redis или MySQL и настраивать upstream на лету.

Пример реализации

http {
    lua_shared_dict server_info 10m;

    server {
        location / {
            content_by_lua_block {
                local redis = require "resty.redis"
                local red = redis:new()

                red:set_timeout(1000)  -- 1 секунда

                local ok, err = red:connect("127.0.0.1", 6379)
                if not ok then
                    ngx.say("failed to connect: ", err)
                    return
                end

                local servers = red:smembers("upstream_servers") -- Получаем список серверов
                if not servers then
                    ngx.say("no servers found")
                    return
                end

                for _, server in pairs(servers) do
                    -- Пример использования ip:port
                    ngx.exec("http://" .. server)
                end
            }
        }
    }
}

Этот пример показывает, как можно интегрировать Lua в конфигурацию Nginx для динамического получения серверов из Redis.

2. Использование DNS-сервиса

Ранее вы упомянули, что использовали DNS-сервер для определения IP-адресов, однако проблема с портами остается актуальной. Одна из возможных схем – это хранить информацию о портам в Redis, а затем обрабатывать ее с помощью шаблонов. Однако это потребует дополнительной логики для определения правильного порта на клиенте.

3. Node.js как прокси

Другим подходом является использование Node.js для создания простого прокси-сервера. Этот прокси может динамически получать параметры конфигурации (включая IP и порт) и отправлять запросы к соответствующим приложениям.

Пример реализации

const http = require('http');
const redis = require('redis');

const client = redis.createClient();

const server = http.createServer((req, res) => {
    client.hgetall('upstream_servers', (err, servers) => {
        if (err) throw err;

        // Логика для выборки подходящего сервера
        const target = selectServer(servers);

        if (target) {
            const options = {
                hostname: target.ip,
                port: target.port,
                path: req.url,
                method: req.method,
                headers: req.headers,
            };
            const proxy = http.request(options, (proxyRes) => {
                // Пересылаем заголовки ответа
                res.writeHead(proxyRes.statusCode, proxyRes.headers);
                proxyRes.pipe(res, { end: true });
            });
            req.pipe(proxy, { end: true });
        } else {
            res.writeHead(502);
            res.end('Bad Gateway');
        }
    });
});

server.listen(3000);

4. Использование сторонних решений

На основании ваших исследований, стоит рассмотреть варианты использования готовых решений, таких как Node.js-based reverse proxy или другие инструменты, доступные в сообществе. Например, node-http-proxy предоставляет множество возможностей для настройки прокси.

Заключение

Решение задачи динамической маршрутизации в Nginx может требовать креативного подхода и использования внешних технологий, таких как Lua или Node.js. Выбор подхода будет зависеть от ваших специфических требований и инфраструктуры. Важно создать решение, которое будет не только эффективным, но и устойчивым к изменениям в окружении, что позволит вашему приложению масштабироваться и адаптироваться.

Оцените материал
Добавить комментарий

Капча загружается...