Migração do Nginx para o Envoy Proxy

Olá, Habr! Chamo a sua atenção para uma tradução do post: Migração do Nginx para o Envoy Proxy.

Envoy é um servidor proxy distribuído de alto desempenho (escrito em C++) projetado para serviços e aplicativos individuais, é também um barramento de comunicação e “plano de dados universal” projetado para grandes arquiteturas de “malha de serviço” de microsserviços. Ao criá-lo, foram levadas em consideração soluções para problemas que surgiram durante o desenvolvimento de servidores como NGINX, HAProxy, balanceadores de carga de hardware e balanceadores de carga em nuvem. O Envoy trabalha junto com cada aplicativo e abstrai a rede para fornecer funcionalidades comuns, independentemente da plataforma. Quando todo o tráfego de serviço em uma infraestrutura flui pela malha do Envoy, fica fácil visualizar áreas problemáticas com observabilidade consistente, ajustar o desempenho geral e adicionar funcionalidades essenciais em um local específico.

Capacidades

  • Arquitetura fora de processo: o envoy é um servidor independente e de alto desempenho que ocupa uma pequena quantidade de RAM. Funciona em conjunto com qualquer linguagem ou estrutura de aplicativo.
  • Suporte http/2 e grpc: o envoy possui suporte http/2 e grpc de primeira classe para conexões de entrada e saída. Este é um proxy transparente de http/1.1 para http/2.
  • Balanceamento de carga avançado: o envoy oferece suporte a recursos avançados de balanceamento de carga, incluindo novas tentativas automáticas, quebra de cadeia, limitação de taxa global, sombreamento de solicitação, balanceamento de carga de zona local, etc.
  • API de gerenciamento de configuração: envoy fornece uma API robusta para gerenciar dinamicamente sua configuração.
  • Observabilidade: Observabilidade profunda do tráfego L7, suporte nativo para rastreamento distribuído e observabilidade de mongodb, dynamodb e muitos outros aplicativos.

Passo 1 — Exemplo de configuração NGINX

Este script usa um arquivo especialmente criado nginx.conf, com base no exemplo completo de Wiki NGINX. Você pode visualizar a configuração no editor abrindo nginx.conf

configuração de origem nginx

user  www www;
pid /var/run/nginx.pid;
worker_processes  2;

events {
  worker_connections   2000;
}

http {
  gzip on;
  gzip_min_length  1100;
  gzip_buffers     4 8k;
  gzip_types       text/plain;

  log_format main      '$remote_addr - $remote_user [$time_local]  '
    '"$request" $status $bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '"$gzip_ratio"';

  log_format download  '$remote_addr - $remote_user [$time_local]  '
    '"$request" $status $bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '"$http_range" "$sent_http_content_range"';

  upstream targetCluster {
    172.18.0.3:80;
    172.18.0.4:80;
  }

  server {
    listen        8080;
    server_name   one.example.com  www.one.example.com;

    access_log   /var/log/nginx.access_log  main;
    error_log  /var/log/nginx.error_log  info;

    location / {
      proxy_pass         http://targetCluster/;
      proxy_redirect     off;

      proxy_set_header   Host             $host;
      proxy_set_header   X-Real-IP        $remote_addr;
    }
  }
}

As configurações do NGINX normalmente têm três elementos principais:

  1. Configurando o servidor NGINX, estrutura de log e funcionalidade Gzip. Isto é definido globalmente em todos os casos.
  2. Configurando o NGINX para aceitar solicitações ao host um.exemplo.com na porta 8080.
  3. Configurando o local de destino, como lidar com o tráfego para diferentes partes do URL.

Nem todas as configurações serão aplicadas ao Envoy Proxy e você não precisa definir algumas configurações. O Envoy Proxy tem quatro tipos principais, que suportam a infraestrutura principal oferecida pelo NGINX. O núcleo é:

  • Ouvintes: Eles determinam como o Envoy Proxy aceita solicitações recebidas. Atualmente, o Envoy Proxy oferece suporte apenas a ouvintes baseados em TCP. Depois que uma conexão é estabelecida, ela é passada para um conjunto de filtros para processamento.
  • Filtros: Eles fazem parte de uma arquitetura de pipeline que pode processar dados de entrada e saída. Essa funcionalidade inclui filtros como o Gzip, que compacta os dados antes de enviá-los ao cliente.
  • Roteadores: Eles encaminham o tráfego para o destino necessário, definido como um cluster.
  • Aglomerados: Eles definem o endpoint para parâmetros de tráfego e configuração.

Usaremos esses quatro componentes para criar uma configuração do Envoy Proxy que corresponda a uma configuração específica do NGINX. O objetivo do Envoy é trabalhar com APIs e configuração dinâmica. Nesse caso, a configuração básica usará configurações estáticas e codificadas do NGINX.

Etapa 2 - Configuração NGINX

A primeira parte nginx.conf define alguns componentes internos do NGINX que precisam ser configurados.

Conexões de Trabalhador

A configuração abaixo determina o número de processos de trabalho e conexões. Isso indica como o NGINX será dimensionado para atender à demanda.

worker_processes  2;

events {
  worker_connections   2000;
}

O Envoy Proxy gerencia fluxos de trabalho e conexões de diferentes maneiras.

O Envoy cria um thread de trabalho para cada thread de hardware no sistema. Cada thread de trabalho executa um loop de eventos sem bloqueio que é responsável por

  1. Ouvindo cada ouvinte
  2. Aceitando novas conexões
  3. Criando um conjunto de filtros para uma conexão
  4. Processe todas as operações de E/S durante a vida útil da conexão.

Todo o processamento adicional da conexão é tratado inteiramente no thread de trabalho, incluindo qualquer comportamento de encaminhamento.

Para cada thread de trabalho no Envoy, há um pool de conexões. Portanto, os pools de conexões HTTP/2 estabelecem apenas uma conexão por host externo por vez; se houver quatro threads de trabalho, haverá quatro conexões HTTP/2 por host externo em um estado estável. Ao manter tudo em um thread de trabalho, quase todo o código pode ser escrito sem bloqueio, como se fosse um thread único. Se mais threads de trabalho forem alocados do que o necessário, isso poderá levar ao desperdício de memória, criando um grande número de conexões ociosas e reduzindo o número de vezes que as conexões são retornadas ao pool.

Para mais informações visite Blog do proxy do enviado.

Configuração HTTP

O seguinte bloco de configuração NGINX define configurações HTTP como:

  • Quais tipos MIME são suportados
  • Tempos limite padrão
  • Configuração Gzip

Você pode personalizar esses aspectos usando filtros no Envoy Proxy, que discutiremos mais tarde.

Passo 3 - Configuração do Servidor

No bloco de configuração HTTP, a configuração NGINX especifica escutar na porta 8080 e responder às solicitações recebidas de domínios um.exemplo.com и www.one.example.com.

 server {
    listen        8080;
    server_name   one.example.com  www.one.example.com;

Dentro do Envoy, ele é controlado por Ouvintes.

Ouvintes enviados

O aspecto mais importante para começar a usar o Envoy Proxy é definir seus ouvintes. Você precisa criar um arquivo de configuração que descreva como deseja executar a instância do Envoy.

O trecho abaixo criará um novo ouvinte e o vinculará à porta 8080. A configuração informa ao Envoy Proxy a quais portas ele deve se vincular para solicitações recebidas.

O Envoy Proxy usa notação YAML para sua configuração. Para uma introdução a esta notação, veja aqui link.

Copy to Editorstatic_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }

Não há necessidade de definir nome do servidor, já que os filtros do Envoy Proxy cuidarão disso.

Passo 4 - Configuração do Local

Quando uma solicitação chega ao NGINX, o bloco de localização determina como processar e para onde rotear o tráfego. No fragmento a seguir, todo o tráfego para o site é transferido para um cluster upstream (nota do tradutor: o upstream geralmente é um servidor de aplicativos) chamado targetCluster. O cluster upstream define os nós que devem processar a solicitação. Discutiremos isso na próxima etapa.

location / {
    proxy_pass         http://targetCluster/;
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
}

No Envoy, a Filters faz isso.

Filtros de enviado

Para uma configuração estática, os filtros determinam como processar as solicitações recebidas. Neste caso, definimos filtros que correspondem nomes_do_servidor na etapa anterior. Quando chegam solicitações de entrada que correspondem a determinados domínios e rotas, o tráfego é roteado para o cluster. Isso é equivalente a uma configuração ascendente do NGINX.

Copy to Editor    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "one.example.com"
                - "www.one.example.com"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router

nome enviado.http_connection_manager é um filtro integrado no Envoy Proxy. Outros filtros incluem Redis, Mongo, TCP. Você pode encontrar a lista completa em documentação.

Para obter mais informações sobre outras políticas de balanceamento de carga, visite Documentação do enviado.

Etapa 5 - Configuração de proxy e upstream

No NGINX, a configuração upstream define um conjunto de servidores de destino que processarão o tráfego. Neste caso, dois clusters foram atribuídos.

  upstream targetCluster {
    172.18.0.3:80;
    172.18.0.4:80;
  }

No Envoy, isso é gerenciado por clusters.

Clusters de Enviados

O equivalente upstream é definido como clusters. Neste caso, os hosts que servirão o tráfego foram identificados. A forma como os hosts são acessados, como os tempos limite, é definida como uma configuração de cluster. Isso permite um controle mais granular sobre aspectos como latência e balanceamento de carga.

Copy to Editor  clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.18.0.3, port_value: 80 }},
      { socket_address: { address: 172.18.0.4, port_value: 80 }}
    ]

Ao usar a descoberta de serviço STRICT_DNS O Envoy resolverá de forma contínua e assíncrona os alvos DNS especificados. Cada endereço IP retornado do resultado DNS será considerado um host explícito no cluster upstream. Isso significa que se uma solicitação retornar dois endereços IP, o Envoy assumirá que há dois hosts no cluster e ambos devem ter carga balanceada. Se um host for removido do resultado, o Envoy assumirá que ele não existe mais e extrairá tráfego de qualquer pool de conexões existente.

Para mais informações, veja Documentação do proxy enviado.

Passo 6 — Acesso ao log e erros

A configuração final é o registro. Em vez de enviar logs de erros para o disco, o Envoy Proxy adota uma abordagem baseada em nuvem. Todos os logs do aplicativo são enviados para stdout и stderr.

Quando os usuários fazem uma solicitação, os logs de acesso são opcionais e desabilitados por padrão. Para habilitar logs de acesso para solicitações HTTP, habilite a configuração log_de acesso para o gerenciador de conexões HTTP. O caminho pode ser um dispositivo como stdoutou um arquivo em disco, dependendo dos seus requisitos.

A configuração a seguir redirecionará todos os logs de acesso para stdout (nota do tradutor - stdout é necessário para usar o envoy dentro do docker. Se usado sem o docker, substitua /dev/stdout pelo caminho para um arquivo de log normal). Copie o snippet para a seção de configuração do gerenciador de conexões:

Copy to Clipboardaccess_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"

Os resultados devem ser assim:

      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          access_log:
          - name: envoy.file_access_log
            config:
              path: "/dev/stdout"
          route_config:

Por padrão, o Envoy possui uma string de formato que inclui os detalhes da solicitação HTTP:

[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n

O resultado desta string de formato é:

[2018-11-23T04:51:00.281Z] "GET / HTTP/1.1" 200 - 0 58 4 1 "-" "curl/7.47.0" "f21ebd42-6770-4aa5-88d4-e56118165a7d" "one.example.com" "172.18.0.4:80"

O conteúdo de saída pode ser personalizado definindo o campo de formato. Por exemplo:

access_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"
    format: "[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n"

A linha de log também pode ser gerada no formato JSON definindo o campo formato_json. Por exemplo:

access_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"
    json_format: {"protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%"}

Para obter mais informações sobre a Metodologia de Registro de Enviados, visite

https://www.envoyproxy.io/docs/envoy/latest/configuration/access_log#config-access-log-format-dictionaries

O registro em log não é a única maneira de obter informações sobre como trabalhar com o Envoy Proxy. Possui recursos avançados de rastreamento e métricas integrados. Você pode saber mais em documentação de rastreamento ou através Script de rastreamento interativo.

Passo 7 - Lançamento

Agora você migrou sua configuração do NGINX para o Envoy Proxy. A última etapa é iniciar uma instância do Envoy Proxy para testá-la.

Executar como usuário

No topo da linha de configuração do NGINX usuário www www; especifica a execução do NGINX como um usuário com poucos privilégios para melhorar a segurança.

O Envoy Proxy adota uma abordagem baseada em nuvem para gerenciar quem é o proprietário de um processo. Quando executamos o Envoy Proxy por meio de um contêiner, podemos especificar um usuário com poucos privilégios.

Lançando o proxy Envoy

O comando abaixo executará o Envoy Proxy por meio de um contêiner Docker no host. Este comando dá ao Envoy a capacidade de escutar solicitações de entrada na porta 80. No entanto, conforme especificado na configuração do ouvinte, o Envoy Proxy escuta o tráfego de entrada na porta 8080. Isso permite que o processo seja executado como um usuário com poucos privilégios.

docker run --name proxy1 -p 80:8080 --user 1000:1000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy

Teste

Com o proxy em execução, os testes já podem ser feitos e processados. O comando cURL a seguir emite uma solicitação com o cabeçalho do host definido na configuração do proxy.

curl -H "Host: one.example.com" localhost -i

A solicitação HTTP resultará em um erro 503. Isso ocorre porque as conexões upstream não estão funcionando e não estão disponíveis. Portanto, o Envoy Proxy não possui destinos disponíveis para a solicitação. O comando a seguir iniciará uma série de serviços HTTP que correspondem à configuração definida para o Envoy.

docker run -d katacoda/docker-http-server; docker run -d katacoda/docker-http-server;

Com os serviços disponíveis, o Envoy pode fazer proxy do tráfego para seu destino com sucesso.

curl -H "Host: one.example.com" localhost -i

Você deverá ver uma resposta indicando qual contêiner do Docker processou a solicitação. Nos logs do Envoy Proxy, você também deverá ver uma saída de string de acesso.

Cabeçalhos de resposta HTTP adicionais

Você verá cabeçalhos HTTP adicionais nos cabeçalhos de resposta da solicitação real. O cabeçalho exibe o tempo que o host upstream gastou processando a solicitação. Expresso em milissegundos. Isto é útil se o cliente quiser determinar o tempo de serviço em comparação com a latência da rede.

x-envoy-upstream-service-time: 0
server: envoy

Configuração final

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "one.example.com"
                - "www.one.example.com"
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router
          clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.18.0.3, port_value: 80 }},
      { socket_address: { address: 172.18.0.4, port_value: 80 }}
    ]

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9090 }

Informações adicionais do tradutor

Instruções para instalar o Envoy Proxy podem ser encontradas no site https://www.getenvoy.io/

Por padrão, rpm não possui uma configuração de serviço systemd.

Adicione a configuração do serviço systemd /etc/systemd/system/envoy.service:

[Unit]
Description=Envoy Proxy
Documentation=https://www.envoyproxy.io/
After=network-online.target
Requires=envoy-auth-server.service
Wants=nginx.service

[Service]
User=root
Restart=on-failure
ExecStart=/usr/bin/envoy --config-path /etc/envoy/config.yaml
[Install]
WantedBy=multi-user.target

Você precisa criar um diretório /etc/envoy/ e colocar a configuração config.yaml lá.

Há um bate-papo por telegrama usando proxy enviado: https://t.me/envoyproxy_ru

O Envoy Proxy não oferece suporte ao fornecimento de conteúdo estático. Portanto, quem pode votar no recurso: https://github.com/envoyproxy/envoy/issues/378

Apenas usuários registrados podem participar da pesquisa. Entrarpor favor

Esta postagem encorajou você a instalar e testar o proxy enviado?

  • sim

  • não

75 usuários votaram. 18 usuários se abstiveram.

Fonte: habr.com

Adicionar um comentário