Передача запросов от хоста к контейнеру с помощью доменного сокета

У меня есть uwsgi, запущенный в контейнере docker. Nginx работает на хосте.

Текущая настройка:

;uwsgi.ini

http-socket=:8080

С помощью docker я перенаправил порт 8080 хоста на порт 8080 контейнера. Nginx настроен следующим образом

server {
    listen 443 ssl http2;
    server_name domain.example.com;
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

Это работает отлично, единственная проблема: мой порт 8080 открыт, и я могу напрямую запросить порт на публичном IP. Я должен быть в состоянии использовать доменные сокеты, чтобы смягчить это, но я не знаю, как это будет выглядеть.

Вот моя полупопытка:

; uwsgi.ini in container

socket=/path/uwsgi.sock
# nginx on host

upstream prod_server {
    server unix:///path/uwsgi.sock;
}

server {
    listen 443 ssl http2;
    server_name example.domain.com;
    location {
        uwsgi_pass pror_server;
    }
}

Поскольку nginx находится на хосте, он будет искать путь на хост-сервере, является ли добавление сокета в качестве тома правильным способом? Есть ли другая лучшая практика? Как бы вы рекомендовали настроить? Спасибо.

мой порт 8080 открыт, и я могу напрямую запросить порт на публичном IP

При публикации порта опции docker run -p и Compose ports: принимают необязательный IP-адрес. Это IP-адрес хоста, к которому Docker должен привязать внешний слушающий сокет. По умолчанию он равен 0.0.0.0, или "все интерфейсы", но вы можете указать 127.0.0.1, чтобы привязать его только к интерфейсу localhost хоста, и тогда бэкенд не будет доступен из других систем.

docker run -p 127.0.0.1:8080:8080 ...
#             ^^^^^^^^^
ports:
  - '127.0.0.1:8000:8000'
  #  ^^^^^^^^^

правильно ли добавлять сокет [Unix] в качестве тома?

Если вы хотите использовать здесь сокет Unix, вам нужно монтировать Docker bind mount (а не именованный том), причем монтировать нужно каталог, содержащий сокет, а не сам сокет. Это, вероятно, означает, что каталог должен быть пустым, поскольку содержимое каталога хоста полностью заменит содержимое образа - не пытайтесь использовать здесь каталог, содержащий код вашего приложения.

docker run -v /path:/path ...
#          -v /host/path:/container/path ...
volumes:
  - "/path:/path

Первый путь - это путь к хосту, он соответствует конфигурации Nginx; второй - это путь к контейнеру, он соответствует вашему файлу uwsgi.ini. Эти два пути не обязательно должны совпадать.

Unix-сокеты могут вообще не работать на Docker Desktop или других установках на базе ВМ; они могут работать только на хосте native-Linux, на котором непосредственно запущен движок Docker.

Как бы вы рекомендовали настраивать?

Я бы запустил Nginx в контейнере, если это возможно. Тогда два контейнера смогут использовать сетевое взаимодействие Docker для связи, и вам не придется публиковать порт бэкенда.

Если прокси уже находится на хостовой системе (возможно, вы проксируете смесь контейнерных и неконтейнерных приложений, или несколько приложений, и нет смысла прикреплять прокси к какому-то одному конкретному), то я бы использовал TCP-сокет, но опубликованный только на хосте, как в первой половине. Это более простая настройка и позволяет избежать проблем с разрешениями файловой системы.

Вернуться на верх