前言
istio是服务网格的一种具体实现方案,在网上已经有非常非常多的相关介绍了,本文主要介绍如何搭建一个开发环境的istio。
准备工作
istio提供了多种部署方式:
- istioctl: 官方安装工具,需要k8s集群
- Istio Operator: 官方安装工具,需要k8s集群
- helm:使用k8s的helm安装
- 多集群安装:跨多个k8s集群安装
- 虚拟机安装:虚拟机直接安装
出于开发使用和安装简单,我们使用istioctl的方式安装,需要做如下准备:
- 部署一个k8s集群,参考k8s部署实战
- 下载istio部署包
curl -L https://istio.io/downloadIstio | sh -
下载后进入部署包目录:
cd istio-1.12.1
部署包内包含了客户端工具bin/istioctl
和示例应用samples
。
将istioctl客户端加入搜索路径:
export PATH=$PWD/bin:$PATH
开始安装
下载的安装包里包含了不同部署场景的配置。
- 面向开发使用的场景我们选用demo,这里包含了一组专门为测试准备的功能集合。
$ istioctl install --set profile=demo -y
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete
- 给命名空间添加标签,指示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中:
- 部署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的命令查看部署的情况:
- 查看部署情况:
$ 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,才表示部署完成。
- 确认服务已经正常运行:
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内部的资源无法被外部直接访问,我们还需要开放外部访问。
- 开放外部访问
要开放示例应用的外部访问,我们需要一个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机器,请参考官网文档
- 支持外部访问
我们使用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的环境上部署和实施。