Service Mesh: 基于 Istio 的落地实践(一)

init Kubernetes

传送门 二进制安装 kubernetes

安装istio

下载安装

下载istio 安装

进入 Istio release 页面,下载对应目标操作系统的安装文件。在 macOS 或者 Linux 系统中,还可以运行下面的命令,进行下载和自动解压缩:

$ curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.2.2 sh -

$ cd istio-1.2.2

$ export PATH=$PWD/bin:$PATH

初始化自定义资源

istio 本身进行了很多的资源自定义。 首先需要将这些自定义的资源创建出来。

$ for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done

$ kubectl get crd | grep istio
adapters.config.istio.io               2019-06-29T04:49:22Z
attributemanifests.config.istio.io     2019-06-29T04:49:22Z
authorizationpolicies.rbac.istio.io    2019-06-29T04:49:22Z
clusterrbacconfigs.rbac.istio.io       2019-06-29T04:49:22Z
destinationrules.networking.istio.io   2019-06-29T04:49:21Z
envoyfilters.networking.istio.io       2019-06-29T04:49:22Z
gateways.networking.istio.io           2019-06-29T04:49:22Z
handlers.config.istio.io               2019-06-29T04:49:22Z
httpapispecbindings.config.istio.io    2019-06-29T04:49:22Z
httpapispecs.config.istio.io           2019-06-29T04:49:22Z
instances.config.istio.io              2019-06-29T04:49:22Z
meshpolicies.authentication.istio.io   2019-06-29T04:49:22Z
policies.authentication.istio.io       2019-06-29T04:49:22Z
quotaspecbindings.config.istio.io      2019-06-29T04:49:22Z
quotaspecs.config.istio.io             2019-06-29T04:49:22Z
rbacconfigs.rbac.istio.io              2019-06-29T04:49:22Z
rules.config.istio.io                  2019-06-29T04:49:22Z
serviceentries.networking.istio.io     2019-06-29T04:49:22Z
servicerolebindings.rbac.istio.io      2019-06-29T04:49:22Z
serviceroles.rbac.istio.io             2019-06-29T04:49:22Z
sidecars.networking.istio.io           2019-06-29T04:49:22Z
templates.config.istio.io              2019-06-29T04:49:22Z
virtualservices.networking.istio.io    2019-06-29T04:49:21Z

执行istio-demo的安装,因为需要下载很多的镜像,而且大部分在国外,耗时比较长。

$ kubectl apply -f install/kubernetes/istio-demo.yaml

确认下列 Kubernetes 服务已经部署并都具有各自的 CLUSTER-IP

$ kubectl get svc -n istio-system
NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                                                                                     AGE
grafana                  ClusterIP      10.254.33.222    <none>        3000/TCP                                                                                                                                    97s
istio-citadel            ClusterIP      10.254.211.95    <none>        8060/TCP,15014/TCP                                                                                                                          97s
istio-egressgateway      ClusterIP      10.254.42.123    <none>        80/TCP,443/TCP,15443/TCP                                                                                                                    97s
istio-galley             ClusterIP      10.254.229.63    <none>        443/TCP,15014/TCP,9901/TCP                                                                                                                  98s
istio-ingressgateway     LoadBalancer   10.254.145.221   <pending>     15020:14115/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:14870/TCP,15030:9447/TCP,15031:14863/TCP,15032:10432/TCP,15443:15781/TCP   97s
istio-pilot              ClusterIP      10.254.92.10     <none>        15010/TCP,15011/TCP,8080/TCP,15014/TCP                                                                                                      97s
istio-policy             ClusterIP      10.254.106.5     <none>        9091/TCP,15004/TCP,15014/TCP                                                                                                                97s
istio-sidecar-injector   ClusterIP      10.254.35.98     <none>        443/TCP                                                                                                                                     97s
istio-telemetry          ClusterIP      10.254.119.223   <none>        9091/TCP,15004/TCP,15014/TCP,42422/TCP                                                                                                      97s
jaeger-agent             ClusterIP      None             <none>        5775/UDP,6831/UDP,6832/UDP                                                                                                                  97s
jaeger-collector         ClusterIP      10.254.167.118   <none>        14267/TCP,14268/TCP                                                                                                                         97s
jaeger-query             ClusterIP      10.254.10.189    <none>        16686/TCP                                                                                                                                   97s
kiali                    ClusterIP      10.254.19.166    <none>        20001/TCP                                                                                                                                   97s
prometheus               ClusterIP      10.254.177.180   <none>        9090/TCP                                                                                                                                    97s
tracing                  ClusterIP      10.254.237.37    <none>        80/TCP                                                                                                                                      97s
zipkin                   ClusterIP      10.254.188.138   <none>        9411/TCP                                                                                                                                    97s

如果你的集群在一个没有外部负载均衡器支持的环境中运行,istio-ingressgateway 的 EXTERNAL-IP 会是 <pending>。要访问这个网关,只能通过服务的 NodePort 或者使用端口转发来进行访问。

这一点很重要,这与后面访问应用时有着紧密的联系。

确认必要的 Kubernetes Pod 都已经创建并且其 STATUS 的值是 Running

$ kubectl get pods -n istio-system
NAME                                      READY   STATUS             RESTARTS   AGE
grafana-97fb6966d-7n2dn                   1/1     Running            0          4m43s
istio-citadel-7c7c5f5c99-9ctwx            1/1     Running            0          4m43s
istio-cleanup-secrets-1.2.2-qnd5p         0/1     Completed          0          4m44s
istio-egressgateway-f7b8cc667-lfwx4       0/1     Running            0          4m43s
istio-galley-585fc86678-pkhzn             1/1     Running            0          4m43s
istio-grafana-post-install-1.2.2-76sgq    1/1     Running            1          4m44s
istio-ingressgateway-cfbf989b7-b8rx7      1/1     Running            0          4m43s
istio-pilot-68f587df5d-qjmf4              2/2     Running            0          4m43s
istio-policy-76cbcc4774-dlrvt             2/2     Running            6          4m43s
istio-security-post-install-1.2.2-t75bl   1/1     Running            1          4m44s
istio-sidecar-injector-97f9878bc-mfbvf    1/1     Running            0          4m42s
istio-telemetry-5f4575974c-gr8qw          2/2     Running            2          4m43s
istio-tracing-595796cf54-q5z9d            1/1     Running            0          4m42s
kiali-55fcfc86cc-8wr9t                    1/1     Running            0          4m43s
prometheus-5679cb4dcd-jxn2x               1/1     Running            0          4m43s

如果上面 的pod 运行不正常,尤其是 istio-policyistio-telemetry ,这两个pod 在构造上是一样的。其中 istio-telemetry 是专门用于收集遥测数据的Mixer服务组件。istio-policy 是另一个Mixer服务,和 istio-telemetry 基本上是完全相同的机制和流程,Data Plane在转发服务的请求前调用 istio-policy 的Check 接口检查是否允许访问。Mixer 根据配置将请求转发到对应的Adapter做对应检查。给代理返回允许访问还是拒绝。

关于这些组件,我们后期还会有详细的介绍。这里暂且略过。

如果运行过程中出现了什么错误的话,可以去check一下 docker image 是否有多个版本存在的问题。

例如笔者曾经以 官方 istio-1.2.0 进行实验,一直出错。后来换成了 isito-1.2.2,又把集群中每个node 上的 docker image 检查了一遍,把 tag:1.2.0 的镜像全部删除掉了。详见 文末 删除Istio 以及Demo示例 部分。

安装BookInfo

安装

在使用 kubectl apply 进行应用部署的时候,如果目标命名空间已经打上了标签 istio-injection=enabledIstio sidecar injector 会自动把 Envoy 容器注入到你的应用 Pod 之中。

这里,我们采用默认的 namespace dafault 避免出错之后不好排查。

$ kubectl create namespace bookinfo

$ kubectl label namespace bookinfo istio-injection=enabled

$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo

验证一下bookinfo 的 service pod 运行状况

$ kubectl get services -n bookinfo
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
details       ClusterIP   10.254.254.166   <none>        9080/TCP   114s
productpage   ClusterIP   10.254.59.59     <none>        9080/TCP   114s
ratings       ClusterIP   10.254.245.84    <none>        9080/TCP   114s
reviews       ClusterIP   10.254.37.253    <none>        9080/TCP   114s


$ kubectl get pods -n bookinfo
NAME                              READY   STATUS    RESTARTS   AGE
details-v1-7964b4bb49-rzrs4       2/2     Running   0          45s
productpage-v1-6c668694dc-v6685   2/2     Running   0          45s
ratings-v1-7bb4dbd557-d44d5       2/2     Running   0          45s
reviews-v1-597f899bf6-fg6hh       2/2     Running   0          45s
reviews-v2-664994896d-694tw       2/2     Running   0          45s
reviews-v3-fc984656d-mx48l        2/2     Running   0          45s

要确认 Bookinfo 应用程序正在运行,请通过某个 pod 中的 curl 命令向其发送请求,例如来自 ratings:

不要忘记,我们默认的的namespace 已经换成了bookinfo

$ kubectl exec -it $(kubectl get pod -n bookinfo -l app=ratings -o jsonpath='{.items[0].metadata.name}') -n bookinfo  -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"

<title>Simple Bookstore App</title>

确定 Ingress 的 IP 和端口

为应用程序定义入口网关:

$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml  -n bookinfo

确认网关创建完成:

$ kubectl get gateway -n bookinfo
NAME               AGE
bookinfo-gateway   47s

接下来,确定 INGRESS_HOSTINGRESS_PORT 变量.

确定入口 IP 和端口,执行以下命令以确定 Kubernetes 集群是否在支持外部负载均衡器的环境中运行

$ kubectl get svc istio-ingressgateway -n istio-system
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                                                                                     AGE
istio-ingressgateway   LoadBalancer   10.254.145.221   <pending>     15020:14115/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:14870/TCP,15030:9447/TCP,15031:14863/TCP,15032:10432/TCP,15443:15781/TCP   60m

如果 EXTERNAL-IP 有值(IP 地址或主机名),则说明环境具有可用于 Ingress 网关的外部负载均衡器。如果 EXTERNAL-IP 值是 <none>(或一直是 <pending> ),则说明可能环境并没有为 Ingress 网关提供外部负载均衡器的功能。在这种情况下,可以使用 Servicenode port 方式访问网关。

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

$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o 'jsonpath={.items[0].status.hostIP}')

$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

确认应用在运行中

可以用 curl 命令来确认 Bookinfo 应用的运行情况

$  curl -s http://${GATEWAY_URL}/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

应用缺省目标规则

在使用 Istio 控制 Bookinfo 版本路由之前,你需要在目标规则中定义好可用的版本,命名为 subsets 。

$ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml -n bookinfo

可以使用以下命令查看目标规则

kubectl get destinationrules -o yaml

访问我们的应用

输入下面的地址,返回 200 的话,就说明部署成功

$ curl -o /dev/null -s -w "%{http_code}\n" http://${GATEWAY_URL}/productpage
200

当然也可以通过 http://${GATEWAY_URL}/productpage 来访问。如下的界面。

Prometheus 指标数据

前面的示例中,官方默认安装了一系列的可测试组件。

可以执行下面的命令,就可以在浏览器 使用 http://hostip:9090/graph 中打开promethues UI 界面了。

$  kubectl -n istio-system port-forward --address 0.0.0.0 $(kubectl -n istio-system get pod -l app=prometheus -o jsonpath='{.items[0].metadata.name}') 9090:9090 &

详细的测试数据可以参考官方的教程。

Grafana Dashboard

首先确保 Prometheus 和 Grafana 在集群中运行

$  kubectl -n istio-system get svc prometheus
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
prometheus   ClusterIP   10.254.177.180   <none>        9090/TCP   3d2h
$  kubectl -n istio-system get svc grafana
NAME      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
grafana   ClusterIP   10.254.33.222   <none>        3000/TCP   3d2h

执行下面的命令,在 浏览器中打开 http://hostip:3000/dashboard/db/istio-mesh-dashboard

$ kubectl -n istio-system port-forward --address 0.0.0.0 $(kubectl -n istio-system get pod -l app=grafana -o jsonpath='{.items[0].metadata.name}') 3000:3000 &

分布式链路追踪 Jaeger

执行下面的命令,在浏览器中打开 http://hostip:15032,就可以访问到分布式链路追踪的UI了。

$ kubectl -n istio-system port-forward --address 0.0.0.0 $(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{.items[0].metadata.name}') 15032:16686

网格可视化kiali

确定kiali在集群中运行

$ kubectl -n istio-system get svc kiali
NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
kiali   ClusterIP   10.254.19.166   <none>        20001/TCP   3d3h

执行下面的命令,浏览器界面打开 http://hostip:20001/kiali/console/就可以对服务网格进行可视化查看了。

$ kubectl -n istio-system port-forward --address 0.0.0.0 $(kubectl -n istio-system get pod -l app=kiali -o jsonpath='{.items[0].metadata.name}') 20001:20001 &

默认账户密码 admin:admin

isito 官方还有 如何创建secret的详细教程可以参考。

删除Istio 以及Demo示例

删除路由规则,并终结应用的 Pod samples/bookinfo/platform/kube/cleanup.sh

确认应用已经关停

$ kubectl get virtualservices   #-- there should be no virtual services
$ kubectl get destinationrules  #-- there should be no destination rules
$ kubectl get gateway           #-- there should be no gateway
$ kubectl get pods               #-- the Bookinfo pods should be deleted

删除 Gateway 和 VirtualService,并关闭 httpbin 服务:

$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f samples/httpbin/httpbin.yaml

删除自定义资源

for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl delete  -f $i  -n bookinfo ; done

删除镜像 ,找到相应的image 版本,替换掉 1.2.0 执行下面的命令

for i in $(docker image ls  | grep 1.2.0 | cut -f 1 -d " "); do docker rmi  $i:1.2.0 ;done

总结

本文虽然说是实践,但是更多的却是将官方的例子跑了起来,没有什么特殊的地方,争取以后详细地输出落地实践的学习心得。

Last updated