Kong Gateway в Docker Compose: готовый файл
Когда микросервисов становится больше двух-трёх, каждый начинает сам разбираться с аутентификацией, лимитами запросов и логированием — код дублируется, а поведение расходится от сервиса к сервису. Kong Gateway решает это на уровне одной точки входа: все запросы идут через него, а плагины дают единую аутентификацию, rate limiting и логи для всех сервисов сразу, без правок в самих микросервисах. Ниже — рабочий docker-compose.yml, DB-less альтернатива и настройка ключевых плагинов через Admin API.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Зачем Kong, если уже есть Nginx или Traefik
Nginx и Traefik как reverse proxy для Docker отлично маршрутизируют трафик по доменам и путям, но у них нет встроенной модели «плагинов на сервис»: аутентификацию и лимиты туда приходится добавлять через lua-модули или отдельные сервисы. Kong построен именно как API-шлюз — поверх того же Nginx/OpenResty, но с декларативной моделью Services → Routes → Plugins и Admin API, через который всё настраивается без правки конфигов и перезапуска.
Практическая разница:
| Задача | Nginx | Traefik | Kong |
|---|---|---|---|
| Маршрутизация по домену/пути | вручную в конфиге | метки на контейнере | Admin API / decK |
| Аутентификация по ключу/JWT | пишется вручную | нет из коробки | плагин key-auth/jwt |
| Rate limiting per-consumer | сложно | базовый middleware | плагин с учётом клиента |
| Централизованные логи запросов | access_log | базовый | плагины file-log, http-log, tcp-log |
| Порог входа | низкий | низкий | выше — своя БД/DB-less конфиг |
Если у вас три сервиса и нужна только маршрутизация — Traefik или Nginx проще и дешевле в поддержке. Kong оправдан, когда за шлюзом реально несколько команд/сервисов и нужна единая политика доступа и лимитов, которую вы не хотите размазывать по коду.
Архитектура и готовый docker-compose.yml (Postgres-режим)
Kong умеет работать в двух режимах, и выбор стоит сделать до первого docker compose up — переключаться между ними на живой системе неудобно. DB-режим (Postgres) хранит сервисы, маршруты, плагины и потребителей в PostgreSQL, конфигурация меняется через Admin API или Kong Manager и применяется сразу, без перезапуска — подходит, когда конфиг правят часто и вручную. DB-less режим держит всю конфигурацию в одном YAML-файле, который Kong читает при старте: никакой базы, конфиг удобно версионировать в git и катить через CI, но изменения применяются через kong reload, а не на лету через API. Для инфраструктуры как кода обычно удобнее DB-less, для многокомандной среды — Postgres. Ниже — оба варианта, начиная с Postgres.
Файл поднимает Postgres, применяет миграции отдельным контейнером и только потом стартует сам Kong — так исключается гонка «Kong запустился раньше, чем накатилась схема БД».
# docker-compose.yml
services:
kong-database:
image: postgres:16-alpine
container_name: kong-database
restart: unless-stopped
environment:
POSTGRES_USER: kong
POSTGRES_DB: kong
POSTGRES_PASSWORD: ${KONG_PG_PASSWORD}
volumes:
- kong_pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "kong"]
interval: 5s
timeout: 5s
retries: 10
networks:
- kong-net
kong-migrations:
image: kong:3.8
container_name: kong-migrations
command: kong migrations bootstrap
restart: on-failure
depends_on:
kong-database:
condition: service_healthy
environment:
KONG_DATABASE: postgres
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: ${KONG_PG_PASSWORD}
networks:
- kong-net
kong:
image: kong:3.8
container_name: kong
restart: unless-stopped
depends_on:
kong-migrations:
condition: service_completed_successfully
environment:
KONG_DATABASE: postgres
KONG_PG_HOST: kong-database
KONG_PG_USER: kong
KONG_PG_PASSWORD: ${KONG_PG_PASSWORD}
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: 0.0.0.0:8001
KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl
ports:
- "8000:8000" # прокси, HTTP
- "8443:8443" # прокси, HTTPS
- "127.0.0.1:8001:8001" # Admin API — только на localhost!
healthcheck:
test: ["CMD", "kong", "health"]
interval: 10s
timeout: 5s
retries: 5
networks:
- kong-net
volumes:
kong_pg_data:
networks:
kong-net:
driver: bridge
Пароль от Postgres кладите в .env рядом с файлом, а не в сам compose-файл — подробнее о подходе к секретам в статье про управление паролями через Docker secrets. Порт 8001 (Admin API) сознательно пробрасывается только на 127.0.0.1: через него можно создавать и удалять любые сервисы и плагины без аутентификации из коробки.
Если бэкенд-сервисы уже описаны в другом docker-compose.yml, подключите их к сети kong-net (external: true) или объедините проекты в один файл — иначе Kong не достучится до них по DNS-имени контейнера. О типах сетей в Docker — в статье про bridge, host и overlay.
Поднимаем:
cp .env.example .env # заполните KONG_PG_PASSWORD
docker compose up -d
docker compose logs -f kong
curl -s http://127.0.0.1:8001/status | jq
Если status отвечает JSON с database.reachable: true — Kong готов принимать конфигурацию.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверDB-less альтернатива: один YAML вместо базы
Меньше сервисов в compose, конфиг версионируется в git.
# docker-compose.dbless.yml
services:
kong:
image: kong:3.8
container_name: kong
restart: unless-stopped
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /kong/declarative/kong.yml
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: 0.0.0.0:8001
KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl
volumes:
- ./kong.yml:/kong/declarative/kong.yml:ro
ports:
- "8000:8000"
- "8443:8443"
- "127.0.0.1:8001:8001"
healthcheck:
test: ["CMD", "kong", "health"]
interval: 10s
timeout: 5s
retries: 5
А сам kong.yml описывает сервисы, маршруты и плагины декларативно:
# kong.yml
_format_version: "3.0"
services:
- name: orders-service
url: http://orders-api:3000
routes:
- name: orders-route
paths:
- /api/orders
plugins:
- name: rate-limiting
config:
minute: 60
policy: local
consumers:
- username: mobile-app
keyauth_credentials:
- key: ${MOBILE_APP_KEY}
После правки файла конфигурация применяется командой docker compose exec kong kong reload или перезапуском контейнера. Admin API здесь доступен только для чтения (GET) — это нормально, а не баг: изменения вносятся через файл.
Сервисы, маршруты и аутентификация через Admin API
В режиме с базой конфигурация задаётся вызовами к Admin API — тем же способом, каким её потом будет менять ваш CI или скрипт. Регистрируем бэкенд-сервис и маршрут к нему:
# сервис: куда Kong будет проксировать запросы
curl -i -X POST http://127.0.0.1:8001/services \
--data name=orders-service \
--data url=http://orders-api:3000
# маршрут: по какому пути этот сервис доступен снаружи
curl -i -X POST http://127.0.0.1:8001/services/orders-service/routes \
--data name=orders-route \
--data paths[]=/api/orders
Проверка:
curl -i http://127.0.0.1:8000/api/orders
Запрос на 8000 порт уходит через Kong к http://orders-api:3000 — при условии, что контейнер orders-api в той же docker-сети, что и Kong. Для команд, которые не хотят гонять curl вручную, есть decK — CLI-утилита, синхронизирующая шлюз с YAML-файлом (deck sync -s kong.yml).
Теперь добавим аутентификацию на этот сервис. Самый простой вариант — плагин key-auth: клиент передаёт ключ в заголовке, Kong проверяет его перед тем, как пропустить запрос дальше.
# включаем key-auth на сервисе
curl -i -X POST http://127.0.0.1:8001/services/orders-service/plugins \
--data name=key-auth
# заводим потребителя и выдаём ему ключ
curl -i -X POST http://127.0.0.1:8001/consumers \
--data username=mobile-app
curl -i -X POST http://127.0.0.1:8001/consumers/mobile-app/key-auth \
--data key=your-secret-key-here
Теперь запрос без ключа получит 401 Unauthorized, а с ним — пройдёт:
curl -i http://127.0.0.1:8000/api/orders \
-H "apikey: your-secret-key-here"
Для сценариев, где токен выдаёт ваш собственный auth-сервис (а не Kong), уместнее плагин jwt: Kong не выдаёт токены сам, а проверяет подпись присланного JWT по секрету или публичному ключу, привязанному к потребителю:
curl -i -X POST http://127.0.0.1:8001/services/orders-service/plugins \
--data name=jwt
curl -i -X POST http://127.0.0.1:8001/consumers/mobile-app/jwt \
--data algorithm=HS256 \
--data secret=your-jwt-secret
Дальше клиент подписывает токен тем же секретом, а Kong валидирует подпись и exp на входе — сервис за шлюзом получает уже проверенный запрос и может не заниматься валидацией токенов у себя.
Rate limiting и защита от перегрузки
Плагин rate-limiting ограничивает число запросов на сервис, маршрут или конкретного потребителя — удобно разделить лимиты для бесплатного и платного тарифа API, не трогая код сервисов.
# общий лимит на сервис: 100 запросов в минуту, 2000 в час
curl -i -X POST http://127.0.0.1:8001/services/orders-service/plugins \
--data name=rate-limiting \
--data config.minute=100 \
--data config.hour=2000 \
--data config.policy=local
policy=local считает лимит в памяти узла — просто, но при нескольких инстансах Kong за балансировщиком каждый узел считает отдельно, не общий лимит. Для честного лимита на кластере нужен policy=redis с общим Redis:
curl -i -X PATCH http://127.0.0.1:8001/plugins/{plugin-id} \
--data config.policy=redis \
--data config.redis.host=redis \
--data config.redis.port=6379
Отдельно можно выдать конкретному потребителю более щедрый лимит — плагин применяется на уровне consumer, и Kong использует именно его вместо общего:
curl -i -X POST http://127.0.0.1:8001/consumers/mobile-app/plugins \
--data name=rate-limiting \
--data config.minute=500
Важно не путать rate limiting с защитой от DDoS: Kong ограничивает легитимных клиентов по идентификатору (ключ, JWT-subject, IP), но от объёмной атаки с тысяч случайных IP это не спасает — для такого нужен CDN/anti-DDoS перед шлюзом.
Логирование и мониторинг
Из коробки Kong пишет access/error логи в stdout/stderr контейнера (это уже настроено переменными KONG_PROXY_ACCESS_LOG в примере выше) — их можно смотреть через docker compose logs kong или собирать любым Docker-log-драйвером. Для структурированных логов запросов (метод, статус, латентность, потребитель) есть плагин file-log или http-log:
# каждый запрос — отдельной JSON-строкой в файл
curl -i -X POST http://127.0.0.1:8001/services/orders-service/plugins \
--data name=file-log \
--data config.path=/tmp/orders-access.log
# либо отправка логов на внешний коллектор
curl -i -X POST http://127.0.0.1:8001/services/orders-service/plugins \
--data name=http-log \
--data config.http_endpoint=http://log-collector:8080/logs
Если у вас уже есть стек логирования, http-log можно направить в Loki через промежуточный приёмник — как собрать саму связку, описано в статье про Grafana Loki в Docker Compose. Для метрик (RPS, latency, коды ответов) в Kong есть плагин prometheus, отдающий /metrics в формате, который Prometheus снимает без дополнительного экспортёра.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Kong обязательно требует PostgreSQL?
Нет, только в классическом режиме. DB-less (KONG_DATABASE: "off") работает с одним YAML-файлом без базы — подходит, если конфигурация меняется редко.
Admin API безопасно оставлять открытым в интернет?
Нет. У него нет аутентификации по умолчанию — любой, кто достучится, может удалить сервисы и плагины. Порт 8001 пробрасывайте только на 127.0.0.1, для удалённого доступа — SSH-туннель или VPN, либо RBAC (Kong Enterprise).
Чем Kong отличается от Kong Enterprise?
Open-source образ покрывает маршрутизацию, плагины аутентификации/лимитов/логирования и Admin API — этого хватает для большинства self-hosted сценариев. Enterprise добавляет Kong Manager с ролевой моделью доступа и часть продвинутых плагинов.
Можно ли поставить Kong перед уже работающим Nginx?
Да, но обычно не нужно: либо Kong сам терминирует TLS, либо перед ним внешний балансировщик, а лишний слой Nginx/Traefik становится избыточным. Двойное проксирование оправдано разве что при постепенной миграции маршрутов.
Как обновить Kong без даунтайма?
В Postgres-режиме — поднять контейнер с новым тегом, дождаться healthcheck, переключить балансировщик, погасить старый; миграции схемы идут отдельным kong-migrations job. В DB-less проще: новый контейнер стартует с тем же kong.yml, старый гасится сразу после healthcheck нового.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →