Ход конём: как принимать сообщения в Kafka через Nginx

Привет, Хабр! Я Алексей Кашавкин, инженер отдела облачных операций в G-Core Labs, последние пять лет занимаюсь администрированием OpenStack. Сегодня расскажу о костыле нестандартном использовании технологий или о том, как посадить брокеры Kafka за Nginx. Если у вас почему-то нет другого способа принимать сообщения — эта заметка как раз для вас.

psfxslo7i4urpeeyfqedaq6i4xa.jpeg

Зачем это нужно

Проблема возникла, когда мне довелось настраивать кластер Kafka, чтобы поднять тестовый стенд для проверки концепции нового проекта. Перед созданием самого сервиса — центрального хранилища логов — мы решили провести PoC-тестирование и выяснить, как Kafka будет работать c Elasticsearch. Стенд сразу начали делать с шифрованием (SSL/TLS), но имеющиеся PEM-сертификаты Kafka принимать отказалась. Решить проблему напрямую мне запрещали регламенты, так как сертификаты курирует и приносит на наши серверы другой отдел с помощью Puppet. Пришлось делать ход конём и в таком виде пытаться добавить их в Nginx. Однако, оказалось, что проксировать в Kafka из коробки веб-сервер не может, поэтому к нему пришлось прикручивать модули. Как мне удалось это сделать я описал ниже — надеюсь, эта мини-инструкция поможет кому-то в схожих условиях.

Понятно, что такое решение кому-то покажется странным, но оно может прийтись весьма кстати в legacy-проектах, где нет возможности написать своего издателя и интегрировать его в код, но есть интерфейс вывода какой-либо информации посредством HTTP, который можно задействовать.

Что делать

Метод, который я опишу достаточно лаконичен. Для него необходимо собрать два динамических модуля Nginx:

  1. echo

  2. kafka-log

После того как сборка будет завершена, конфигурационный файл для работы модулей не вызовет трудностей в написании. Я лишь приведу простенький пример 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;
    }
  }
}

Разберём конфигурационный файл по порядку:

  1. Модули:

    • ngx_http_echo_module.so необходим для передачи тела запроса когда не используются директивы proxy_pass, fastcgi_pass, uwsgi_pass и scgi_pass;

    • ngx_http_kafka_log_module.so — модуль для передачи сообщений из Nginx в топики Kafka.

  2. kafka_log_kafka_brokers — непосредственно брокеры Kafka.

  3. Дальше идет блок http c блоком server, в котором содержится условие для $request_uri. Это условие нужно, чтобы убрать "/” из $request_uri, так как rewrite тут использовать не получится — он вызовет return и завершит обработку до директивы echo_read_request_body. В переменной $request_key получаем название топика без обратного слеша. Было — /topic_name, стало — topic_name.

  4. Блок location задает работу с двумя модулями:

    • kafka_log — отправляем в топики Kafka тело запроса;

    • echo_read_request_body— прочитываем тело запроса, чтобы передать в $request_body.

На этом всё — теперь вы можете принимать сообщения для Kafka, отправляя их на URL вида https://example.com/topic_name

P.S. Не забывайте, что у этого метода могут быть существенные ограничения и он во многом уступает возможностям собственного издателя. Для нашего проекта мы позже всё же переделали сертификаты и добавили их в конфигурацию Kafka.

© Habrahabr.ru