Как использовать Traefik и Envoy в одном проекте для обработки grp c -web? - PullRequest
0 голосов
/ 14 января 2020

У меня есть служба, запущенная на traefik с LetsEncrypt по адресу grp c .mydomain.com. Однако traefik не поддерживает маршрутизацию запроса grp c -web из-за некоторых проблем с CORS (https://github.com/containous/traefik/issues/4210). Похоже, что посланник является альтернативой traefik, который работает с grp c -web, но я не хочу go о перенастройке всего.

Если я поставлю посланника на envoy.mydomain.com, тогда он на самом деле сначала запускает traefik, а traefik не может направить запросы посланника grp c -web. Так что это не работает.

Если я поставлю посланника вне traefik (mydomain.com:9091), то у посланника не будет поддержки TLS, которую имеет traefik.

Нужно ли мне переключить все на посланника? Есть ли альтернатива, которую я не рассматривал? Любое руководство приветствуется:)

Текущая настройка 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=*"

1 Ответ

0 голосов
/ 18 апреля 2020

Способ решения этой проблемы - использование 2 разных URL, которые сначала обрабатываются traefik. Один URL-адрес используется для «direct grp c» (grp c .mydomain.com), другой - для grp c -web (назовем его grp c -web.mydomain.com). Traefik выполняет TLS-завершение для обоих.

Трафик grp c .mydomain.com c напрямую передается в контейнер, в котором запущен grpc_server. Трафик grp c -web.mydomain.com c передается посланнику, который действует как grp c -web-прокси, а затем передает трафик c серверу grpc_server.

Итак так как вы используете docker -compose, вам необходимо добавить службу envoy к вашему docker -compose.yml:

---
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 }}]

Это довольно простой c grp c веб-конфиг для посланника. Важно отметить, что мы установили address: grpc-server, port_value: 8090 в конфигурации кластерной конфигурации "grpc_service" на имя службы из docker -compose.yml и на порт, который прослушивает ваш grp c -сервер. Обратите внимание, что я переименовал ваш сервис из grpc_server в grp c -server, поскольку подчеркивание не является допустимым символом в именах хостов.

На стороне клиента используйте:

  • "grp c -web.mydomain.com "в вашем javascript (grp c -web) коде.
  • " grp c .mydomain.com "при написании клиента на другом языке (например, golang например).

Я создал рабочий пример, который можно найти в: https://github.com/rbicker/greeter

...