Migração do Nginx para o Envoy Proxy

Olá, Habr! Apresento a vocês a tradução de um post: Migração do Nginx para o Envoy Proxy.

Envoy é um proxy distribuído de alto desempenho (escrito em C++) projetado para serviços e aplicativos individuais, além de ser um barramento de comunicação e um 'data plane' universal, desenvolvido para grandes arquiteturas de microserviços 'service mesh'. Na sua criação, foram consideradas soluções para problemas que surgiram ao desenvolver servidores como NGINX, HAProxy, balanceadores de carga de hardware e balanceadores de carga em nuvem. O Envoy trabalha com cada aplicativo e abstrai a rede, fornecendo funções comuns independentemente da plataforma. Quando todo o tráfego de serviço na infraestrutura passa pela rede Envoy, torna-se fácil visualizar áreas problemáticas por meio de uma observabilidade consistente, ajustar o desempenho geral e adicionar funcionalidades essenciais em um determinado ponto.

Recursos

  • Arquitetura fora do processo: o Envoy é um servidor autônomo de alto desempenho que ocupa um pequeno volume de memória. Ele funciona em conjunto com qualquer linguagem de aplicativo ou framework.
  • Suporte a http/2 e grpc: o Envoy tem suporte de primeira classe para http/2 e grpc para conexões de entrada e saída. É um proxy transparente de http/1.1 para http/2.
  • Balanceamento de carga avançado: o Envoy suporta funcionalidades avançadas de balanceamento de carga, incluindo tentativas automáticas, quebra de circuito, limitação de velocidade global, sombreamento de solicitações, balanceamento de carga local por zona, e muito mais.
  • API para gerenciamento de configuração: o Envoy fornece uma API robusta para gerenciamento dinâmico de sua configuração.
  • Observabilidade: observabilidade profunda do tráfego L7, suporte embutido para rastreamento distribuído e observabilidade para mongodb, dynamodb e muitos outros aplicativos.

Passo 1 — Exemplo de configuração do NGINX

Neste cenário, um arquivo especificamente criado é usado nginx.conf, baseado em um exemplo completo do Wiki do NGINX. Você pode visualizar a configuração no editor, abrindo nginx.conf

Configuração original do 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 geralmente têm três elementos principais:

  1. Configuração do servidor NGINX, estrutura dos logs e funcionalidade Gzip. Isso é definido globalmente em todos os casos.
  2. Configuração do NGINX para receber solicitações no host one.example.com na porta 8080.
  3. Configuração do local de destino, como gerenciar o tráfego para diferentes partes da URL.

Nem toda a configuração será aplicada ao Envoy Proxy, e você não precisa configurar alguns parâmetros. O Envoy Proxy possui quatro tipos principais, que suportam a infraestrutura básica oferecida pelo NGINX. O núcleo é:

  • Ouvintes: Eles definem como o Envoy Proxy recebe solicitações de entrada. Atualmente, o Envoy Proxy suporta apenas ouvintes baseados em TCP. Assim que a conexão é estabelecida, ela é passada para um conjunto de filtros para processamento.
  • Filtros: Eles são parte da arquitetura de pipeline que pode processar dados de entrada e saída. Essa funcionalidade inclui filtros, como o Gzip, que comprime os dados antes de enviá-los ao cliente.
  • Roteadores: Eles redirecionam o tráfego para o destino necessário, definido como um cluster.
  • Clusters: Eles definem o ponto final para o tráfego e os parâmetros de configuração.

Usaremos esses quatro componentes para criar a configuração do Envoy Proxy para corresponder a uma configuração específica do NGINX. O objetivo do Envoy é trabalhar com APIs e configuração dinâmica. Neste caso, a configuração básica usará parâmetros estáticos e fixos do NGINX.

Passo 2 — Configuração do NGINX

Primeira parte nginx.conf define alguns componentes internos do NGINX que devem ser configurados.

Worker Connections

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

worker_processes  2;

events {
  worker_connections   2000;
}

O Envoy Proxy gerencia processos de trabalho e conexões de maneira diferente.

O Envoy cria um fluxo de trabalho para cada thread de hardware no sistema. Cada fluxo de trabalho executa um loop de eventos não bloqueante, responsável por

  1. Escutar cada ouvinte (listener)
  2. Aceitar novas conexões
  3. Criar um conjunto de filtros para a conexão
  4. Processar todas as operações de entrada e saída durante a vida útil da conexão.

Todo o processamento adicional da conexão é tratado completamente dentro do fluxo de trabalho, incluindo qualquer comportamento de redirecionamento.

Para cada fluxo de trabalho no Envoy, existe uma conexão no pool. Assim, os pools de conexões HTTP/2 estabelecem apenas uma conexão para cada host externo de cada vez, e com quatro fluxos de trabalho haverá quatro conexões HTTP/2 para cada host externo em um estado estável. Mantendo tudo em um único fluxo de trabalho, quase todo o código pode ser escrito sem bloqueios, como se fosse de thread único. Se mais fluxos de trabalho forem alocados do que o necessário, isso pode levar a um uso ineficiente de memória, à criação de um grande número de conexões ociosas e à diminuição do número de retornos de conexão ao pool.

Para mais informações, visite o blog do Envoy Proxy.

Configuração HTTP

O bloco de configuração NGINX a seguir define as configurações HTTP, como:

  • Quais tipos de mime são suportados
  • Timeouts padrão
  • Configuração Gzip

Você pode ajustar esses aspectos usando filtros no Envoy Proxy, que discutiremos mais adiante.

Passo 3 — Configuração do Servidor

No bloco de configuração HTTP, a configuração NGINX especifica escutar na porta 8080 e responder a solicitações de entrada para os domínios one.example.com e www.one.example.com.

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

Dentro do Envoy, isso é gerenciado pelos Ouvintes.

Ouvintes Envoy

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

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

O Envoy Proxy utiliza a notação YAML para sua configuração. Para se familiarizar com essa notação, veja aqui. o 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 server_name, 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 local define como processar e para onde direcionar o tráfego. No próximo trecho, todo o tráfego do site é encaminhado para um cluster upstream (nota do tradutor: upstream geralmente se refere a servidores de aplicativos) chamado targetCluster. O cluster upstream define os nós que devem processar a solicitação. Vamos discutir 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, isso é tratado pelos Filtros.

Filtros do Envoy

Para configuração estática, os filtros definem como processar as solicitações de entrada. Neste caso, configuramos filtros que correspondem a server_names na etapa anterior. Quando solicitações de entrada correspondem a determinados domínios e rotas, o tráfego é direcionado ao cluster. Isso é equivalente à configuração upstream 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 envoy.http_connection_manager é um filtro embutido no Envoy Proxy. Outros filtros incluem Redis, Mongo, TCP. Você pode encontrar a lista completa em documentação.

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

Passo 5 — Configuração do Proxy e Upstream

No NGINX, a configuração upstream define um conjunto de servidores-alvo que processarão o tráfego. Neste caso, dois clusters foram designados.

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

No Envoy, isso é gerenciado por clusters.

Clusters do Envoy

O equivalente upstream é definido como clusters. Neste caso, foram definidos os hosts que irão gerenciar o tráfego. O método de acesso aos hosts, como o tempo de espera, é definido como a configuração do cluster. Isso permite um controle mais preciso sobre aspectos como tempo de espera e balanceamento de carga.

Copiar para o 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ços STRICT_DNS O Envoy irá resolver continuamente e de forma assíncrona os destinos DNS especificados. Cada endereço IP retornado como resultado da resolução 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 existem dois hosts no cluster e ambos devem ser balanceados. Se um host for removido do resultado, o Envoy presume que ele não existe mais e irá selecionar tráfego de quaisquer pools de conexões existentes.

Para mais informações, veja A documentação do proxy Envoy.

Passo 6 - Acesso ao log e erros

A configuração final - registro. Em vez de gravar logs de erros em disco, o Proxy Envoy usa uma abordagem em nuvem. Todos os logs de aplicativos são enviados para stdout e stderr.

Quando os usuários realizam uma solicitação, os logs de acesso são opcionais e, por padrão, estão desativados. Para ativar os logs de acesso para solicitações HTTP, habilite a configuração access_log para o gerenciador de conexões HTTP. O caminho pode ser um dispositivo, como stdout, ou um arquivo no disco, dependendo das suas necessidades.

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

Copiar para a área de transferênciaaccess_log:
- name: envoy.file_access_log
  config:
    path: "\/dev\/stdout"

Os resultados devem se parecer com isto:

      - 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 tem uma string de formato que inclui 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 da saída pode ser configurado 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 do log também pode ser gerada no formato JSON definindo o campo json_format. 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 do envoy, visite

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

A exploração de logs não é a única maneira de obter uma visão do funcionamento do Envoy Proxy. Ele possui recursos avançados de rastreamento e métricas integrados. Você pode saber mais na documentação sobre rastreamento ou através do Script de rastreamento interativo.

Passo 7 — Execução

Agora você traduziu a configuração do NGINX para o Envoy Proxy. O último passo é executar uma instância do Envoy Proxy para testá-la.

Execução como usuário

Na parte superior da configuração do NGINX, a linha user www www; indica a execução do NGINX sob um usuário com privilégios baixos para aumentar a segurança.

O Envoy Proxy utiliza uma abordagem em nuvem para gerenciar quem é o proprietário do processo. Quando executamos o Envoy Proxy através de um contêiner, podemos especificar um usuário com privilégios baixos.

Executando o Envoy Proxy

O comando abaixo executará o Envoy Proxy através de um contêiner Docker no host. Este comando permite que o Envoy escute 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 privilégios baixos.

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

Testes

Com o proxy em execução, os testes agora podem ser feitos e processados. O próximo comando cURL envia 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 503Isso se deve ao fato de que as conexões ascendentes não estão funcionando e não estão disponíveis. Assim, o Envoy Proxy não tem destinatários disponíveis para a solicitação. O seguinte comando 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 o destino com sucesso.

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

Você deve ver uma resposta indicando qual container Docker processou a solicitação. Nos logs do Envoy Proxy, você também deve ver a linha de acesso gerada.

Cabeçalhos adicionais da resposta HTTP (HTTP Response)

Nos cabeçalhos da resposta da solicitação válida, você verá cabeçalhos HTTP adicionais. No cabeçalho, é exibido o tempo que o host upstream levou para processar a solicitação. É expresso em milissegundos. Isso é útil se o cliente quiser determinar o tempo de atendimento em comparação com a latência na 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ção adicional do tradutor

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

Por padrão, o RPM não possui configuração de serviço do systemd.

Adicione a configuração de serviço do systemd em /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 o diretório /etc/envoy/ e colocar a configuração config.yaml lá.

No chat do Telegram sobre o Envoy Proxy: https://t.me/envoyproxy_ru

O Envoy Proxy não possui suporte para distribuição de conteúdo estático. Portanto, quem puder, vote pela funcionalidade: https://github.com/envoyproxy/envoy/issues/378

Apenas usuários registrados podem participar da pesquisa. Entre, por favor.

Este post incentivou você a instalar e testar o Envoy Proxy?

  • sim

  • não

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

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster