DevSecOps

8 dez, 2015

Nginx: não é possível determinar uma requisição de endereço no upstream

Publicidade

Há alguns dias, eu me deparei com uma mensagem de erro interessante no Nginx.

[crit] 12889#0: *32401195 connect() to 127.0.0.1:80 failed (99: Cannot assign requested address) while connecting to upstream

Minha configuração foi muito simples. Isso foi um proxy Nginx que fez toda a criptografia SSL e enviou o tráfego para instância de Varnish, sendo executado em port :80 em localhost. A grande questão aqui é que foi um tráfego bastante elevado de proxy Nginx.

Mesmo com keepalive ativado no upstream do nginx, o erro apareceu. Mas o que isso significa?

Portas TCP e limites

É bom saber uma coisa ou duas sobre redes, além de apenas servidores, de vez em quando. O problema ocorreu porque o servidor não poderia ter uma porta TCP livre rápido o suficiente para fazer a conexão com 127.0.0.1.

$ ss -s
Total: 3130 (kernel 3431)
TCP:   51582 (estab 2866, closed 48611, orphaned 92, synrecv 0, timewait 48611/0), ports 35279

A ferramenta ss oferece estatísticas sobre soquetes/portas no servidor. Neste caso, eu tinha 51.582 sessões TCP em uso (tanto ativas, fechadas, à espera de serem fechada, …).

Um servidor normal tem aproximadamente 28.000 portas TCP possíveis que podem ser usadas ​​para fazer uma conexão TCP para um sistema remoto (ou local). Tudo o que fala por meio de um endereço IP irá escolher uma porta livre dessas para servir como porta de origem para a conexão de saída. Esse intervalo de porta é definido pelo parâmetro sysctl ip_local_port_range.

$ cat /proc/sys/net/ipv4/ip_local_port_range
32768	61000

$ sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768	61000

O formato é porta “minimum maximum“. Assim, 61.000-32.768 = 28 232 portas-fonte disponíveis.

Um proxy SSL Nginx que se conecta a uma instância Varnish rodando em localhost será parecido com isto em sua netstat.

$ netstat -anp | grep 127.0.0.1
...
tcp        0      0 127.0.0.1:37713         127.0.0.1:80            TIME_WAIT   -

O principal tópico aqui é a conexão de fonte de 127.0.0.1:37713 que se conecta ao seu endpoint 127.0.0.1:80. Para cada origem de conexão, uma nova fonte porta TCP é selecionada a partir do intervalo no parâmetro ip_local_port_range.

A combinação de um IP de origem, porta de origem, IP de destino e destino IP deve ser única. Isso é o que é chamado um quadruplet em termos de rede. Você provavelmente não pode (facilmente) mudar o IP de origem. A porta de origem é escolhida de forma dinâmica. Isso só deixa a o IP de destino e a porta de destino livres para brincar.

Resolvendo a limitação da porta de origem

Há algumas correções fáceis. Primeiro, o ip_local_port_range pode ser aumentado em uma máquina Linux (para obter mais material de leitura, ver aumentar o intervalo ip_local_port_range de portas TCP no Linux).

$ echo 15000 64000 > /proc/sys/net/ipv4/ip_local_port_range

Isso efetivamente aumenta o intervalo de portas totais do padrão de 28.232 para 49.000 portas.

Se isso não for suficiente, você pode adicionar mais IPs de destino para se conectar. Lembre-se de que cada conexão consiste em 4 partes (chamadas quadruplets) com porta de origem e IP de origem, IP de destino e porta de destino. Se você não pode mudar a porta de origem ou IP, basta alterar os IPs de destino.

Considere este tipo de definição para o upstream em Nginx;

upstream varnish {
  server 127.0.0.1:80;
}

Essa definição pode ser usada em suas configurações nginx com a diretiva proxy_pass.

server {
  listen 443;
  ...
  location / {
    proxy_pass http://varnish;
    ...
  }
}

Agora, se você sabe que cada servidor tem geralmente 2 IPs ou mais, é muito fácil adicionar mais quadriplets à sua pilha de rede, fazendo uma adição ao seu IP Nginx upstream. Você já adicionou 127.0.0.1, mas o servidor terá um outro IP (será público ou DHCP IP) que você pode adicionar com segurança também, se o seu servidor web se liga a todas as portas.

upstream varnish {
  server 127.0.0.1:80;
  server 31.193.180.217:80;
  server 10.50.5.1:80;
  ...
}

Cada IP que você adicionar em seu upstream está efetivamente adicionando 49.000 portas locais para a sua pilha de rede. Você pode até adicionar IPs locais não-roteáveis ​​para o servidor, como aliases de interface, apenas para usar como novos IPs de destino para as suas configurações de proxy.

***

Mattias Geniar faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://ma.ttias.be/nginx-cannot-assign-requested-address-for-upstream/