Привет, Хабр! Я Алексей Кашавкин, инженер отдела облачных операций в G-Core Labs, последние пять лет занимаюсь администрированием OpenStack. Сегодня расскажу о костыле нестандартном использовании технологий или о том, как посадить брокеры Kafka за Nginx, используя протокол HTTP. Если у вас почему-то нет другого способа принимать сообщения — эта заметка как раз для вас.
Зачем это нужно
Проблема возникла, когда мне довелось настраивать кластер Kafka, чтобы поднять тестовый стенд для проверки концепции нового проекта. Перед созданием самого сервиса — центрального хранилища логов — мы решили провести PoC-тестирование и выяснить, как Kafka будет работать c Elasticsearch. Стенд сразу начали делать с шифрованием (SSL/TLS), но имеющиеся PEM-сертификаты Kafka принимать отказалась. Решить проблему напрямую мне запрещали регламенты, так как сертификаты курирует и приносит на наши серверы другой отдел с помощью Puppet. Пришлось делать ход конём и в таком виде пытаться добавить их в Nginx. Однако, поскольку Kafka не использует протокол HTTP для коммуникаций — REST Proxy от Confluent не в счет из-за условий лицензии, — а SSL-терминация при проксирования TCP доступна только в платной версии Nginx, использовать доступные из коробки модули для проксирования было нельзя. Как мне в результате удалось всё сделать, сохранив при этом роутинг сообщений по топикам, я описал ниже — надеюсь, эта мини-инструкция поможет кому-то в схожих условиях.
Понятно, что такое решение кому-то покажется странным, но оно может прийтись весьма кстати в legacy-проектах, где нет возможности написать своего издателя и интегрировать его в код, но есть интерфейс вывода какой-либо информации посредством HTTP, который можно задействовать.
Что делать
Метод, который я опишу достаточно лаконичен. Для него необходимо собрать два динамических модуля Nginx:
После того как сборка будет завершена, конфигурационный файл для работы модулей не вызовет трудностей в написании. Я лишь приведу простенький пример c последующими комментариями к нему, а вы уже сможете дописать его c учётом ваших особенностей:
load_module /etc/nginx/modules/ngx_http_echo_module.so;
load_module /etc/nginx/modules/ngx_http_kafka_log_module.so;
http {
kafka_log_kafka_brokers kafka1:9092,kafka2:9092,kafka3:9092;
server {
listen 443 ssl;
ssl_certificate /etc/nginx/certs/your_cert.crt;
ssl_certificate_key /etc/nginx/certs/your_cert_key.key;
if ($request_uri ~* ^/(.*)$) {
set $request_key $1;
}
location / {
kafka_log kafka:$request_key $request_body;
echo_read_request_body;
}
}
}
Разберём конфигурационный файл по порядку:
Модули:
ngx_http_echo_module.so необходим для передачи тела запроса когда не используются директивы
proxy_pass
,fastcgi_pass
,uwsgi_pass
иscgi_pass
;ngx_http_kafka_log_module.so — модуль для передачи сообщений из Nginx в топики Kafka.
kafka_log_kafka_brokers — непосредственно брокеры Kafka.
Дальше идет блок http c блоком server, в котором содержится условие для
$request_uri
. Это условие нужно, чтобы убрать“/”
из$request_uri
, так какrewrite
тут использовать не получится — он вызоветreturn
и завершит обработку до директивы echo_read_request_body. В переменной$request_key
получаем название топика без обратного слеша. Было — /topic_name, стало — topic_name.Блок location задает работу с двумя модулями:
kafka_log — отправляем в топики Kafka тело запроса;
echo_read_request_body— прочитываем тело запроса, чтобы передать в
$request_body
.
На этом всё — теперь вы можете принимать сообщения для Kafka, отправляя их на URL вида https://example.com/topic_name
P.S.: Для нашего проекта мы позже всё же переделали сертификаты и добавили их в конфигурацию Kafka.
VG_GC
Спасибо, полезно