Перейти к основному содержанию Перейти к навигации Перейти к нижнему колонтитулу

Сетевое взаимодействие

Предоставление сервисов через обратный прокси, Docker-метки, TLS-сертификаты, DNS и проброс TCP/UDP-портов.

Сетевое взаимодействие

На этой странице описывается, как сервисы, работающие внутри изолированных Docker-демонов, становятся доступными из интернета. Рассматривается система обратного прокси, Docker-метки для маршрутизации, TLS-сертификаты, DNS и проброс TCP/UDP-портов. | Route server running old version | Binary was updated but service not restarted | Happens automatically on provisioning; manual: sudo systemctl restart rediacc-router | | STUN/TURN relay not reachable | Relay addresses cached at startup | Recreate the service after DNS or IP changes so it picks up the new network config |

Информацию о том, как сервисы получают loopback IP-адреса и как работает система слотов .rediacc.json, см. в разделе Сервисы.

Как это работает

Rediacc использует двухкомпонентную систему прокси для маршрутизации внешнего трафика к контейнерам:

  1. Сервер маршрутов, systemd-сервис, который обнаруживает работающие контейнеры во всех Docker-демонах репозиториев. Он проверяет метки контейнеров и генерирует конфигурацию маршрутизации, предоставляемую как YAML-эндпоинт.
  2. Traefik, обратный прокси, который опрашивает сервер маршрутов каждые 5 секунд и применяет обнаруженные маршруты. Он обрабатывает HTTP/HTTPS-маршрутизацию, TLS-терминацию и проброс TCP/UDP.

Поток трафика выглядит следующим образом:

Internet → Traefik (ports 80/443/TCP/UDP)
               ↓ polls every 5s
           Route Server (discovers containers)
               ↓ inspects labels
           Docker Daemons (/var/run/rediacc/docker-*.sock)

           Containers (bound to 127.x.x.x loopback IPs)

Когда вы добавляете правильные метки к контейнеру и запускаете его с помощью renet compose, он автоматически становится маршрутизируемым, ручная настройка прокси не требуется.

The route server binary is kept in sync with your CLI version. When the CLI updates the renet binary on a machine, the route server is automatically restarted (~1–2 seconds). This causes no downtime, Traefik continues serving traffic with its last known configuration during the restart and picks up the new config on the next poll. Existing client connections are not affected. Your application containers are not touched.

Docker-метки

Маршрутизация управляется с помощью меток Docker-контейнеров. Существуют два уровня:

Уровень 1: Метки rediacc.* (автоматические)

Эти метки автоматически внедряются командой renet compose при запуске сервисов. Вам не нужно добавлять их вручную.

МеткаОписаниеПример
rediacc.service_nameИдентификатор сервисаmyapp
rediacc.service_ipНазначенный loopback IP127.0.11.2
rediacc.network_idИдентификатор демона репозитория2816
rediacc.repo_nameRepository namemarketing
rediacc.tcp_portsTCP ports the service listens on8080,8443
rediacc.udp_portsUDP ports the service listens on53

Когда контейнер имеет только метки rediacc.* (без traefik.enable=true), сервер маршрутов генерирует автомаршрут с использованием имени репозитория и поддомена машины:

{service}.{repoName}.{machineName}.{baseDomain}

Например, сервис с именем myapp в репозитории marketing на машине server-1 с базовым доменом example.com получит:

myapp.marketing.server-1.example.com

Каждый репозиторий имеет свой собственный уровень поддомена, поэтому форки и разные репозитории никогда не пересекаются. При форке репозитория (например, marketing-staging) форк автоматически получает отдельные маршруты. Для сервисов с пользовательскими доменами используйте метки уровня 2 или метку rediacc.domain.

Пользовательский домен через rediacc.domain

Вы можете задать пользовательский домен для сервиса с помощью метки rediacc.domain в вашем docker-compose.yml. Поддерживаются как короткие имена, так и полные домены:

labels:
  # Короткое имя, преобразуется в cloud.example.com с использованием baseDomain машины
  - "rediacc.domain=cloud"

  # Полный домен, используется как есть
  - "rediacc.domain=cloud.example.com"

Значение без точек обрабатывается как короткое имя, и baseDomain машины добавляется автоматически. Значение с точками используется как полный домен.

Когда настроен machineName, сервисы с пользовательским доменом получают два маршрута: один на базовом домене (cloud.example.com) и один на поддомене машины (cloud.server-1.example.com).

Уровень 2: Метки traefik.* (пользовательские)

Добавьте эти метки в ваш docker-compose.yml, когда вам нужна маршрутизация по пользовательскому домену, TLS или определенные точки входа. Установка traefik.enable=true указывает серверу маршрутов использовать ваши пользовательские правила вместо генерации автомаршрута.

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
  - "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
  - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
  - "traefik.http.services.myapp.loadbalancer.server.port=8080"

Здесь используется стандартный синтаксис меток Traefik v3.

Совет: Внутренние сервисы (базы данных, кеши, очереди сообщений) не должны иметь traefik.enable=true. Им нужны только метки rediacc.*, которые внедряются автоматически.

Предоставление HTTP/HTTPS-сервисов

Предварительные требования

  1. Настроенная инфраструктура на машине (Настройка машины, Настройка инфраструктуры):

    # Общие учетные данные (один раз на конфигурацию, применяются ко всем машинам)
    rdc config infra set -m server-1 \
      --cert-email admin@example.com \
      --cf-dns-token your-cloudflare-api-token
    
    # Настройки конкретной машины
    rdc config infra set -m server-1 \
      --public-ipv4 203.0.113.50 \
      --base-domain example.com
    
    rdc config infra push -m server-1
  2. DNS-записи, указывающие ваш домен на публичный IP сервера (см. Настройка DNS ниже).

Добавление меток

Добавьте метки traefik.* к сервисам, которые хотите предоставить, в вашем docker-compose.yml:

services:
  myapp:
    image: myapp:latest
    environment:
      - LISTEN_ADDR=${MYAPP_IP}:8080
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.myapp.entrypoints=websecure,websecure-v6"
      - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.myapp.loadbalancer.server.port=8080"

  database:
    image: postgres:17
    command: ["-c", "listen_addresses=${DATABASE_IP}"]
    # Без меток traefik, база данных только для внутреннего использования
МеткаНазначение
traefik.enable=trueВключает пользовательскую маршрутизацию Traefik для этого контейнера
traefik.http.routers.{name}.ruleПравило маршрутизации, обычно Host(\domain`)`
traefik.http.routers.{name}.entrypointsТочки входа: websecure (HTTPS IPv4), websecure-v6 (HTTPS IPv6)
traefik.http.routers.{name}.tls.certresolverРезолвер сертификатов, используйте letsencrypt для автоматического Let’s Encrypt
traefik.http.services.{name}.loadbalancer.server.portПорт, на котором ваше приложение слушает внутри контейнера

{name} в метках, произвольный идентификатор; он должен быть согласованным во всех связанных метках маршрутизатора/сервиса/middleware.

Примечание: Метки rediacc.* (rediacc.service_name, rediacc.service_ip, rediacc.network_id) внедряются автоматически командой renet compose. Вам не нужно добавлять их в ваш compose-файл.

TLS-сертификаты

TLS-сертификаты получаются автоматически через Let’s Encrypt с использованием DNS-01 проверки Cloudflare. Учетные данные настраиваются один раз на конфигурацию (общие для всех машин):

rdc config infra set -m server-1 \
  --cert-email admin@example.com \
  --cf-dns-token your-cloudflare-api-token

Автомаршруты используют wildcard-сертификаты на уровне поддомена репозитория (*.marketing.server-1.example.com) вместо сертификатов для каждого сервиса. Это позволяет избежать ограничений скорости Let’s Encrypt и ускоряет запуск. Маршруты с пользовательскими доменами используют wildcard на уровне машины (*.server-1.example.com).

Для маршрутов уровня 2 с traefik.http.routers.{name}.tls.certresolver=letsencrypt wildcard-домены SAN автоматически добавляются на основе имени хоста маршрута.

API-токен Cloudflare DNS должен иметь разрешение Zone:DNS:Edit для доменов, которые вы хотите защитить.

Проброс TCP/UDP-портов

Для не-HTTP протоколов (почтовые серверы, DNS, базы данных с внешним доступом) используйте проброс TCP/UDP-портов.

Шаг 1: Регистрация портов

Добавьте необходимые порты при настройке инфраструктуры:

rdc config infra set -m server-1 \
  --tcp-ports 25,143,465,587,993 \
  --udp-ports 53

rdc config infra push -m server-1

Это создает точки входа Traefik с именами tcp-{port} и udp-{port}.

Plain TCP Example (Database)

To expose a database externally without TLS passthrough (Traefik forwards raw TCP):

services:
  postgres:
    image: postgres:17
    command: -c listen_addresses=${POSTGRES_IP} -c port=5432
    labels:
      - "traefik.enable=true"
      - "traefik.tcp.routers.mydb.entrypoints=tcp-5432"
      - "traefik.tcp.routers.mydb.rule=HostSNI(`*`)"
      - "traefik.tcp.services.mydb.loadbalancer.server.port=5432"

Port 5432 is pre-configured (see below), so no --tcp-ports setup is needed.

Security note: Exposing a database to the internet is a risk. Use this only when remote clients need direct access. For most setups, keep the database internal and connect through your application.

После добавления или удаления портов всегда повторно выполняйте rdc config infra push для обновления конфигурации прокси.

Шаг 2: Добавление TCP/UDP-меток

Используйте метки traefik.tcp.* или traefik.udp.* в вашем compose-файле:

services:
  mail-server:
    image: ghcr.io/docker-mailserver/docker-mailserver:latest
    labels:
      - "traefik.enable=true"

      # SMTP (port 25)
      - "traefik.tcp.routers.mail-smtp.entrypoints=tcp-25"
      - "traefik.tcp.routers.mail-smtp.rule=HostSNI(`*`)"
      - "traefik.tcp.routers.mail-smtp.service=mail-smtp"
      - "traefik.tcp.services.mail-smtp.loadbalancer.server.port=25"

      # IMAPS (port 993), TLS passthrough
      - "traefik.tcp.routers.mail-imaps.entrypoints=tcp-993"
      - "traefik.tcp.routers.mail-imaps.rule=HostSNI(`mail.example.com`)"
      - "traefik.tcp.routers.mail-imaps.tls.passthrough=true"
      - "traefik.tcp.routers.mail-imaps.service=mail-imaps"
      - "traefik.tcp.services.mail-imaps.loadbalancer.server.port=993"

Ключевые концепции:

  • HostSNI(\*`)` соответствует любому имени хоста (для протоколов, не отправляющих SNI, например, обычный SMTP)
  • tls.passthrough=true означает, что Traefik пересылает необработанное TLS-соединение без расшифровки, приложение само обрабатывает TLS
  • Имена точек входа следуют соглашению tcp-{port} или udp-{port}

Предварительно настроенные порты

Следующие TCP/UDP-порты имеют точки входа по умолчанию (не нужно добавлять через --tcp-ports). Точки входа генерируются только для настроенных семейств адресов, точки входа IPv4 требуют --public-ipv4, точки входа IPv6 требуют --public-ipv6:

ПортПротоколТипичное использование
80HTTPВеб (автоперенаправление на HTTPS)
443HTTPSВеб (TLS)
3306TCPMySQL/MariaDB
5432TCPPostgreSQL
6379TCPRedis
27017TCPMongoDB
11211TCPMemcached
5672TCPRabbitMQ
9092TCPKafka
53UDPDNS
10000–10010TCPДинамический диапазон (автовыделение)

Настройка DNS

Автоматический DNS (Cloudflare)

Когда настроен --cf-dns-token, rdc config infra push автоматически создает необходимые DNS-записи в Cloudflare:

ЗаписьТипСодержимоеСоздано
server-1.example.comA / AAAAПубличный IP машиныpush-infra
*.server-1.example.comA / AAAAПубличный IP машиныpush-infra
*.marketing.server-1.example.comA / AAAAПубличный IP машиныrepo up

Записи уровня машины создаются командой push-infra и покрывают маршруты с пользовательскими доменами (rediacc.domain). Wildcard-записи для каждого репозитория создаются автоматически командой repo up и покрывают автомаршруты этого репозитория.

Это идемпотентно, существующие записи обновляются при изменении IP и остаются без изменений, если уже корректны.

Wildcard базового домена (*.example.com) необходимо создать вручную, если вы используете пользовательские метки домена, например rediacc.domain=erp.

Ручная настройка DNS

Если вы не используете Cloudflare или управляете DNS вручную, создайте A (IPv4) и/или AAAA (IPv6) записи:

# Поддомен машины (для маршрутов с пользовательским доменом, например rediacc.domain=erp)
server-1.example.com           A     203.0.113.50
*.server-1.example.com         A     203.0.113.50
*.server-1.example.com         AAAA  2001:db8::1

# Wildcard для каждого репозитория (для автомаршрутов вроде myapp.marketing.server-1.example.com)
*.marketing.server-1.example.com    A     203.0.113.50
*.marketing.server-1.example.com    AAAA  2001:db8::1

# Wildcard базового домена (для сервисов с пользовательским доменом, например rediacc.domain=erp)
*.example.com                  A     203.0.113.50

При настроенном Cloudflare DNS wildcard-записи для каждого репозитория создаются автоматически командой repo up. При наличии нескольких машин каждая машина получает собственные DNS-записи, указывающие на её собственный IP.

Middleware

Middleware Traefik модифицируют запросы и ответы. Применяйте их через метки.

HSTS (HTTP Strict Transport Security)

labels:
  - "traefik.http.middlewares.myapp-hsts.headers.stsSeconds=15768000"
  - "traefik.http.middlewares.myapp-hsts.headers.stsIncludeSubdomains=true"
  - "traefik.http.middlewares.myapp-hsts.headers.stsPreload=true"
  - "traefik.http.routers.myapp.middlewares=myapp-hsts"

Буферизация для больших файлов

labels:
  - "traefik.http.middlewares.myapp-buffering.buffering.maxRequestBodyBytes=536870912"
  - "traefik.http.routers.myapp.middlewares=myapp-buffering"

Несколько middleware

Объединяйте middleware через запятую:

labels:
  - "traefik.http.routers.myapp.middlewares=myapp-hsts,myapp-buffering"

Полный список доступных middleware см. в документации Traefik middleware.

Диагностика

Если сервис недоступен, подключитесь к серверу по SSH и проверьте эндпоинты сервера маршрутов:

Проверка состояния

curl -s http://127.0.0.1:7111/health | python3 -m json.tool

Показывает общий статус, количество обнаруженных маршрутизаторов и сервисов, и включены ли автомаршруты.

Обнаруженные маршруты

curl -s http://127.0.0.1:7111/routes.json | python3 -m json.tool

Выводит список всех HTTP, TCP и UDP маршрутизаторов с их правилами, точками входа и бэкенд-сервисами.

Выделение портов

curl -s http://127.0.0.1:7111/ports | python3 -m json.tool

Показывает сопоставления TCP и UDP портов для динамически выделенных портов.

Типичные проблемы

ПроблемаПричинаРешение
Сервис не отображается в маршрутахКонтейнер не запущен или отсутствуют меткиПроверьте с помощью docker ps на демоне репозитория; проверьте метки
Сертификат не выпущенDNS не указывает на сервер или невалидный токен CloudflareПроверьте разрешение DNS; проверьте разрешения API-токена Cloudflare
502 Bad GatewayПриложение не слушает на объявленном портуУбедитесь, что приложение привязано к {SERVICE}_IP и порт совпадает с loadbalancer.server.port
TCP-порт недоступенПорт не зарегистрирован в инфраструктуреВыполните rdc config infra set --tcp-ports ... и push-infra

Полный пример

Этот пример развертывает веб-приложение с базой данных PostgreSQL. Приложение публично доступно по адресу app.example.com с TLS; база данных доступна только внутри.

docker-compose.yml

services:
  webapp:
    image: myregistry/webapp:latest
    environment:
      DATABASE_URL: postgresql://app:changeme@${POSTGRES_IP}:5432/webapp
      LISTEN_ADDR: ${WEBAPP_IP}:3000
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.webapp.entrypoints=websecure,websecure-v6"
      - "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
      - "traefik.http.services.webapp.loadbalancer.server.port=3000"
      # HSTS
      - "traefik.http.middlewares.webapp-hsts.headers.stsSeconds=15768000"
      - "traefik.http.middlewares.webapp-hsts.headers.stsIncludeSubdomains=true"
      - "traefik.http.routers.webapp.middlewares=webapp-hsts"

  postgres:
    image: postgres:17
    environment:
      POSTGRES_DB: webapp
      POSTGRES_USER: app
      POSTGRES_PASSWORD: changeme
    command: -c listen_addresses=${POSTGRES_IP} -c port=5432
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    # Без меток traefik, только для внутреннего использования

Rediaccfile

#!/bin/bash

up() {
    mkdir -p data/postgres
    renet compose -- up -d
}

down() {
    renet compose -- down
}

DNS

Создайте A-запись, указывающую app.example.com на публичный IP вашего сервера:

app.example.com   A   203.0.113.50

Развертывание

rdc repo up --name my-app -m server-1 --mount

Через несколько секунд сервер маршрутов обнаружит контейнер, Traefik подхватит маршрут, запросит TLS-сертификат, и https://app.example.com станет доступен.