初入 Envoy/Istio

由于要做 K8S 的 sidecar 扩展,而其实际是由 Envoy 来实现的。要将 Envoy 部署为 sidecar,需要先安装 Istio。

$ wget https://raw.githubusercontent.com/istio/istio/master/release/downloadIstioCandidate.sh
$ sh downloadIstioCandidate.sh

完成下载后,将得到一个 istio-1.8.1 目录,将目录内的 bin 目录加入到环境变量 PATH 中。注意,此处应当是全局的环境变量,因此可以考虑将 istio-1.8.1 目录整体移往 /opt,并且修改 /etc/profile 以加入环境变量。

然后执行命令安装 Istio,并开启自动注入:

$ istioctl install --set profile=demo -y
$ kubectl label namespace default istio-injection=enabled

部署完毕后,可以用以下命令来查看自动注入的启用情况:

$ kubectl get namespace -L istio-injection

按上一篇所说的,我们原本在 K8S 里有一个名为 sample-service 的 Pod,在注入开启后,我们需要重新部署之:

$ kubectl delete -f sample-service.yaml
$ kubectl create -f sample-service.yaml

完成后会发现,Pod 的 Ready 状态有所改变,在没有注入时,状态为 1/1,而开启注入后,状态为 2/2,此时即代表注入成功。


接着要打一个 Envoy 的镜象,在打镜象前,需要对 Envoy 作出配置,我们在这里简单的进行一个代理,将请求转发至 sample-service。先通过 kubectl describe pod sample-service 可以得知 Pod 的 IP,然后作出如下配置:

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: 
      address: 127.0.0.1
      port_value: 9901
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: 
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route: 
                  cluster: sample-envoy-service
          http_filters:
          - name: envoy.router
  clusters:
  - name: sample-envoy-service
    connect_timeout: 30s
    type: STATIC
    lb_policy: ROUND_ROBIN
    hosts: 
    - socket_address: 
        address: 192.168.235.233
        port_value: 9001

需要注意的是,这里的 admin 相关的端口必须配置,因为内带了一个管理员工具,我们会需要访问到它。

然后写一个 Dockerfile 就可以打包镜象了:

FROM envoyproxy/envoy-dev:e98e41a8e168af7acae8079fc0cd68155f699aa3
COPY envoy.yaml /etc/envoy/envoy.yaml
$ sudo docker build -t envoy:v1 .

打完镜象后,将它运行起来即可:

$ sudo docker run -it -d --name envoy -p 9901:9901 -p 10000:10000 envoy:v1

完成后即可对 10000 端口发出请求:

$ curl 'http://0.0.0.0:10000'

即可以看到我们原本部署于 9001 端口上的内容了,即告代理成功。

对于外部的访问,也可以在浏览器下使用以下 URL:

http://10.211.55.16:10000

这样我们就不再需要开启 32001 端口来供外部访问了。


踩坑

第一次部署好 sample-service 服务后,跑起 Envoy 并在外部浏览器请求时,会出现一个异常,upstream connect error or disconnect/reset before headers. reset reason: connection termination,初看之下,就是请求在 header 被处理之前就挂了。那就要去查一下是否 header 里面有 Envoy 不支持的东西了。

经过排查,发现是我在 Ktor 内开启了 Compress 插件,并且未把 Accept-Encoding: gzip 加入响应头,而 Envoy 在转发时,默认将原始的响应头送出,因此在浏览器侧无法接受到 Accept-Encoding 的值,所以就没有进行解压而产生了异常。解决方法也很简单,就是在 Ktor 项目启动的时候,禁用 Compress:

fun Application.module() {
    installPlugin(
        useCompress = false,    // 此处禁用压缩
        sessionIdentifier = "SampleSession",
        headers = mapOf("X-Engine" to "Ktor")) { }
    routing {
        ... ...
    }
}

另外,上面说到了 admin 相关的端口配置,其实 Envoy 对 admin 提供了操作接口,需要进入容器来操作,如下:

$ sudo docker exec -it envoy sh
# curl 'http://0.0.0.0:9901/help'
# curl 'http://0.0.0.0:9901/stats'
# curl 'http://0.0.0.0:9901/server_info'

容器中可能没有 curl,在此情况下需要手动安装一下,apt update && apt install curl

最后,经张瑾大神的指点,才知道 Istio 是 Envoy 的上层实现,其实很多情况下,我们并没有必要直接使用 Envoy,而是在 Istio 上发挥就好了,下次再研究吧。

你可能感兴趣的:(初入 Envoy/Istio)