【问题标题】:How to use Traefik and Envoy in the same project to handle grpc-web?如何在同一个项目中使用 Traefik 和 Envoy 来处理 grpc-web?
【发布时间】:2020-01-14 11:33:54
【问题描述】:

我在 grpc.mydomain.com 上使用 LetsEncrypt 在 traefik 上启动并运行了一项服务。但是,由于 CORS (https://github.com/containous/traefik/issues/4210) 的一些问题,traefik 不支持路由 grpc-web 请求。 Envoy 似乎是与 grpc-web 一起使用的 traefik 的替代品,但我不想重新配置所有内容。

如果我将 envoy 放在 envoy.mydomain.com 上,那么它实际上会首先命中 traefik,并且 traefik 无法将 grpc-web 请求路由到 envoy。所以这行不通。

如果我将 envoy 放在 traefik (mydomain.com:9091) 之外,则 envoy 没有 traefik 所具有的 TLS 支持。

我需要将所有东西都切换到 envoy 吗?有没有我没有考虑过的替代方案?欢迎任何指导:)

当前 Traefik 设置:

  traefik:
    image: traefik:v2.0.0
    container_name: traefik
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --entrypoints.grpc.address=:8090
      - --providers.docker
      - --api
      - --serversTransport.rootCAs=/certs/grpc.cert
      # Lets Encrypt Resolvers
      - --certificatesresolvers.leresolver.acme.email=${EMAIL}
      - --certificatesresolvers.leresolver.acme.storage=/etc/acme/cert.json
      - --certificatesresolvers.leresolver.acme.tlschallenge=${TLS_CHALLENGE}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/acme/:/etc/acme/
      - ./secrets/grpc.cert:/certs/grpc.cert
    # Dynamic Configuration
    labels:
      # Dashboard
      - "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.tls.certresolver=leresolver"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.middlewares=authtraefik"

      # https://docs.traefik.io/middlewares/basicauth/
      # password generated from `echo $(htpasswd -nb admin $PASSWORD) | sed -e s/\\$/\\$\\$/g`
      - "traefik.http.middlewares.authtraefik.basicauth.users=admin:$$apr1$$6VzI3S0N$$29FC82dYEbjFN9tPSfWLX1"

      # global redirect to https
      - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"

      # middleware redirect
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
    ports:
      - 80:80
      - 443:443
      - 8090:8090
    networks:
      - internal
      - proxied

  grpc_server:
    image: ${GRPC_IMAGE}
    container_name: grpc_server
    volumes:
      - /tmp/keyset.json:/tmp/keyset.json
      - ./secrets/:/secrets/
    working_dir: /app/__main__/
    labels:
      - "traefik.http.routers.combined_server.rule=Host(`grpc.${DOMAIN}`)"
      - "traefik.http.routers.combined_server.entrypoints=grpc"
      - "traefik.http.routers.combined_server.tls=true"
      - "traefik.http.routers.combined_server.tls.certresolver=leresolver"
      # http
      - "traefik.http.services.grpc-svc.loadbalancer.server.scheme=h2c"
      - "traefik.http.services.grpc-svc.loadbalancer.server.port=8090"
    expose:
      - 8090
    networks:
      - internal
      - proxied

我也尝试设置这些以修复 CORS 错误,但无济于事。

      - "traefik.http.middlewares.testheader.headers.accesscontrolallowmethods=GET,PUT,DELETE,POST,OPTIONS"
      - "traefik.http.middlewares.testheader.headers.accesscontrolallowheaders=keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout"
      - "traefik.http.middlewares.testheader.headers.accesscontrolmaxage=100"
      - "traefik.http.middlewares.testheader.headers.addvaryheader=true"
      - "traefik.http.middlewares.testheader.headers.alloworigin=*"

【问题讨论】:

    标签: traefik envoyproxy grpc-web


    【解决方案1】:

    解决此问题的一种方法是使用 2 个不同的 URL,它们最初都由 traefik 处理。一个 URL 用于“直接 grpc”(grpc.mydomain.com),另一个用于 grpc-web(我们称之为 grpc-web.mydomain.com)。 Traefik 对两者都进行 TLS 终止。

    grpc.mydomain.com 流量直接传递给运行 grpc_server 的容器。 grpc-web.mydomain.com 流量被传递给充当 grpc-web-proxy 的 envoy,然后将流量传递给 grpc_server。

    所以当你使用 docker-compose 时,你需要在你的 docker-compose.yml 中添加一个 envoy 服务:

    ---
    version: '3'
    services:
      traefik:
        # traefik configuration from your question
        # ...
       grpc-server:
        # grpc_server configuration from your question
        # ...
      envoy:
        image: envoyproxy/envoy:v1.14.1
        restart: unless-stopped
        volumes:
          - ./envoy.yaml:/etc/envoy/envoy.yaml
        labels:
          - traefik.enable=true
          - traefik.http.routers.envoy.rule=Host(`grpc-web.mydomain.com`)
          - traefik.http.services.envoy.loadbalancer.server.port=8080
          - traefik.http.routers.envoy.tls=true
          - traefik.http.routers.envoy.tls.certresolver=leresolver
    

    envoy.yaml 配置(安装在上面的卷部分)如下所示:

    admin:
      access_log_path: /tmp/admin_access.log
      address:
        socket_address: { address: 0.0.0.0, port_value: 9901 }
    
    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: local_service
                          domains: ["*"]
                          routes:
                            - match: { prefix: "/" }
                              route:
                                cluster: grpc_service
                                max_grpc_timeout: 0s
                          cors:
                            allow_origin_string_match:
                              - prefix: "*"
                            allow_methods: GET, PUT, DELETE, POST, OPTIONS
                            allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
                            max_age: "1728000"
                            expose_headers: custom-header-1,grpc-status,grpc-message
                    http_filters:
                      - name: envoy.grpc_web
                      - name: envoy.cors
                      - name: envoy.router
      clusters:
        - name: grpc_service
          connect_timeout: 0.25s
          type: logical_dns
          http2_protocol_options: {}
          lb_policy: round_robin
          hosts: [{ socket_address: { address: grpc-server, port_value: 8090 }}]
    

    这是 envoy 的一个非常基本的 grpc-web 配置。需要注意的重要部分是我们在“grpc_service”集群配置的配置中将address: grpc-server, port_value: 8090 设置为docker-compose.yml 中的服务名称和您的grpc-server 正在侦听的端口。请注意,我将您的服务从 grpc_server 重命名为 grpc-server,因为下划线不是主机名中的有效字符。

    在客户端,使用:

    • “grpc-web.mydomain.com”在您的 javascript (grpc-web) 代码中。
    • “grpc.mydomain.com”在用另一种语言(例如 golang)编写客户端时。

    我创建了一个工作示例,可以在以下位置找到:https://github.com/rbicker/greeter

    【讨论】:

      【解决方案2】:

      如果您想摆脱 envoy 中已弃用的警告,您可以使用这三个更改更新 envoy.yaml from this answer:

      1. 替换:
                  - name: envoy.http_connection_manager
                    config:
      

      与:

                  - name: envoy.filters.network.http_connection_manager
                    typed_config:
                      "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
      
      1. 替换
                        - name: envoy.grpc_web
                        - name: envoy.cors
                        - name: envoy.router
      

      与

                        - name: envoy.filters.http.grpc_web
                        - name: envoy.filters.http.cors
                        - name: envoy.filters.http.router
      
      1. 替换
      hosts: [{ socket_address: { address: grpc-server, port_value: 8090 }}]
      

      与

            load_assignment:
              cluster_name: cluster_0
              endpoints:
                - lb_endpoints:
                    - endpoint:
                        address:
                          socket_address:
                            address: grpc-server
                            port_value: 8090
      

      【讨论】:

        猜你喜欢
        • 2021-12-02
        • 2020-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多