最近一直在搞kubernetes上的服务化。首先切到kubernetes上的项目是一个没有状态的data worker。一切如丝般润滑,简单到爆。但是为了部署我的grpc service时,引入了istio,一切变得艰难了好多。
首先,如果不考虑istio,单看kubernetes的话,这里需要定义一个Deployment,方便进行rolling update。然后,grpc service是一个service,这里还需要定义一个Service。此时,kubernetes的工作就结束了。到这里为止,k8s cluster上有一个grpc service instance了。我们理应可以通过ip访问这个服务。但是如果我们希望有多个instance,如何做load balance?
这里就要引入istio了。istio管理了kubernetes上所有的网络通信。所有跟网络相关的配置,都需要走istio。
如何构建全局的load balancer
我希望可以通过一个域名就能访问到k8s集群上所有的服务。使用kops在aws上创建的集群已经有一个aws classic load balancer,这里就可以直接使用了。这个load balancer不做任何事,只是把请求转发给istio的ingress gateway。注意,这里的loadbalancer是用来访问需要暴露到outside的服务。
Gateway & Virtual Service
Istio使用ingress gateway来管理所有流入的流量。我们需要创建不同功能的gateway用来从ingress gateway中分流到自己所需的流量。但是gateway不能单独使用,这里还要配合virtual service。virtual service & gateway共同定义了流量特征。
比如,对应http服务,我希望获取uri开头为/hello的请求,并将这些流量转给端口号为8080的hello-world service。这里就需要定义virtual service和gateway来做这件事。
在这里,我看文档的时候有点懵。因为我发现virtual service和gateway有一些相同的配置,我不明白这两个为什么一定要拆开定义,这里的设计没太看懂。
另外,istio是以sidecar的形式,在初始化服务的时候,将转发的配置信息注入进来的。所以,你会看到一个服务会有两个pod:服务本身和sidecar。
最后,kubernetes和istio对gRPC都十分友好。gRPC使用的是HTTP2,这里在定义virtual service的时候也可以通过uri prefix的方式分割不同的服务流量。
配置好的yaml看起来就像下面这样:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: main-server-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 8888
name: grpc
protocol: GRPC #or GRPC, which gives the same result
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: main-server
spec:
hosts:
- "*"
gateways:
- main-server-gateway
http:
- match:
- uri:
prefix: "/main.MainService"
route:
- destination:
port:
number: 8888
host: main-server
---
apiVersion: v1
kind: Service
metadata:
name: main-server
labels:
app: main-server
spec:
ports:
- name: grpc
port: 8888
selector:
app: main-server
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: main-server
spec:
replicas: 2
template:
metadata:
labels:
app: main-server
version: v1
spec:
containers:
- image: xxxxxxx.dkr.ecr.ap-southeast-1.amazonaws.com/grpc-test
imagePullPolicy: Always
name: main-server
env:
- name: EXTERNAL_SERVER_HOST
value: "ip-xxxxxxxxxx.ap-southeast-1.compute.internal"
- name: EXTERNAL_SERVER_PORT
value: "8888"
ports:
- containerPort: 8888
只要几段配置就能做grpc服务的负载均衡,确实挺方便。科技是我幸福。