Pular para conteúdo

upstream-jdomain: Módulo de resolução assíncrona de nomes de domínio para NGINX upstream

Instalação

Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:

  • RedHat Enterprise Linux 7, 8, 9 e 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 e Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-upstream-jdomain
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-upstream-jdomain

Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:

load_module modules/ngx_http_upstream_jdomain_module.so;

Este documento descreve o nginx-module-upstream-jdomain v1.5.2 lançado em 09 de dezembro de 2024.


Um módulo de resolução assíncrona de nomes de domínio para nginx upstream.

Este módulo permite que você use um nome de domínio em um bloco upstream e espera que o nome de domínio seja resolvido dinamicamente, para que seu upstream possa ser resiliente a atualizações de entradas DNS.

O módulo não realiza a resolução DNS automaticamente em algum intervalo. Em vez disso, a resolução DNS precisa ser solicitada por uma requisição para o upstream dado. Se o nginx servir uma conexão destinada a um upstream jdomain, e o interval configurado tiver decorrido, então o módulo realizará uma consulta DNS.

O módulo é compatível com outras diretivas de escopo upstream. Isso significa que você pode preencher um bloco upstream com múltiplas diretivas jdomain, múltiplas diretivas server, keepalive, diretivas de balanceamento de carga, etc. Observe que, a menos que outro método de balanceamento de carga seja especificado no bloco upstream, este módulo utiliza o algoritmo de balanceamento de carga round robin padrão embutido no núcleo do nginx.

Nota Importante: Se um algoritmo de balanceamento de carga alternativo for especificado, ele deve vir antes da diretiva jdomain no bloco upstream! Se isso não for seguido, o nginx irá falhar durante a execução! Isso ocorre porque muitos outros módulos de balanceamento de carga estendem explicitamente o round robin embutido e, assim, acabam sobrescrevendo os manipuladores de inicialização do jdomain, uma vez que o jdomain é tecnicamente um módulo de balanceamento de carga também. Embora isso possa não ser o caso com todos os módulos de balanceamento de carga, é melhor ficar no lado seguro e colocar o jdomain depois.

Nota Importante: Devido à natureza não bloqueante deste módulo e ao fato de que sua resolução DNS é acionada por requisições de entrada, a requisição que aciona uma consulta será realmente encaminhada para o upstream que foi resolvido e armazenado em cache antes que a consulta DNS ocorra. Dependendo do cenário, isso pode resultar em uma falha única ao mudar os estados dos upstreams. Isso é importante ter em mente para garantir transições suaves dos seus upstreams.

Este repositório é um fork de um repositório originalmente criado por wdaike. Como aquele projeto não é mais mantido, este repositório visa ser seu sucessor e agora está vários recursos à frente.

Uso

resolver 8.8.8.8; # Seu Servidor DNS Local

## Upstream básico usando nome de domínio com porta padrão 80.
upstream backend_01 {
    jdomain example.com;
}

## Upstream básico especificando porta diferente.
upstream backend_02 {
    jdomain example.com port=8080;
}

## Upstream com um servidor de backup a ser usado em caso de host não encontrado ou erros de formato na resolução DNS.
upstream backend_03 {
    server 127.0.0.2 backup;
    jdomain example.com;
}

## Upstream que usará backup para quaisquer e todos os erros de resolução DNS.
upstream backend_04 {
    server 127.0.0.2 backup;
    jdomain example.com strict;
}

server {
    listen 127.0.0.2:80;
    return 502 'Um erro.';
}

Sinopse

Sintaxe: jdomain <nome-do-domínio> [port=80] [max_ips=4] [interval=1] [strict]
Contexto: upstream
Atributos:
    port:       Porta de escuta do backend.                                      (Padrão: 80)
    max_ips:    Tamanho do buffer de IP. Número máximo de IPs resolvidos a serem armazenados em cache.       (Padrão: 4)
    interval:   Quantos segundos para resolver o nome do domínio.                       (Padrão: 1)
    ipver:      Apenas endereços da família IPv4 ou IPv6 serão usados se definidos  (Padrão: 0)
    strict:     Exige que a resolução DNS seja bem-sucedida e retorne endereços,
                caso contrário, marca o servidor subjacente e os pares como inativos e
                força o uso de outros servidores no bloco upstream, se houver
                algum presente. Uma resolução falhada pode ser um timeout, falha do
                servidor DNS, recusas de conexão, resposta sem
                endereços, etc.

Veja https://www.nginx.com/resources/wiki/modules/domain_resolve/ para detalhes.

Desenvolvimento

Pré-requisitos

Para facilitar o desenvolvimento local e permitir que você construa e teste o módulo, você precisará de algumas ferramentas.

  • Docker: para fornecer um ambiente que reproduza facilmente as condições ideais para construção e teste.
  • act: para simular a execução de fluxos de trabalho do GitHub Actions localmente, evitando que você precise enviar commits apenas para ver a CI falhar.
  • rust: dependência de cargo-make.
  • cargo-make: para executar tarefas comuns de desenvolvimento, como construir, testar e formatar código.

Executor de Tarefas

cargo-make é um executor de tarefas avançado que permitirá que você execute facilmente operações comuns de desenvolvimento, como formatar o código, construir o módulo, executar a suíte de testes e realizar análise de código. Você pode ver as definições de tarefas no arquivo Makefile.toml. A instalação do cargo-make resultará em um executável autônomo chamado makers, além de uma extensão cargo que pode ser executada via cargo make. Como este projeto não é um crate rust, é recomendado usar simplesmente makers.

Além disso, note que, para simplificar, o executor de tarefas usa o docker para executar todas as tarefas. Isso significa que o binário de construção não está direcionado à sua plataforma host.

Tarefa Padrão

Para agregar valor, a tarefa padrão (ou seja, simplesmente executar makers sozinho) iniciará uma sessão bash interativa dentro do contêiner docker usado para este projeto.

Isso deve ajudar na depuração e no fluxo de trabalho geral.

Formatação

Código mal formatado fará com que o trabalho de linting do GitHub Actions falhe. Para evitar isso, você pode executar a tarefa de formatação antes de enviar novas alterações, assim:

makers format

Essa formatação é realizada por uma ferramenta chamada clang-format. Você pode encontrar as opções de configuração para isso definidas no arquivo ./.clang-format.

Análise Estática de Código

Você pode executar uma análise estática no código através da tarefa de análise:

makers analyse

Essa análise é realizada por uma ferramenta chamada clang-tidy. Você pode encontrar as opções de configuração para isso definidas no arquivo ./.clang-tidy.

Testes

Você pode executar a suíte de testes usando a tarefa de teste, assim:

makers test

Depuração

Podemos usar valgrind e gdb no nginx de dentro do contêiner.

Primeiro, abra um shell interativo no contêiner com:

$ makers

Usaremos essa sessão para executar valgrind:

$ valgrind --vgdb=full --vgdb-error=0 /github/workspace/bin/static/nginx -p/github/workspace/t/servroot -cconf/nginx.conf
==15== Memcheck, um detector de erro de memória
==15== Copyright (C) 2002-2017, e GNU GPL'd, por Julian Seward et al.
==15== Usando Valgrind-3.13.0 e LibVEX; reexecute com -h para informações de copyright
==15== Comando: /github/workspace/bin/static/nginx -p/github/workspace/t/servroot -cconf/nginx.conf
==15==
==15== (ação na inicialização) vgdb me ...
==15==
==15== PARA DEPURAR ESTE PROCESSO USANDO GDB: inicie o GDB assim
==15==   /path/to/gdb /github/workspace/bin/static/nginx
==15== e então  ao GDB o seguinte comando
==15==   target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=15
==15== --pid é opcional se apenas um processo valgrind estiver em execução
==15==

Em seguida, encontre o identificador do contêiner para que possamos abrir outra sessão dentro dele:

$ docker ps
CONTAINER ID        IMAGE                                     COMMAND             CREATED             STATUS              PORTS                    NAMES
55fab1e069ba        act-github-actions-nginx-module-toolbox   "bash"              4 seconds ago       Up 3 seconds        0.0.0.0:1984->1984/tcp   serene_newton

Use o nome ou ID para executar uma sessão bash dentro do contêiner:

$ docker exec -it serene_newton bash

Usaremos essa sessão para iniciar o gdb e direcionar o servidor gdb do valgrind que iniciamos na outra sessão:

$ gdb /github/workspace/bin/static/nginx
GNU gdb (GDB) Red Hat Enterprise Linux 8.0.1-30.amzn2.0.3
Copyright (C) 2017 Free Software Foundation, Inc.
Licença GPLv3+: versão 3 ou posterior da GNU GPL <http://gnu.org/licenses/gpl.html>
Este é um software livre: você é livre para modificar e redistribuir.
NÃO  GARANTIA, na medida permitida por lei.  Digite "show copying"
e "show warranty" para detalhes.
Este GDB foi configurado como "x86_64-redhat-linux-gnu".
Digite "show configuration" para detalhes da configuração.
Para instruções de relatório de bugs, consulte:
<http://www.gnu.org/software/gdb/bugs/>.
Encontre o manual do GDB e outros recursos de documentação online em:
<http://www.gnu.org/software/gdb/documentation/>.
Para ajuda, digite "help".
Digite "apropos word" para procurar comandos relacionados a "word"...
Lendo símbolos de /github/workspace/bin/static/nginx...feito.
(gdb)

A partir do prompt do gdb, direcione o processo valgrind e comece a depuração:

(gdb) target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=15
Depuração remota usando | /usr/lib64/valgrind/../../bin/vgdb --pid=15
revezando dados entre gdb e o processo 15
aviso: o alvo remoto não suporta transferência de arquivos, tentando acessar arquivos do sistema de arquivos local.
Lendo símbolos de /lib64/ld-linux-x86-64.so.2...(nenhum símbolo de depuração encontrado)...feito.
0x0000000004000ef0 in _start () from /lib64/ld-linux-x86-64.so.2
Faltando informações de depuração separadas, use: debuginfo-install glibc-2.26-35.amzn2.x86_64
(gdb)

Executando GitHub Actions

Com act, você pode simular o fluxo de trabalho que será executado nos servidores do GitHub assim que você enviar alterações.

Há mais de um trabalho no fluxo de trabalho principal, então você precisa especificar o trabalho de teste ao executar act. Por exemplo, você pode usar este comando para executar a validação de formatação do código:

act -vj lint

Observe que o trabalho lint não formata seu código, ele apenas verifica se a formatação está conforme o esperado.

Além disso, note que -v é usado para habilitar o modo verbose para dar mais visibilidade sobre tudo que o act está fazendo.

Os trabalhos que você pode (e deve) executar localmente são lint, build, analyse e test. O trabalho test depende da saída do trabalho build. Para manter a saída do trabalho de construção, você pode adicionar a flag -b ao act, ou pode simplesmente usar o executor de tarefas para construir.

Problemas Conhecidos

No momento? Nenhum! 🎉

Se você descobrir um bug ou tiver uma pergunta a fazer, por favor abra uma issue.

Autor Original

wdaike wdaike@163.com (https://github.com/wdaike), Baidu Inc.

GitHub

Você pode encontrar dicas de configuração adicionais e documentação para este módulo no repositório do GitHub para nginx-module-upstream-jdomain.