Envoy Deployment


Envoy proxy for Kubernetes & local development

Build Envoy docker image for local development

We can build our envoy image from base envoy docker with minor customization on log level and other env params. This is useful to point envoy to other services running in docker host.

Docker file
FROM envoyproxy/envoy:v1.13.0
RUN apt-get update && apt-get install -y curl iputils-ping net-tools dnsutils nano gettext --no-install-recommends ca-certificates wget pwgen openssl && DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata && ln -fs /usr/share/zoneinfo/America/Los_Angeles /etc/localtime && dpkg-reconfigure --frontend noninteractive tzdata && rm -rf /var/lib/apt/lists/* && apt-get clean
COPY entrypoint.sh /
RUN chmod 500 /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
Entrypoint

We can add a custom entrypoint for docker image. Idea is to pass docker host ip and log level required as env variables and typically envoy.yaml will be mounted from external volume during startup along with environment variables.

#!/bin/sh
set -e

echo "Generating envoy.yaml config file...host ip=>$DOCKER_HOST_IP"
cat /envoyproxy/envoy.yaml | envsubst \$DOCKER_HOST_IP > /envoyproxy/envoy-mod.yaml

echo "Starting Envoy with log level => $ENVOY_LOG_LEVEL"
/usr/local/bin/envoy -c /envoyproxy/envoy-mod.yaml -l $ENVOY_LOG_LEVEL
Sample enovy.yaml
# $DOCKER_HOST_IP, ENVOY_LOG_LEVEL
admin:
  access_log_path: /dev/stdout
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_http
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          use_remote_address: true
          stat_prefix: ingress_http
          access_log:
          - name: envoy.file_access_log
            config:
              path: "/dev/stdout"
              json_format: {"upstream_host": "%UPSTREAM_HOST%", "x-request-id": "%REQ(X-REQUEST-ID)%", "user-agent": "%REQ(USER-AGENT)%", "x-forwared-for": "%REQ(X-FORWARDED-FOR)%", "protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%", "start_time": "%START_TIME%", "response_code": "%RESPONSE_CODE%", "response_flags": "%RESPONSE_FLAGS%", "bytes_received": "%BYTES_RECEIVED%", "bytes_sent": "%BYTES_SENT%", "upstream_service_time": "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"}
          route_config:
            name: local_route
            response_headers_to_add:
              - header:
                  key: "Strict-Transport-Security"
                  value: "max-age=31536000"
                append: true
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/myservice" }
                route:
                  cluster: def_grpc_my_service
                  max_grpc_timeout: 0s
              - match:
                  prefix: "/"
                route:
                  cluster: serviceui
              cors:
                allow_origin_string_match:
                  - safe_regex:
                      google_re2: {}
                      regex: \*
                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,cookie,set-cookie
                filter_enabled:
                  default_value:
                    numerator: 100
                    denominator: HUNDRED
          http_filters:
          - name: envoy.grpc_web
          - name: envoy.cors
          - name: envoy.router    
  clusters:
  - name: def_grpc_my_service
    connect_timeout: 0.25s
    type: logical_dns
    http2_protocol_options: {}
    lb_policy: round_robin
    hosts: [{ socket_address: { address: ${DOCKER_HOST_IP}, port_value: 8090 }}]
  - name: serviceui
    connect_timeout: 0.25s
    type: logical_dns
    lb_policy: round_robin
    hosts: [{ socket_address: { address: ${DOCKER_HOST_IP}, port_value: 3000 }}]
Build & run docker image
docker build -t myenvoy:dev-1.13.0 .
Ubuntu
docker run -d -it --name envoyfe --restart=always -p 80:8080 -p 443:8443 -p 9901:9901 \
-v `pwd`/envoy-front-proxy.yaml:/envoyproxy/envoy.yaml \
-e ENVOY_LOG_LEVEL=debug -e DOCKER_HOST_IP="$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')" \
myenvoy:dev-1.13.0 && docker logs -f envoyfe
Mac has a predefined docker.host.internal defined which is accessible from docker containers.
docker run -d -it --name envoyfe --restart=always -p 80:8080 -p 443:8443 -p 9901:9901 \
-v `pwd`/envoy-front-proxy.yaml:/envoyproxy/envoy.yaml \
-e ENVOY_LOG_LEVEL=debug -e DOCKER_HOST_IP="host.docker.internal" \
myenvoy:dev-1.13.0 && docker logs -f envoyfe