干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序

Posted 中兴开发者社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序相关的知识,希望对你有一定的参考价值。

每天读一篇一线开发者原创好文

▍作者简介

赵化冰是一个程序员及开源软件爱好者,目前在NFV&SDN编排开源社区ONAP担任MSB项目PTL,致力于高性能,高可用性微服务架构在编排领域的应用。这篇文章主要介绍了下一代微服务Service Mesh的开源项目Istio及如何从零搭建Istio及Bookinfo示例程序,希望对大家有所帮助。


服务网格简介

服务网格(Service Mesh)是为解决微服务的通信和治理而出现的一种架构模式。

服务网格将服务间通讯以及与此相关的管理控制功能从业务程序中下移到一个基础设施层,从而彻底隔离了业务逻辑和服务通讯两个关注点。采用服务网格后,应用开发者只需要关注并实现应用业务逻辑。服务之间的通信,包括服务发现,通讯的可靠性,通讯的安全性,服务路由等由服务网格层进行处理,并对应用程序透明。

让我们来回顾一下微服务架构的发展过程。在出现服务网格之前,我们在微服务应用程序进程内处理服务通讯逻辑,包括服务发现,熔断,重试,超时等逻辑,如下图所示:干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序
通过对这部分负责服务通讯的逻辑进行抽象和归纳,可以形成一个代码库供应用程序调用。但应用程序还是需要处理和各种语言代码库的调用细节,并且各种代码库互不兼容,导致对应用程序使用的语言和代码框架有较大限制。


如果我们更进一步,将这部分逻辑从应用程序进程中抽取出来,作为一个单独的进程进行部署,并将其作为服务间的通信代理,如下图所示:
干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序
因为通讯代理进程和应用进程一起部署,因此形象地把这种部署方式称为“sidecar”(三轮摩托的挎斗)。

干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序

应用间的所有流量都需要经过代理,由于代理以sidecar方式和应用部署在同一台主机上,应用和代理之间的通讯被认为是可靠的。然后由代理来负责找到目的服务并负责通讯的可靠性和安全等问题。

当服务大量部署时,随着服务部署的sidecar代理之间的连接形成了一个如下图所示的网格,被称之为Service Mesh(服务网格),从而得出如下的服务网格定义。

服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求可以在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但应用程序不需要知道它们的存在。


William Morgan __WHAT’S A SERVICE MESH? AND WHY DO I NEED ONE?_ _

干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序

了解了服务网格的基本概念,下一步介绍一下Istio。Istio是来自Google,IBM和Lyft的一个Service Mesh(服务网格)开源项目,是Google继Kubernetes之后的又一大作,Istio架构先进,设计合理,刚一宣布就获得了Linkerd,nginmesh等其他Service Mesh项目的合作以及Red hat/Pivotal/Weaveworks/Tigera/Datawire等的积极响应。
干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序
可以设想,在不久的将来,微服务的标准基础设施将是采用kubernetes进行服务部署和集群管理,采用Istio处理服务通讯和治理,两者相辅相成,缺一不可。


安装Kubernetes


Istio是微服务通讯和治理的基础设施层,本身并不负责服务的部署和集群管理,因此需要和Kubernetes等服务编排工具协同工作。


Istio在架构设计上支持各种服务部署平台,包括kubernetes,cloud foundry,Mesos等,但Istio作为Google亲儿子,对自家兄弟Kubernetes的支持肯定是首先考虑的。目前版本的0.2版本的手册中也只有Kubernetes集成的安装说明,其它部署平台和Istio的集成将在后续版本中支持。


从Istio控制面Pilot的架构图可以看到各种部署平台可以通过插件方式集成到Istio中,为Istio提供服务注册和发现功能。

kubernetes集群的部署较为复杂,Rancher提供了kubernetes部署模板,通过一键式安装,可以大大简化kubernetes集群的安装部署过程。


通过Rancher安装Kubernetes集群的简要步骤如下:


在server和工作节点上安装docker

因为k8s并不支持最新版本的docker,因此需根据该页面安装指定版本的docker
http://rancher.com/docs/rancher/v1.6/en/hosts/ ,目前是1.12版本。

 
   
   
 
  1. curl https://releases.rancher.com/install-docker/1.12.sh | sh

                    

启动Rancher server

 
   
   
 
  1. sudo docker run ---restart=always -8080:8080 rancher/server


登录Rancher管理界面,创建k8s集群

Rancher 管理界面的缺省端口为8080,在浏览器中打开该界面,通过菜单Default->Manage Environment->Add Environment添加一个kubernetes集群。这里需要输入名称kubernetes,描述,然后选择kubernetes template,点击create,创建Kubernetes环境。 

点击菜单切换到kubernetes Environment,然后点击右上方的Add a host,添加一台host到kubernetes集群中。注意添加到集群中的host上必须先安装好符合要求的docker版本。

host加入cluster后Rancher会在host上pull kubernetes的images并启动kubernetes相关服务,根据安装环境所在网络情况不同需要等待几分钟到几十分钟不等。


安装并配置kubectl

待Rancher界面提示kubernetes创建成功后,安装kubernetes命令行工具kubectl

 
   
   
 
  1. curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubectl

  2.  

  3. chmod +./kubectl

  4.  

  5. sudo mv ./kubectl /usr/local/bin/kubectl

登录Rancher管理界面, 将 All Environments->kubernetes->KUBERNETES->CLI create config 的内容拷贝到~/.kube/config 中,以配置Kubectl和kubernetes server的连接信息。干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序

安装Istio

Istio提供了安装脚本,该脚本会根据操作系统下载相应的Istio安装包并解压到当前目录。

 
   
   
 
  1.  curl -L https://git.io/getLatestIstio | sh -

根据脚本的提示将Istio命令行所在路径加入到系统PATH环境变量中

 
   
   
 
  1. export PATH="$PATH:/home/ubuntu/istio-0.2.10/bin"

在kubernetes集群中部署Istio控制面服务

 
   
   
 
  1. kubectl apply -f istio-0.2.10/install/kubernetes/istio.yaml

确认Istio控制面服务已成功部署。Kubernetes会创建一个istio-system namespace,将Istio相关服务部署在该namespace中。

确认Istio相关Service的部署状态

 
   
   
 
  1. kubectl get svc -n istio-system

 
   
   
 
  1. NAME            CLUSTER-IP      EXTERNAL-IP        PORT(S)                                                  AGE

  2. istio-egress    10.43.192.74    <none>             80/TCP                                                   25s

  3. istio-ingress   10.43.16.24     10.12.25.116,...   80:30984/TCP,443:30254/TCP                               25s

  4. istio-mixer     10.43.215.250   <none>             9091/TCP,9093/TCP,9094/TCP,9102/TCP,9125/UDP,42422/TCP   26s

  5. istio-pilot     10.43.211.140   <none>             8080/TCP,443/TCP                                         25s

确认Istio相关Pod的部署状态

 
   
   
 
  1. kubectl get pods -n istio-system

 
   
   
 
  1. NAME                             READY     STATUS    RESTARTS   AGE

  2. istio-ca-367485603-qvbfl         1/1       Running   0          2m

  3. istio-egress-3571786535-gwbgk    1/1       Running   0          2m

  4. istio-ingress-2270755287-phwvq   1/1       Running   0          2m

  5. istio-mixer-1505455116-9hmcw     2/2       Running   0          2m

  6. istio-pilot-2278433625-68l34     1/1       Running   0          2m

从上面的输出可以看到,这里部署的主要是Istio控制面的服务,而数据面的网络代理要如何部署呢?
根据前面服务网格的架构介绍可以得知,网络代理是随着应用程序以sidecar的方式部署的,在下面部署Bookinfo示例程序时会演示如何部署网络代理。


部署Bookinfo示例程序

在下载的Istio安装包的samples目录中包含了示例应用程序。

通过下面的命令部署Bookinfo应用

 
   
   
 
  1. kubectl apply -<(istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml)

确认Bookinfo服务已经启动

 
   
   
 
  1. kubectl get services

 
   
   
 
  1. NAME          CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE

  2. details       10.43.175.204   <none>        9080/TCP   6m

  3. kubernetes    10.43.0.1       <none>        443/TCP    5d

  4. productpage   10.43.19.154    <none>        9080/TCP   6m

  5. ratings       10.43.50.160    <none>        9080/TCP   6m

  6. reviews       10.43.219.248   <none>        9080/TCP   6m

http://10.12.25.116/productpage
干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序

理解Istio Proxy实现原理

服务网格相对于sprint cloud等微服务代码库的一大优势是其对应用程序无侵入,在不修改应用程序代码的前提下对应用服务之间的通信进行接管,Istio是如何做到这点的呢?下面通过示例程序的部署剖析其中的原理。

如果熟悉kubernetes的应用部署过程,我们知道Bookinfo应用程序的标准部署方式是这样的:

 
   
   
 
  1. kubectl apply -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml

但从上面的部署过程可以看到,kubectl apply命令的输入并不是一个kubernetes yaml文件,而是istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml命令的输出。

这段命令在这里起到了什么作用呢?通过单独运行该命令并将输出保存到文件中,我们可以查看istioctl kube-inject命令到底在背后搞了什么小动作。

 
   
   
 
  1. istioctl kube-inject -f istio-0.2.10/samples/bookinfo/kube/bookinfo.yaml >> bookinfo_with_sidecar.yaml

对比bookinfo_with_sidecar.yaml文件和bookinfo.yaml,可以看到该命令在bookinfo.yaml的基础上做了如下改动:

  • 为每个pod增加了一个代理container,该container用于处理应用container之间的通信,包括服务发现,路由规则处理等。从下面的配置文件中可以看到proxy container通过15001端口进行监听,接收应用container的流量。

  • 为每个pod增加了一个init-container,该container用于配置iptable,将应用container的流量导入到代理container中。

 
   
   
 
  1.   #注入istio 网络代理

  2.   image: docker.io/istio/proxy_debug:0.2.10

  3.         imagePullPolicy: IfNotPresent

  4.         name: istio-proxy

  5.         resources: {}

  6.         securityContext:

  7.           privileged: true

  8.           readOnlyRootFilesystem: false

  9.           runAsUser: 1337

  10.         volumeMounts:

  11.         - mountPath: /etc/istio/proxy

  12.           name: istio-envoy

  13.         - mountPath: /etc/certs/

  14.           name: istio-certs

  15.           readOnly: true

  16.       #使用init container修改iptable

  17.       initContainers:

  18.       - args:

  19.         - -p

  20.         - "15001"

  21.         - -u

  22.         - "1337"

  23.         image: docker.io/istio/proxy_init:0.2.10

  24.         imagePullPolicy: IfNotPresent

  25.         name: istio-init

从上面的分析,我们可以看出Istio的kube-inject工具的用途即是将代理sidecar注入了Bookinfo的kubernetes yaml部署文件中。通过该方式,不需要用户手动修改kubernetes的部署文件,即可在部署服务时将sidecar和应用一起部署。

通过命令查看pod中部署的docker container,确认是否部署了Istio代理

 
   
   
 
  1. kubectl get pods

  2.  

  3. NAME                              READY     STATUS    RESTARTS   AGE

  4. details-v1-3688945616-8hv8x       2/2       Running   0          1d

  5. productpage-v1-2055622944-cslw1   2/2       Running   0          1d

  6. ratings-v1-233971408-8dcnp        2/2       Running   0          1d

  7. reviews-v1-1360980140-474x6       2/2       Running   0          1d

  8. reviews-v2-1193607610-cfhb5       2/2       Running   0          1d

  9. reviews-v3-3340858212-b5c8k       2/2       Running   0          1d

查看reviews pod的中的container,可以看到pod中除reviews container外还部署了一个istio-proxy container

 
   
   
 
  1. kubectl get pod reviews-v3-3340858212-b5c8k -o jsonpath='{.spec.containers[*].name}'

  2.  

  3. reviews istio-proxy

而应用container的流量是如何被导入到istio-proxy中的呢?

原理是Istio proxy在端口15001进行监听,pod中应用container的流量通过iptables规则被重定向到15001端口中。下面我们进入pod内部,通过相关命令来验证这一点。

先通过命令行找到ratings-v1-233971408-8dcnp pod的PID,以用于查看其network namespace內的iptables规则。

 
   
   
 
  1. CONTAINER_ID=$(kubectl get po ratings-v1-233971408-8dcnp -o jsonpath='{.status.containerStatuses[0].containerID}' | cut -10-21)

  2.  

  3. PID=$(sudo docker inspect --format '' $CONTAINER_ID)

可以使用nsenter命令来进入pod的network namespace执行命令。
使用netstat命令可以看到istio proxy代理的监听端口15001

 
   
   
 
  1. sudo nsenter -t ${PID} -n netstat -all | grep 15001

  2.  

  3. tcp        0      0 *:15001                 *:*                     LISTEN

使用iptables命令可以查看到下面的规则

 
   
   
 
  1. sudo nsenter -t ${PID} -n iptables -t nat ---v

  2.  

  3. Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)

  4.  pkts bytes target     prot opt in     out     source               destination

  5.    16   960 ISTIO_REDIRECT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* istio/install-istio-prerouting */

  6.  

  7. Chain INPUT (policy ACCEPT 16 packets, 960 bytes)

  8.  pkts bytes target     prot opt in     out     source               destination

  9.  

  10. Chain OUTPUT (policy ACCEPT 84838 packets, 7963K bytes)

  11.  pkts bytes target     prot opt in     out     source               destination

  12.  1969  118K ISTIO_OUTPUT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* istio/install-istio-output */

  13.  

  14. Chain POSTROUTING (policy ACCEPT 84838 packets, 7963K bytes)

  15.  pkts bytes target     prot opt in     out     source               destination

  16.  

  17. Chain ISTIO_OUTPUT (1 references)

  18.  pkts bytes target     prot opt in     out     source               destination

  19.     0     0 ISTIO_REDIRECT  all  --  *      lo      0.0.0.0/0           !127.0.0.1            /* istio/redirect-implicit-loopback */

  20.  1969  118K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1337 /* istio/bypass-envoy */

  21.     0     0 RETURN     all  --  *      *       0.0.0.0/0            127.0.0.1            /* istio/bypass-explicit-loopback */

  22.     0     0 ISTIO_REDIRECT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* istio/redirect-default-outbound */

  23.  

  24. Chain ISTIO_REDIRECT (3 references)

  25.  pkts bytes target     prot opt in     out     source               destination

  26.    16   960 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* istio/redirect-to-envoy-port */ redir ports 15001

从pod所在network namespace的iptables规则中可以看到,pod的入口和出口流量分别通过PREROUTING和OUTPUT chain指向了自定义的ISTIO_REDIRECT chain,而ISTIO_REDIRECT chain中的规则将所有流量都重定向到了istio proxy正在监听的15001端口中。从而实现了对应用透明的通信代理。


测试路由规则

多次刷新Bookinfo应用的productpage页面,我们会发现该页面中显示的Book Reviews有时候有带红星的评价信息,有时有带黑星的评价信息,有时只有文字评价信息。
这是因为Bookinfo应用程序部署了3个版本的Reviews服务,每个版本的返回结果不同,在没有设置路由规则时,缺省的路由会将请求随机路由到每个版本的服务上,如下图所示:

通过创建一条路由规则route-rule.yaml,将请求流量都引导到Reviews-v1服务上

 
   
   
 
  1. apiVersion: config.istio.io/v1alpha2

  2. kind: RouteRule

  3. metadata:

  4.   name: reviews-default

  5. spec:

  6.   destination:

  7.     name: reviews

  8.   precedence: 1

  9.   route:

  10.   - labels:

  11.       version: v1

启用该路由规则

 
   
   
 
  1. istioctl create -f route_rule.yaml -default

再次打开productpage页面, 无论刷新多少次,显示的页面将始终是v1版本的输出,即不带星的评价内容。
干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序
删除该路由规则

 
   
   
 
  1. istioctl delete -f route_rule.yaml -default

继续刷新productpage页面,将重新随机出现三个版本的评价内容页面。


▍分布式调用追踪

首先修改安装包中的 istio-0.2.10/install/kubernetes/addons/zipkin.yaml 部署文件,增加Nodeport,以便能在kubernetes集群外部访问zipkin界面。

 
   
   
 
  1. apiVersion: v1

  2. kind: Service

  3. metadata:

  4.   name: zipkin

  5.   namespace: istio-system

  6. spec:

  7.   ports:

  8.   - name: http

  9.     port: 9411

  10.     nodePort: 30001

  11.   selector:

  12.     app: zipkin

  13.   type: NodePort

部署zipkin服务。

 
   
   
 
  1. kubectl apply -f istio-0.2.10/install/kubernetes/addons/zipkin.yaml

在浏览器中打开zipkin页面,可以追踪一个端到端调用经过了哪些服务,以及各个服务花费的时间等详细信息,如下图所示:
http://10.12.25.116:30001
干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序

▎性能指标监控

首先修改安装包中的 istio-0.2.10/install/kubernetes/addons/grafana.yaml 部署文件,增加Nodeport,以便能在kubernetes集群外部访问grafana界面。

 
   
   
 
  1. apiVersion: v1

  2. kind: Service

  3. metadata:

  4.   name: grafana

  5.   namespace: istio-system

  6. spec:

  7.   ports:

  8.   - port: 3000

  9.     protocol: TCP

  10.     name: http

  11.     nodePort: 30002

  12.   selector:

  13.     app: grafana

  14.   type: NodePort

prometheus用于收集和存储信息指标,grafana用于将性能指标信息进行可视化呈现,需要同时部署prometheus和grafana服务。

 
   
   
 
  1. kubectl apply -f istio-0.2.10/install/kubernetes/addons/prometheus.yaml

  2.  

  3. kubectl apply -f istio-0.2.10/install/kubernetes/addons/grafana.yaml

首先在浏览器中打开Bookinfo的页面http://10.12.25.116/productpage,刷新几次,以制造一些性能指标数据。

然后打开grafana页面查看性能指标

http://10.12.25.116:30002/dashboard/db/istio-dashboard,如下图所示:

▍参考

  • Istio官方文档

  • Pattern: Service Mesh

  • WHAT’S A SERVICE MESH? AND WHY DO I NEED ONE?

  • A Hacker’s Guide to Kubernetes Networking

以上是关于干货|下一代微服务:手把手教你从零搭建Istio及Bookinfo示例程序的主要内容,如果未能解决你的问题,请参考以下文章

手把手教你从零开始搭建个人博客,20 分钟上手

手把手教你从零开始搭建SpringBoot后端项目框架

手把手教你从零开始搭建SpringBoot后端项目框架

游戏开发实战手把手教你从零跑一个Skynet,详细教程,含案例讲解(服务端 | Skynet | Ubuntu)

游戏开发实战手把手教你从零跑一个Skynet,详细教程,含案例讲解(服务端 | Skynet | Ubuntu)

Jenkins搭建,从零手把手教你入门及项目实践。