istio部署与评估

Jan 12, 2022


前言

istio是服务网格的一种具体实现方案,在网上已经有非常非常多的相关介绍了,本文主要介绍如何搭建一个开发环境的istio。

准备工作

istio提供了多种部署方式:

  • istioctl: 官方安装工具,需要k8s集群
  • Istio Operator: 官方安装工具,需要k8s集群
  • helm:使用k8s的helm安装
  • 多集群安装:跨多个k8s集群安装
  • 虚拟机安装:虚拟机直接安装

出于开发使用和安装简单,我们使用istioctl的方式安装,需要做如下准备:

curl -L https://istio.io/downloadIstio | sh -

下载后进入部署包目录:

cd istio-1.12.1

部署包内包含了客户端工具bin/istioctl和示例应用samples

将istioctl客户端加入搜索路径:

export PATH=$PWD/bin:$PATH

开始安装

下载的安装包里包含了不同部署场景的配置。

  1. 面向开发使用的场景我们选用demo,这里包含了一组专门为测试准备的功能集合。
$ istioctl install --set profile=demo -y
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete
  1. 给命名空间添加标签,指示istio在部署应用的时候,自动注入Envoy边车代理:
$ kubectl label namespace default istio-injection=enabled
namespace/default labeled

这里使用的是kubectl,k8s的工具,实际上是增加了一个触发器,在Pod创建时,会触发istio的sidecar注入流程,为pod注入sidecar(istio默认使用的是envoy),注入sidecar的pod实际上会产生两个容器。

到这里,我们就完成在k8s集群上部署istio了。

整个部署过程非常简单,接下来我们看看如何试用istio的功能。

示例应用

在istio中,提供了一个非常经典的示例应用,Bookinfo,现在我们将这个应用部署到k8s中:

  1. 部署Bookinfo
$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created

istio内置的示例应用实际上是通过k8s的配置文件实现的,k8s的部署就是配置文件编写,程序镜像已经事先推送到docker的镜像仓库了。

部署命令执行完成后,并不是部署完成了,而是存储了部署计划,开始启动部署流程,我们可以通过k8s的命令查看部署的情况:

  1. 查看部署情况:
$ kubectl get services
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.0.0.212      <none>        9080/TCP   29s
kubernetes    ClusterIP   10.0.0.1        <none>        443/TCP    25m
productpage   ClusterIP   10.0.0.57       <none>        9080/TCP   28s
ratings       ClusterIP   10.0.0.33       <none>        9080/TCP   29s
reviews       ClusterIP   10.0.0.28       <none>        9080/TCP   29s

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
details-v1-558b8b4b76-2llld       2/2     Running   0          2m41s
productpage-v1-6987489c74-lpkgl   2/2     Running   0          2m40s
ratings-v1-7dc98c7588-vzftc       2/2     Running   0          2m41s
reviews-v1-7f99cc4496-gdxfn       2/2     Running   0          2m41s
reviews-v2-7d79d5bd5d-8zzqd       2/2     Running   0          2m41s
reviews-v3-7dbcdcbc56-m8dph       2/2     Running   0          2m41s

重复运行kubectl get pods等待所有pod的READY状态值为2/2,STATUS的值为Running,才表示部署完成。

  1. 确认服务已经正常运行:
kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -s productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

看到<title>Simple Bookstore App</title>的结果即说明我们已经可以访问应用了。

虽然部署已经完成,但是此时我们还是无法访问这个应用,因为k8s内部的资源无法被外部直接访问,我们还需要开放外部访问。

  1. 开放外部访问

要开放示例应用的外部访问,我们需要一个Istio入站网关(Ingress Gateway),它会在网格边缘把一个路径映射到路由。

先把应用关联到Istio网关:

$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created

然后验证配置文件:

$ istioctl analyze
✔ No validation issues found when analyzing namespace: default.

关联到istio网关是指,在istio网关上增加一个代理的配置,将istio网关的特定url转发到示例应用的服务中来。

现在示例应用已经挂到istio的网关上了,我们需要知道istio网关的访问地址。

不同的k8s集群部署方式获取istio网关访问地址的方式不同,本文使用的是minikube部署的k8s集群,接下来的介绍我们基于minikube的方式介绍,如果是采用其他方式部署的k8s机器,请参考官网文档

  1. 支持外部访问

我们使用minikube部署的k8s集群,实现的原理是在本机的docker上运行了一个镜像:

$ docker ps
CONTAINER ID   IMAGE                                 COMMAND                  CREATED        STATUS        PORTS                                                                                                                                  NAMES
ce4e90343fc9   gcr.io/k8s-minikube/kicbase:v0.0.28   "/usr/local/bin/entr…"   46 hours ago   Up 46 hours   127.0.0.1:49172->22/tcp, 127.0.0.1:49171->2376/tcp, 127.0.0.1:49170->5000/tcp, 127.0.0.1:49169->8443/tcp, 127.0.0.1:49168->32443/tcp   minikube

这个docker镜像才是k8s集群的节点(不是本机),因此在本机的docker里我们看不到k8s里运行的容器,这个k8s里的容器,也有docker,真正的k8s内部署的应用,实际上是在容器内的docker运行的,因此想看到k8s上运行的容器,我们得进入到docker容器内运行docker ps

因此,实际上我们现在在本机,访问k8s的容器,已经可以访问到示例应用了,但是要怎么访问呢?

我们先看看istio网关监听的端口:

$ echo $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
32608

然后看看k8s容器的ip地址:

$ minikube ip
192.168.49.2

那么访问地址如下:

echo http://$(minikube ip):$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')/productpage

可以直接使用如下命令访问:

$ curl http://$(minikube ip):$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

到这一步,如果你是在本机直接部署访问的,到这里即可访问了,但是在开发阶段,我们也有可能不是在本机部署,是在虚拟机部署之后,在开发机上访问,那么这种情况是访问不了的,因为k8s容器监听的端口没有绑定到宿主机上,

因此要实现其他机器访问示例应用,只能通过宿主机端口转发的方式,端口转发的方法有很多,这里我们使用ncat来实现:

# 安装ncat
$ yum install nmap-ncat -y 
# 运行端口转发
$ ncat --sh-exec "ncat $(minikube ip) $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')" -l 8888  --keep-open 

现在我们使用宿主机的ip:8888这个地址就可以访问服务了:

查看仪表盘

到目前为止,我们完成了istio和bookinfo示例应用的部署,但是还没有感受到istio带来的效果和威力,接下来我们开始部署真正展现istio威力的工具。

使用如下命令部署istio集成的遥测应用(包括:Kiali,Prometheus,Grafana,Jaeger):

kubectl apply -f samples/addons
kubectl rollout status deployment/kiali -n istio-system
Waiting for deployment "kiali" rollout to finish: 0 of 1 updated replicas are available...
deployment "kiali" successfully rolled out

如果安装插件时出错,再运行一次命令即可,有一些和时间相关的问题,再运行就能解决。

访问Kiali仪表板

istioctl dashboard kiali

上面的命令运行后,可以直接在本地访问Kiali仪表板,如果我们想在其他机器上访问,则需要指定–address参数来指定Kiali绑定的host,并且可以用–port来制定端口。

这里为了方便,我们可以使用如下命令截取本机ip:

$ ip addr | grep "eth0" | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}'

这里eth0是网卡名称,如果你希望获取其他网卡的ip,请自行替换

最终我们可以用如下命令运行:

$ istioctl dashboard kiali --address $(ip addr | grep "eth0" | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}') --port 8003
http://10.224.192.140:8003/kiali
Failed to open browser; open http://10.224.192.140:8003/kiali in your browser.

此时我们通过http://10.224.192.140:8003/kiali就可以访问到Kiali仪表盘了:

查看Prometheus仪表盘

先验证前面是否已安装Prometheus的插件:

$ kubectl -n istio-system get svc prometheus
NAME         CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
prometheus   10.59.241.54   <none>        9090/TCP   2m

这里我们可以看到已经安装了。

用如下命令可以启动一个代理,在本地访问Prometheus:

$ istioctl dashboard prometheus

当然,如果需要在其他的机器上访问的话,则需要指定–address参数:

$ istioctl dashboard prometheus --address $(ip addr | grep "eth0" | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}') --port 8004
http://10.224.192.140:8004
Failed to open browser; open http://10.224.192.140:8004 in your browser.

现在我们可以通过http://10.224.192.140:8004访问Prometheus:

我们执行一个Prometheus查询,在 web 页面顶部的 “Expression” 对话框中,输入文本:

istio_requests_total

然后点击 Execute 按钮,结果类似如下:

查看Grafana面板

Grafana面板依赖Prometheus,因此要先确认Prometheus已经部署:

$ kubectl -n istio-system get svc prometheus
NAME         CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
prometheus   10.59.241.54   <none>        9090/TCP   2m

再检查Grafana服务是否部署:

$ kubectl -n istio-system get svc grafana
NAME      CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
grafana   10.59.247.103   <none>        3000/TCP   2m

如果都运行了,可以使用如下命令启动Grafana的外部访问:

kubectl -n istio-system port-forward $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}')  --address=$(ip addr | grep "eth0" | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/, "\\1", "g", $2)}') 3000:3000 &

在浏览器中访问http://10.224.192.140:3000即可打开控制台界面:

到这里,我们对istio开发版的部署和评估已经基本完成,istio通过sidecar的方式实现服务网格,在sidecar中植入了许多特性,帮助我们实现服务中公共的功能抽离出来,极大减轻了应用的对接负担,但是这种模式本身的部署和管理是非常麻烦的,因此最好在基于k8s的环境上部署和实施。