/ Kubernetes

istio入门玩家笔记

最近需要用 istio-ingress 做一些事情, 所以先在测试环境部署一下 istio 玩一下.

部署 istio

部署 istio 选择了 Helm 来生成部署文件, 关于 Helm 可以见 Helm入门笔记 因为暂时只需要 istio-ingress 的功能,所以裁剪了许多不需要的组件, 最终的 Helm template 如下:

helm template /opt/istio-0.8.0/install/kubernetes/helm/istio \
--name istio \
--namespace istio-system \
--set sidecarInjectorWebhook.enabled=false \
--set galley.enabled=false \
--set mixer.enabled=false > ~/istio-min.yaml

这里还要注意的是, helm 并不会帮你写创建 --namespace istio-system 的配置,所以在apply前要记得先把 namespace 创建好. 在正确apply以后可以看到 istio-system 这个 namespace 下的服务有:

  • istio-citadel
  • istio-cleanup
  • istio-egressgateway
  • istio-ingress
  • istio-ingressgateway
  • istio-pilot
  • prometheus

因为没有启用 mixer 所以按这个方式去启动 istio 以后 envoy 会报错

[libprotobuf ERROR src/istio/mixerclient/report_batch.cc:83] Mixer Report failed with: UNAVAILABLE:Cluster not available

在之前产生的安装yaml里找到

# To disable the mixer completely (including metrics), comment out
# the following lines
mixerCheckServer: istio-policy.istio-system.svc.cluster.local:15004
mixerReportServer: istio-telemetry.istio-system.svc.cluster.local:15004

注释这两行, 但是很奇怪的是 mixerCheckServermixerReportServer 提交数据给名叫 istio-policyistio-telemetry 的服务,还不清楚具体的数据流是怎么传输的.

在折腾 istio-ingress 前多嘴一句, 既然安装了 istio 要体验它自动给 pods 加上 sidecar 的话, 可以参考 https://istio.io/docs/setup/kubernetes/sidecar-injection/#automatic-sidecar-injection 在新建 namespace 的时候加入 istio-injection=enabled 就可以了~

$ kubectl label namespace <namespace> istio-injection=enabled
$ kubectl create -n <namespace> -f <your-app-spec>.yaml

准备好测试服务

之前用gin写了一个非常简单的http api, 根据发的版本 v1v2 ,调用 /test/release 可以获得当前发布的版本和对应的容器名称,例如对 test-service-a 这个域名:

curl -HHost:test-service-a.deploy.com http://10.7.3.194:31380

返回

{
   "hostname":"tapi-5c745dbdf8-v44ws",
   "message":"service available",
   "release_version":"v1.0",
   "status":200
}

返回的版本号是v1.0, 对 test-service-b 这个域名:

curl -HHost:test-service-b.deploy.com http://10.7.3.194:31380

返回

{
   "hostname":"tapi-v2-7976fddd8-tzd9m",
   "message":"service available",
   "release_version":"v2.0",
   "status":200
}

版本号为v2.0.

在正常部署服务pod和service后,暴露两个 ClusterIPistio-ingress 调用, kubectl -n test-deploy get service 的结果如下:

test-deploy tapi-service-only-v1 ClusterIP 172.21.138.249  80/TCP app=tapi-service,deployVersion=v1.0
test-deploy tapi-service-only-v2 ClusterIP 172.21.57.248  80/TCP app=tapi-service,deployVersion=v2.0

首先在 istio-ingress 里部署一个 Gateway, istioGateway 作为一个负载均衡器工作在ingress的位置监听端口,接收HTTP/TCP请求并转发给后端. 一个简单的 Gateway 配置如下:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: tapi-gateway
  namespace: test-deploy
spec:
  selector:
    istio: ingressgateway # 用Istio默认的gateway,在service里selector为istio=ingressgateway
  servers:
  - port:
      number: 80    # 80端口
      name: http
      protocol: HTTP   # 可以是HTTP\HTTP2等见文档
    hosts:
    - "*"           # 允许的域名

在定义好负载均衡器后,还要定义具体的后端转发流程, 在 istio 里的 VirtualService 用来定义请求的转发规则和对应的后端服务, 下面的例子里定义了2个 VirtualService ,后端服务分别为同一个服务的 v1 和 v2 版, 同时定义了 Gateway 为前面创建的 tapi-gateway.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: test-virtualservice-v1
  namespace: test-deploy
spec:
  hosts:
  - "test-service-a.deploy.com"   # 监听的域名, 可以有多个
  gateways:
  - tapi-gateway                  # 对应使用的gateway, 可以有多个
  http:
  - match:                        # 对应uri的转发策略
    - uri:
        prefix: /
    route:
    - destination:                # 后端的服务
        port:
          number: 80
        host: tapi-service-only-v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: test-virtualservice-v2
  namespace: test-deploy
spec:
  hosts:
  - "test-service-b.deploy.com"
  - "tapi-*.deploy.com"
  gateways:
  - tapi-gateway
  http:
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        port:
          number: 80
        host: tapi-service-only-v2

其中 match 可以支持非常多的匹配形式, 例如 uri 前缀, header, cookie 等, 详情见 https://istio.io/docs/reference/config/istio.networking.v1alpha3/#Gateway
destination 可以配置多个后端, 并支持权重配置 https://istio.io/docs/reference/config/istio.networking.v1alpha3/#DestinationWeight

最终可以见到在不同 Host 请求 test-service-a.deploy.comtest-service-b.deploy.com 时得到不同的后端服务.

Gateway 和 VirtualService 姿势说明

  • 对不同的服务 使用不同的 namespace 和 Gateway, VirtualService 隔离;
  • 尽量不要在 Gateway 的 host 里写 * 匹配以免发生一些自己都不知道结果是怎么样的事情;
  • 当前 Gateway 的 TLS 配置存在时必须保证正确否则会把整个 Gateway 带挂起不来;
  • 要配置多张 TLS 证书, 参考 https://github.com/istio/istio/issues/7658
  • host 匹配重复域名时必然会发生错误, istio并不会替你检查, 要避免这一点