Nginx не запускается с хостом, который не найден в восходящем потоке
Я использую nginx для прокси-сервера и сохраняю постоянные подключения к удаленным серверам для меня.
Я сконфигурировал около 15 блоков, подобных этому примеру:
upstream rinu-test {
server test.rinu.test:443;
keepalive 20;
}
server {
listen 80;
server_name test.rinu.test;
location / {
proxy_pass https://rinu-test;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $http_host;
}
}
Проблема в том, что если имя хоста не может быть разрешено в одном или нескольких из upstream
блоков, nginx не запустится (повторно). Я также не могу использовать статические IP-адреса, некоторые из этих ящиков явно не говорили об этом, потому что IP-адреса будут меняться. Каждое другое решение, которое я видел в этом сообщении об ошибке, говорит, чтобы избавиться от upstream
и сделать все в блоке location
. Это невозможно здесь, потому что keepalive
доступен только под upstream
.
Я могу временно позволить себе потерять один сервер, но не все 15.
Edit: Оказывается, nginx не подходит для этого варианта использования. Следует использовать альтернативный бэкэнд (upstream) keepalive proxy. В моем ответе есть альтернатива Node.js. До сих пор я не нашел других альтернатив, которые действительно работают.
Ответы
Ответ 1
Более ранние версии nginx (до 1.1.4), которые уже приводили в действие огромное количество самых посещаемых веб-сайтов во всем мире (а некоторые до сих пор работают даже в наши дни, если верить заголовкам серверов), даже не поддерживали поддержку keepalive
в upstream
сторона, потому что в настройке центра обработки данных это очень мало выгодно, если у вас нет нетривиальной задержки между вашими различными хостами; см. https://serverfault.com/a/883019/110020 для некоторых объяснений.
По сути, если вы не знаете, что вам конкретно нужен keepalive между вашими вышестоящим и внешним интерфейсом, скорее всего, это только сделает вашу архитектуру менее устойчивой и ухудшающей.
(Обратите внимание, что ваше текущее решение также неверно, потому что изменение IP-адреса также останется незамеченным, потому что вы выполняете разрешение имени хоста только при перезагрузке конфигурации; поэтому, даже если nginx запускается, он в основном перестанет работать после того, как IP-адреса из вышестоящих серверов меняются.)
Потенциальные решения, выберите одно:
-
Лучшее решение, по-видимому, состоит в том, чтобы просто избавиться от поддержки keepalive
в upstream
как, вероятно, ненужной в среде центра обработки данных, и использовать переменные с proxy_pass
для современного разрешения DNS для каждого запроса (nginx все еще достаточно умен, чтобы все еще выполнять кэширование таких резолюции)
-
Другой вариант - получить платную версию nginx через коммерческую подписку, в которой есть параметр resolve
для директивы server
в контексте upstream
.
-
Наконец, еще одна вещь, которую можно попробовать, это использовать переменную set
и/или map
для определения серверов в upstream
; это ни подтверждено, ни опровергнуто не было выполнено; например, это может или не может работать.
Ответ 2
Одним из возможных решений является использование локального кэша DNS. Это может быть локальный DNS-сервер, такой как Bind или Dnsmasq (с некоторой хитрой конфигурацией, обратите внимание, что nginx также может использовать указанный DNS-сервер вместо системы по умолчанию) или просто поддерживать кеш в файле hosts
.
Похоже, что использование файла hosts
с некоторыми скриптами довольно просто. Файл hosts должен быть разделен на статические и динамические части (то есть cat hosts.static hosts.dynamic > hosts
), а динамическая часть должна автоматически генерироваться (и обновляться) скриптом.
Возможно, имеет смысл время от времени проверять имена хостов для изменения IP-адресов и обновлять файлы хостов и перезагружать конфигурацию в nginx при изменениях. В случае, если какое-либо имя хоста не может быть разрешено, должен использоваться старый IP-адрес или некоторый IP-адрес по умолчанию (например, 127.0.1.9).
Если вам не нужны имена хостов в файле конфигурации nginx (т.е. Достаточно IP-адресов), upstream
раздел с IP-адресами (разрешенными именами хостов) может быть сгенерирован скриптом и включен в конфигурацию nginx - и нет необходимости касаться файла hosts в таком случае.
Ответ 3
Альтернативой является создание новой службы, которая только делает то, что я хочу. Следующее заменяет nginx для проксирования соединений https с помощью Node.js
const http = require('http');
const https = require('https');
const httpsKeepAliveAgent = new https.Agent({ keepAlive: true });
http.createServer(onRequest).listen(3000);
function onRequest(client_req, client_res) {
https.pipe(
protocol.request({
host: client_req.headers.host,
port: 443,
path: client_req.url,
method: client_req.method,
headers: client_req.headers,
agent: httpsKeepAliveAgent
}, (res) => {
res.pipe(client_res);
}).on('error', (e) => {
client_res.end();
})
);
}
Пример использования: curl http://localhost:3000/request_uri -H "Host: test.rinu.test"
который эквивалентен: curl https://test.rinu.test/request_uri
Ответ 4
Я установил параметр разрешения на сервер, и вам нужно установить Nginx Resolver в nginx.conf, как показано ниже:
/etc/nginx/nginx.conf:
http {
resolver 192.168.0.2 ipv6=off valid=40s; # The DNS IP server
}
Site.conf:
upstream rinu-test {
server test.rinu.test:443;
keepalive 20;
}
Ответ 5
(новый для nginx) В моем случае это было неправильное имя папки
Для конфигурации
upstream serv {
server ex2_app_1:3000;
}
убедитесь, что папка приложения находится в папке ex2:
ех2/приложение/...
Ответ 6
Ваш сценарий очень похож на тот, который используется при использовании aws ELB
как uptreams, где критически важно resolve
правильный IP-адрес определенного домена.
Первое, что вам нужно сделать и обеспечить, - это то, что DNS-серверы, которые вы используете, могут разрешать ваши домены, тогда вы можете создать свою конфигурацию следующим образом:
resolver 10.0.0.2 valid=300s;
resolver_timeout 10s;
location /foo {
set $foo_backend_servers foo_backends.example.com;
proxy_pass http://$foo_backend_servers;
}
location /bar {
set $bar_backend_servers bar_backends.example.com;
proxy_pass http://$bar_backend_servers;
}
Обратите внимание, что resolver 10.0.0.2
должен быть IP-сервером DNS-сервера, который работает и отвечает на ваши запросы, в зависимости от вашей установки это может быть служба локального кеша, такая как unbound. а затем просто используйте resolve 127.0.0.1
Теперь очень важно использовать переменную для указания имени домена из документов:
Когда вы используете переменную для указания имени домена в директиве proxy_pass, NGINX повторно разрешает доменное имя, когда истекает его TTL.
Вы можете проверить свой резольвер, используя такие инструменты, как dig
например:
$ dig +short stackoverflow.com
В случае необходимости использовать keepalive
в восходящем потоке, и если вы не можете использовать Nginx +, тогда вы можете попробовать открыть резервный балансир, вам нужно будет использовать/реализовать lua-resty-dns