Migración de Nginx a Envoy Proxy

¡Hola Habr! Les traigo una traducción del post: Migración de Nginx a Envoy Proxy.

Envoy es un servidor proxy distribuido de alto rendimiento (escrito en C++) diseñado para servicios y aplicaciones individuales, también es un bus de comunicación y un "plano de datos universal" diseñado para grandes arquitecturas de "malla de servicios" de microservicios. Al crearlo se tuvieron en cuenta soluciones a problemas que surgieron durante el desarrollo de servidores como NGINX, HAProxy, balanceadores de carga de hardware y balanceadores de carga en la nube. Envoy trabaja junto con cada aplicación y abstrae la red para proporcionar una funcionalidad común independientemente de la plataforma. Cuando todo el tráfico de servicios en una infraestructura fluye a través de la malla de Envoy, resulta fácil visualizar áreas problemáticas con observabilidad consistente, ajustar el rendimiento general y agregar funcionalidad central en una ubicación específica.

oportunidades

  • Arquitectura fuera de proceso: envoy es un servidor autónomo de alto rendimiento que ocupa una pequeña cantidad de RAM. Funciona en conjunto con cualquier lenguaje o marco de aplicación.
  • Compatibilidad con http/2 y grpc: envoy tiene compatibilidad con http/2 y grpc de primera clase para conexiones entrantes y salientes. Este es un proxy transparente de http/1.1 a http/2.
  • Equilibrio de carga avanzado: envoy admite funciones avanzadas de equilibrio de carga que incluyen reintentos automáticos, interrupción de cadena, limitación de velocidad global, seguimiento de solicitudes, equilibrio de carga de zona local, etc.
  • API de gestión de configuración: envoy proporciona una API sólida para gestionar dinámicamente su configuración.
  • Observabilidad: observabilidad profunda del tráfico L7, soporte nativo para seguimiento distribuido y observabilidad de mongodb, dynamodb y muchas otras aplicaciones.

Paso 1: ejemplo de configuración de NGINX

Este script utiliza un archivo especialmente diseñado nginx.conf, basado en el ejemplo completo de Wiki NGINX. Puede ver la configuración en el editor abriendo nginx.conf

configuración de fuente 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;
    }
  }
}

Las configuraciones de NGINX suelen tener tres elementos clave:

  1. Configuración del servidor NGINX, estructura de registros y funcionalidad Gzip. Esto se define globalmente en todos los casos.
  2. Configurar NGINX para aceptar solicitudes al host uno.ejemplo.com en el puerto 8080.
  3. Configurar la ubicación de destino, cómo manejar el tráfico para diferentes partes de la URL.

No todas las configuraciones se aplicarán a Envoy Proxy y no es necesario configurar algunas configuraciones. Envoy Proxy tiene cuatro tipos de claves, que respaldan la infraestructura central ofrecida por NGINX. El núcleo es:

  • Oyentes: Determinan cómo Envoy Proxy acepta las solicitudes entrantes. Actualmente, Envoy Proxy solo admite escuchas basadas en TCP. Una vez que se establece una conexión, se pasa a un conjunto de filtros para su procesamiento.
  • Filtros: Son parte de una arquitectura de canalización que puede procesar datos entrantes y salientes. Esta funcionalidad incluye filtros como Gzip, que comprime los datos antes de enviarlos al cliente.
  • Enrutadores: Reenvían el tráfico al destino requerido, definido como un clúster.
  • Grupos: Definen el punto final para el tráfico y los parámetros de configuración.

Usaremos estos cuatro componentes para crear una configuración de Envoy Proxy que coincida con una configuración NGINX específica. El objetivo de Envoy es trabajar con API y configuración dinámica. En este caso, la configuración base utilizará configuraciones estáticas codificadas de NGINX.

Paso 2: configuración de NGINX

La primera parte nginx.conf define algunos componentes internos de NGINX que deben configurarse.

Conexiones de trabajadores

La siguiente configuración determina la cantidad de procesos y conexiones de trabajo. Esto indica cómo NGINX escalará para satisfacer la demanda.

worker_processes  2;

events {
  worker_connections   2000;
}

Envoy Proxy gestiona flujos de trabajo y conexiones de diferentes maneras.

Envoy crea un subproceso de trabajo para cada subproceso de hardware del sistema. Cada hilo de trabajo ejecuta un bucle de eventos sin bloqueo que es responsable de

  1. Escuchando a cada oyente
  2. Aceptar nuevas conexiones
  3. Crear un conjunto de filtros para una conexión
  4. Procese todas las operaciones de E/S durante la vida útil de la conexión.

Todo el procesamiento de conexión adicional se maneja completamente en el subproceso de trabajo, incluido cualquier comportamiento de reenvío.

Para cada subproceso de trabajo en Envoy, hay una conexión en el grupo. Por lo tanto, los grupos de conexiones HTTP/2 solo establecen una conexión por host externo a la vez; si hay cuatro subprocesos de trabajo, habrá cuatro conexiones HTTP/2 por host externo en un estado estable. Al mantener todo en un subproceso de trabajo, casi todo el código se puede escribir sin bloqueo, como si fuera de un solo subproceso. Si se asignan más subprocesos de trabajo de los necesarios, esto puede generar un desperdicio de memoria, lo que crea una gran cantidad de conexiones inactivas y reduce la cantidad de veces que las conexiones se devuelven al grupo.

Para más información visite Blog de proxy enviado.

Configuración HTTP

El siguiente bloque de configuración de NGINX define configuraciones HTTP como:

  • ¿Qué tipos de mime son compatibles?
  • Tiempos de espera predeterminados
  • Configuración Gzip

Puede personalizar estos aspectos utilizando filtros en Envoy Proxy, que analizaremos más adelante.

Paso 3: configuración del servidor

En el bloque de configuración HTTP, la configuración de NGINX especifica escuchar en el puerto 8080 y responder a las solicitudes entrantes de dominios. uno.ejemplo.com и www.one.ejemplo.com.

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

Dentro de Envoy, está controlado por oyentes.

Oyentes enviados

El aspecto más importante al empezar a utilizar Envoy Proxy es definir a sus oyentes. Debe crear un archivo de configuración que describa cómo desea ejecutar la instancia de Envoy.

El siguiente fragmento creará un nuevo oyente y lo vinculará al puerto 8080. La configuración le indica a Envoy Proxy a qué puertos debe vincularse para las solicitudes entrantes.

Envoy Proxy utiliza la notación YAML para su configuración. Para una introducción a esta notación, mire aquí enlace.

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

No es necesario definir nombre del servidor, ya que los filtros de Envoy Proxy se encargarán de esto.

Paso 4: Configuración de la ubicación

Cuando llega una solicitud a NGINX, el bloque de ubicación determina cómo procesar y dónde enrutar el tráfico. En el siguiente fragmento, todo el tráfico al sitio se transfiere a un clúster ascendente (nota del traductor: el ascendente suele ser un servidor de aplicaciones) llamado objetivoClúster. El clúster ascendente define los nodos que deben procesar la solicitud. Discutiremos esto en el siguiente paso.

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

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

En Envoy, Filters hace esto.

Filtros de enviado

Para una configuración estática, los filtros determinan cómo procesar las solicitudes entrantes. En este caso configuramos filtros que coinciden nombres_servidor en el paso anterior. Cuando llegan solicitudes entrantes que coinciden con ciertos dominios y rutas, el tráfico se dirige al clúster. Este es el equivalente a una configuración ascendente de 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

nombre enviado.http_connection_manager es un filtro incorporado en Envoy Proxy. Otros filtros incluyen Redis, Mongo, TCP. Puedes encontrar la lista completa en documentación.

Para obtener más información sobre otras políticas de equilibrio de carga, visite Documentación del enviado.

Paso 5: configuración de proxy y ascendente

En NGINX, la configuración ascendente define un conjunto de servidores de destino que procesarán el tráfico. En este caso se asignaron dos grupos.

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

En Envoy, esto se gestiona mediante clústeres.

Grupos de enviados

El equivalente ascendente se define como clústeres. En este caso, se han identificado los hosts que atenderán el tráfico. La forma en que se accede a los hosts, como los tiempos de espera, se define como una configuración de clúster. Esto permite un control más granular sobre aspectos como la latencia y el equilibrio 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 }}
    ]

Al utilizar el descubrimiento de servicios STRICT_DNS Envoy resolverá de forma continua y asincrónica los objetivos DNS especificados. Cada dirección IP devuelta por el resultado DNS se considerará un host explícito en el clúster ascendente. Esto significa que si una solicitud devuelve dos direcciones IP, Envoy asumirá que hay dos hosts en el clúster y que ambos deben tener equilibrio de carga. Si se elimina un host del resultado, Envoy asumirá que ya no existe y extraerá el tráfico de cualquier grupo de conexiones existente.

Para más información, ver Documentación del proxy enviado.

Paso 6: acceso al registro y errores

La configuración final es el registro. En lugar de enviar registros de errores al disco, Envoy Proxy adopta un enfoque basado en la nube. Todos los registros de la aplicación se envían a stdout и stderr.

Cuando los usuarios realizan una solicitud, los registros de acceso son opcionales y están deshabilitados de forma predeterminada. Para habilitar los registros de acceso para solicitudes HTTP, habilite la configuración registro_acceso para el administrador de conexiones HTTP. La ruta puede ser un dispositivo como stdout, o un archivo en el disco, según sus requisitos.

La siguiente configuración redirigirá todos los registros de acceso a stdout (Nota del traductor: se requiere stdout para usar envoy dentro de Docker. Si se usa sin Docker, reemplace /dev/stdout con la ruta a un archivo de registro normal). Copie el fragmento en la sección de configuración del administrador de conexiones:

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

Los resultados deberían verse así:

      - 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:

De forma predeterminada, Envoy tiene una cadena de formato que incluye los detalles de la solicitud 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

El resultado de esta cadena de formato es:

[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"

El contenido de salida se puede personalizar configurando el campo de formato. Por ejemplo:

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"

La línea de registro también se puede generar en formato JSON configurando el campo formato_json. Por ejemplo:

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

Para obtener más información sobre la Metodología de registro de enviados, visite

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

El registro no es la única forma de obtener información sobre cómo trabajar con Envoy Proxy. Tiene capacidades avanzadas de seguimiento y métricas integradas. Puedes obtener más información en documentación de rastreo o por medio de Script de rastreo interactivo.

Paso 7 - Lanzar

Ahora ha migrado su configuración de NGINX a Envoy Proxy. El último paso es iniciar una instancia de Envoy Proxy para probarla.

Ejecutar como usuario

En la parte superior de la línea de configuración de NGINX usuario www www; especifica ejecutar NGINX como un usuario con pocos privilegios para mejorar la seguridad.

Envoy Proxy adopta un enfoque basado en la nube para gestionar quién es el propietario de un proceso. Cuando ejecutamos Envoy Proxy a través de un contenedor, podemos especificar un usuario con pocos privilegios.

Lanzamiento del proxy Envoy

El siguiente comando ejecutará Envoy Proxy a través de un contenedor Docker en el host. Este comando le da a Envoy la capacidad de escuchar solicitudes entrantes en el puerto 80. Sin embargo, como se especifica en la configuración del oyente, Envoy Proxy escucha el tráfico entrante en el puerto 8080. Esto permite que el proceso se ejecute como un usuario con pocos privilegios.

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

pruebas

Con el proxy en ejecución, ahora se pueden realizar y procesar pruebas. El siguiente comando cURL emite una solicitud con el encabezado del host definido en la configuración del proxy.

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

La solicitud HTTP resultará en un error. 503. Esto se debe a que las conexiones ascendentes no funcionan y no están disponibles. Por lo tanto, Envoy Proxy no tiene destinos disponibles para la solicitud. El siguiente comando iniciará una serie de servicios HTTP que coinciden con la configuración definida para Envoy.

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

Con los servicios disponibles, Envoy puede enviar con éxito el tráfico a su destino.

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

Debería ver una respuesta que indique qué contenedor Docker procesó la solicitud. En los registros de Envoy Proxy también debería ver una salida de cadena de acceso.

Encabezados de respuesta HTTP adicionales

Verá encabezados HTTP adicionales en los encabezados de respuesta de la solicitud real. El encabezado muestra el tiempo que el host ascendente dedicó a procesar la solicitud. Expresado en milisegundos. Esto es útil si el cliente desea determinar el tiempo de servicio en comparación con la latencia de la red.

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

Configuración 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 }

Información adicional del traductor.

Las instrucciones para instalar Envoy Proxy se pueden encontrar en el sitio web https://www.getenvoy.io/

De forma predeterminada, rpm no tiene una configuración de servicio systemd.

Agregue la configuración del servicio 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

Debe crear un directorio /etc/envoy/ y colocar la configuración config.yaml allí.

Hay un chat de Telegram que utiliza el proxy enviado: https://t.me/envoyproxy_ru

Envoy Proxy no admite la publicación de contenido estático. Por lo tanto, ¿quién puede votar por la función? https://github.com/envoyproxy/envoy/issues/378

Solo los usuarios registrados pueden participar en la encuesta. Registrarsepor favor

¿Esta publicación lo animó a instalar y probar el proxy enviado?

  • no

75 usuarios votaron. 18 usuarios se abstuvieron.

Fuente: habr.com

Añadir un comentario