既然我们已经对Istio的核心概念有了深入的了解,那就让我们来使用它吧。我们将部署包含在Istio发行版中的示例Bookinfo应用程序,稍后我们将使用一些Istio bells和whistles对其进行改进。具体来说,我们将演示Zipkin的分布式跟踪和JWT的强制用户身份验证。
二、安装
要求
这些示例将使用istio1.4。此版本的Istio已经过Kubernetes 1.13、1.14和1.15版的测试。这些例子已经用Kubernetes 1.14.8进行了验证。
假设您可以访问Kubernetes集群和Kubernetes中的坚实背景。Docker Desktop附带的Kubernetes集群就可以了。
安装
首先下载Istio发行版:
代码语言:javascript复制curl -L https://istio.io/downloadIstio | sh-
移至Istio软件包目录。在撰写本文时,最新的稳定Istio版本是1.4.2
。您可能有较新的版本,因此请相应地更改路径。
cd istio-1.4.2
安装目录包含以下内容:
- Istio资源定义-将Istio安装到Kubernetes集群所需的。回想一下,Istio只是部署到Kubernetes中的另一个应用程序。
samples/
目录中的示例应用程序。- 目录中的
istioctl
客户端二进制bin/
文件。
下一步是可选的,但强烈建议您这样做。添加istioctl
到您的路径:
export PATH=$PWD/bin:$PATH
Istio提供了几个配置文件。这些配置文件为Istio控制平面和Istio数据平面的sidecar提供了固定的定制。您可以从Istio的内置配置文件之一开始,然后根据您的特定需求定制配置。有五个内置配置文件。我们将简要介绍三个较常见的三个。
default
:为生产部署推荐的配置文件。具有最少的附加组件,并使用生产级默认值。demo
:用于展示Istio功能的广度。具有完整的插件集和配置优化,可最大程度地减少资源使用。它还包含大量的跟踪和访问日志记录,因此通常不建议将其用于对性能敏感的部署。minimal
:Istio的简约部署,足以利用其流量管理功能。
让我们继续安装demo
配置文件:
istioctl manifest apply --set profile=demo
--set values.tracing.enabled=true
--set values.tracing.provider=zipkin
首次运行此操作可能需要一段时间。Kubernetes将部署十二个左右的服务,并引入一堆Docker映像。此外,我们还启用了Zipkin插件,我们希望稍后再展示。如果您以前安装的Istio没有此附加组件,请不用担心-您可以随时重新运行istioctl manifest apply
,指定备用配置文件或一组不同的附加组件。
部署Istio后,通过查询istio-system
名称空间来验证是否存在所有组件。(这是默认的Istio根名称空间,如有必要,可以将其重新配置为备用名称空间。)
kubectl get svc -n istio-system
输出:
代码语言:javascript复制NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 10.105.190.242 <none> 3000/TCP 3d3h
istio-citadel ClusterIP 10.100.144.109 <none> 8060/TCP,15014/TCP 3d3h
istio-egressgateway ClusterIP 10.101.65.30 <none> 80/TCP,443/TCP,15443/TCP 3d3h
istio-galley ClusterIP 10.100.233.70 <none> 443/TCP,15014/TCP,9901/TCP,15019/TCP 3d3h
istio-ingressgateway LoadBalancer 10.106.108.201 localhost 15020:30912/TCP,80:30218/TCP,443:30059/TCP,15029:31861/TCP,15030:32620/TCP,15031:30363/TCP,15032:30868/TCP,15443:30359/TCP 3d3h
istio-pilot ClusterIP 10.108.102.237 <none> 15010/TCP,15011/TCP,8080/TCP,15014/TCP 3d3h
istio-policy ClusterIP 10.111.28.108 <none> 9091/TCP,15004/TCP,15014/TCP 3d3h
istio-sidecar-injector ClusterIP 10.103.185.22 <none> 443/TCP 3d3h
istio-telemetry ClusterIP 10.111.73.89 <none> 9091/TCP,15004/TCP,15014/TCP,42422/TCP 3d3h
kiali ClusterIP 10.109.207.229 <none> 20001/TCP 3d3h
prometheus ClusterIP 10.96.164.188 <none> 9090/TCP 3d3h
tracing ClusterIP 10.108.205.179 <none> 80/TCP 3d3h
zipkin ClusterIP 10.107.7.90 <none> 9411/TCP 3d3h
确保相应的Istio Pod也已部署且状态为Running
。首次部署时,READY
每个Pod的状态可能会从一段时间转换0/1
为1/1
:
kubectl get pods -n istio-system
输出:
代码语言:javascript复制NAME READY STATUS RESTARTS AGE
grafana-5f798469fd-qmzqd 1/1 Running 1 3d3h
istio-citadel-6dc789bc4c-qcpq6 1/1 Running 2 3d3h
istio-egressgateway-75cb89bd7f-96xbw 1/1 Running 1 3d3h
istio-galley-5bcd89bd9c-6z9hm 1/1 Running 1 3d3h
istio-ingressgateway-7d6b9b5ffc-n9vrp 1/1 Running 1 3d3h
istio-pilot-678b45584b-h2pxv 1/1 Running 1 3d3h
istio-policy-9f78db4cb-bjk54 1/1 Running 5 3d3h
istio-sidecar-injector-7d65c79dd5-th5ts 1/1 Running 2 3d3h
istio-telemetry-fc488f958-9np6n 1/1 Running 5 3d3h
istio-tracing-6bc9795bd7-4gqrr 1/1 Running 1 3d2h
kiali-7964898d8c-bsxvd 1/1 Running 1 3d3h
prometheus-586d4445c7-qcjxk 1/1 Running 1 3d3h
启动sidecar注入
Istio将自动将sidecar容器注入到以标记为的任何命名空间中启动的应用程序容器中istio-injection=enabled
。
由于我们的Bookinfo示例将在default
名称空间中托管,因此让我们为侧向注入注入做好准备:
kubectl label namespace default istio-injection=enabled
Istio不会在您的应用程序上强制进行自动sidecar注入。您可以istioctl kube-inject
用来丰富任何现有的资源定义,在部署它们之前将Envoy容器显式注入到您的应用程序容器中:
istioctl kube-inject -f <resource-definitions>.yaml | kubectl apply -f -
三、部署BookInfo
关于Bookinfo示例
Bookinfo应用程序包含在samples/bookinfo/
目录的Istio发行版中。这是一个多语言应用程序,用于显示有关图书的信息,类似于在线图书商店的目录条目。它包含以有向无环图(DAG)安排通信的四个微服务:
productpage
:调用details
和reviews
服务以填充页面。
details
:包含书籍信息。
reviews
:包含书评。根据实现版本的不同,该reviews
服务将调用该ratings
服务以获得书评。reviews
部署了三个版本:
v1
不致电ratings
服务。v2
呼叫ratings
服务,将每个等级显示为1到5个黑色星标。v3
呼叫ratings
服务,将每个评分显示为1到5个红色星标。
ratings
:包含书评随附的书评信息。
Bookinfo的高级体系结构如下所示。
部署Bookinfo
使用kubectl
以下方法部署应用程序:
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
注意:如果您选择不启用自动sidecar注入功能,则可以使用以下方法实现等效功能istioctl
:
kubectl apply -f <(istioctl kube-inject -f样本/bookinfo/platform/kube/bookinfo.yaml)
运行kubectl get svc
并kubectl get po
验证是否已部署该应用程序:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.104.247.109 <none> 9080/TCP 3d4h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d5h
productpage ClusterIP 10.102.89.169 <none> 9080/TCP 3d4h
ratings ClusterIP 10.103.85.175 <none> 9080/TCP 3d4h
reviews ClusterIP 10.100.227.109 <none> 9080/TCP 3d4h
NAME READY STATUS RESTARTS AGE
details-v1-c5b5f496d-zz5dh 2/2 Running 2 3d4h
productpage-v1-c7765c886-zdqv4 2/2 Running 0 2m17s
ratings-v1-f745cf57b-lln4d 2/2 Running 2 3d4h
reviews-v1-75b979578c-t4ns7 2/2 Running 0 2m17s
reviews-v2-597bf96c8f-jrs2c 2/2 Running 0 2m17s
reviews-v3-54c6c64795-zxzk2 2/2 Running 0 2m17s
在Istio中部署后,Bookinfo的体系结构将进行轻微修改以反映Sidecar代理的存在:
让我们花点时间环顾四周。第一步是确定我们是否有虚拟服务:
代码语言:javascript复制kubectl get vs
输出:
代码语言:javascript复制NAME GATEWAYS HOSTS AGE
bookinfo [bookinfo-gateway] [*] 3d4h
将虚拟服务配置转储到YAML:
代码语言:javascript复制kubectl get vs bookinfo -o yaml
输出:
代码语言:javascript复制apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
*** omitted for brevity ***
creationTimestamp: "2019-12-25T01:54:39Z"
generation: 1
name: bookinfo
namespace: default
resourceVersion: "6896"
selfLink: /apis/networking.istio.io/v1alpha3/namespaces/default/virtualservices/bookinfo
uid: 85c222bd-1d4b-11ea-84b7-025000000001
spec:
gateways:
- bookinfo-gateway
hosts:
- '*'
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
这告诉我们什么?首先,我们有一个名为的虚拟服务,可将bookinfo
请求捕获到任何(*
)主机。虚拟服务将接受与中指定的路径匹配的请求,spec.http.match
并将其转发到productpage
端口上的目标9080
。
我们还可以看到bookinfo
虚拟服务已绑定到bookinfo-gateway
网关。让我们深入研究一下:
kubectl get gw bookinfo-gateway -o yaml
输出:
代码语言:javascript复制apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
*** omitted for brevity ***
creationTimestamp: "2019-12-25T01:54:39Z"
generation: 1
name: bookinfo-gateway
namespace: default
resourceVersion: "6895"
selfLink: /apis/networking.istio.io/v1alpha3/namespaces/default/gateways/bookinfo-gateway
uid: 85bf7194-1d4b-11ea-84b7-025000000001
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP
这是在通知我们,一个Istio网关正在80
为所有主机的端口提供HTTP通信。我们应该只已经调用Bookinfo服务,但是首先我们需要知道从群集外部可以访问网关的地址和端口号。答案取决于如何公开底层的Istio入口网关服务。(请记住,Istio由常规的Kubernetes组件组成-必须公开它们才能从群集外部访问。)
kubectl get svc istio-ingressgateway -n istio-system
输出:
代码语言:javascript复制NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.106.108.201 localhost 15020:30912/TCP,80:30218/TCP,443:30059/TCP,15029:31861/TCP,15030:32620/TCP,15031:30363/TCP,15032:30868/TCP,15443:30359/TCP 3d20h
我碰巧在Docker Desktop附带的Kubernetes集群上运行此示例,因此在我的情况下,EXTERNAL-IP
设置为localhost
。您可能正在阿里云或者腾讯云中运行Kubernetes集群,在这种情况下,LoadBalancer
将使用云本地负载均衡器(例如ELB或NLB)来实现服务类型。或者,您可能会发现自己处于不支持LoadBalancer
服务的环境中(例如,不带MiniKube的环境),tunnel
在这种情况下,EXTERNAL-IP
将会显示为<none>
或永久显示<pending>
。在这种情况下,你可以使用它的节点端口通过检查端口的端口映射访问入口网关服务80
在PORT(S)
列。
让我们调用我们的应用程序。浏览到localhost / productpage。(适当地替换主机和端口。)
刷新屏幕几次。您会注意到,每次提供的视图都略有不同。这是因为该reviews
服务正在选择带有标签的所有Pod app: reviews
。我们稍后会处理。
恭喜你!您已经使用Istio成功部署了第一个应用程序。
四、使用Zipkin进行分布式跟踪
在对Bookinfo部署进行任何重大更改之前,让我们首先使用Zipkin来了解流量如何在整个微服务架构中流动。
无法直接访问Zipkin。要使用它,您必须设置临时端口转发:
代码语言:javascript复制istioctl dashboard zipkin
这将在新的浏览器选项卡中启动Zipkin UI。单击“查找跟踪”按钮以查看最近的跟踪:
Zipkin将呈现遍历所选服务的跟踪。您可以展开跟踪,以显示基础跨度:
Zipkin还使我们能够可视化服务之间的高级依赖关系。点击屏幕顶部的“依赖关系”链接:
还不错吧?我们不费吹灰之力就得到了所有这些。
五、量身定制的路由
目前,到reviews
服务的路由到处都是:随机为客户提供三种版本的服务。让我们围绕如何向消费者提供服务的方式进行一些调整。运行以下命令,这将kubectl
通过标准输入(heredoc样式)注入一对资源定义。
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: bob
route:
- destination:
host: reviews
subset: v1
- route:
- destination:
host: reviews
subset: v3
weight: 25
- destination:
host: reviews
subset: v2
weight: 75
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
EOF
现在v3
,我们为25%的普通访问者提供了金丝雀放映服务,其余的仍在访问中v2
。在此示例中,我们有一个特别挑剔的用户-bob
可能对我们来说非常重要。登录后将始终为该用户提供服务v1
。
立即尝试Bookinfo网站。刷新页面主要用于v2
,偶尔v3
会通过。与另一个用户登录-例如,charlie
-行为仍然相同。(顺便说一句,密码字段纯粹是装饰性的-任何密码都可以使用。)现在注销,然后以用户身份重新登录bob
。屏幕将呈现v1
视图,而不是您按下该刷新按钮的次数。
注意:*如果您想知道,Istio对用户身份没有任何特殊的了解。该
*end-user*
头仅仅通过所附*productpage*
的所有身份验证的会话服务。*
启用原始身份验证
身份验证是服务网格的另一个常见用例。就像现成的API网关一样,服务网格可以在现有服务之上提供透明的身份验证和授权控制。我们的下一个示例将使用JSON Web令牌来验证用户对服务的身份。与验证服务的传输身份验证相反,Istio将此称为源身份验证。
为了试验JWT身份验证,我们需要一个有效的JWT和一个JWKS(JSON Web密钥集)端点。后者是一组签名的公共密钥,可用于验证JWT。Istio的好伙伴为我们提供了一个示例JWKS端点。接下来,我们将创建一个Policy
资源,该资源要求对服务使用JWT productpage
,但仅对于以/productpage
or/api/v1
路径开头的资源。当同一应用程序还提供需要向未经身份验证的用户开放的静态内容时,选择性身份验证很有用。
cat <<EOF | kubectl apply -f -
apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:
name: "productpage-policy"
namespace: default
spec:
targets:
- name: productpage
origins:
- jwt:
issuer: "testing@secure.istio.io"
jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.4/security/tools/jwt/samples/jwks.json"
trigger_rules:
- included_paths:
- prefix: /productpage
- prefix: /api/v1
principalBinding: USE_ORIGIN
EOF
Give Istio a few seconds to pro
给Istio几秒钟的时间来传播新策略。然后使用调用productpage
服务curl
,仅输出状态代码:
curl -s http:// localhost / productpage -o / dev / null -w“%{http_code} n”
导致:
代码语言:javascript复制401
未经授权,符合预期。让我们再试一次,这次传入一个有效的JWT:
代码语言:javascript复制JWT=$(curl https://raw.githubusercontent.com/istio/istio/release-1.4/security/tools/jwt/samples/demo.jwt -s)
curl -H "Authorization: Bearer $JWT" -s http://localhost/productpage -o /dev/null -w "%{http_code}n"
导致:
代码语言:javascript复制200
我们已经成功启用了承载令牌认证。这意味着我们现在可以通过简单地插入备用JWKS文件,用外部身份提供程序(例如AWS Cognito)替换粗略的身份验证表单。
四、用Grafana可视化
采用服务网格的即时满足之一是开箱即用的遥测数量。我们已经研究了使用Zipkin进行分布式跟踪。现在让我们看一下Istio提供的服务和网格级别指标。
在尝试该示例之前,让我们删除在上一个示例中使用的身份验证策略:
代码语言:javascript复制kubectl delete policy productpage-policykubectl删除策略productpage-policy
demo
Istio的配置文件随附了Prometheus和Grafana。我们可以通过以下istio dashboard
命令代理对Grafana的访问:
istioctl dashboard grafana
这将打开一个浏览器标签到Grafana主页。针对Istio行为的各个方面,有几十个预装的仪表板。在左上角,选择“仪表板”,然后选择“ Istio服务仪表板”。
最初的印象可能令人印象深刻:空图和显示“无数据”的小部件。那不应该令我们感到惊讶;毕竟,没有人正在使用我们的Bookinfo服务。让我们模拟一些流量:
代码语言:javascript复制for i in `seq 1 1000`; do
curl -s -o /dev/null http://localhost/productpage
done
返回信息中心,然后productpage.default.svc.cluster.local
从“服务”下拉菜单中选择。如果下拉菜单为空,请刷新屏幕,然后重新填充屏幕。仪表盘将像圣诞树一样点亮。我们将看到我们的请求吞吐量(每秒查询),错误率,周转时间(请求持续时间)以及更细粒度的指标。
花时间浏览其他仪表板。Istio公开了其对基础控制平面组件(混音器,城堡,飞行员和厨房)的关键指标。此外,Istio还提供了一个方便的摘要“ Istio Performance Dashboard”,它将关键组件合并到一个视图中。
可以将服务网格想象为在后台工作的小精灵,毫不客气且未被承认,以帮助进行流量管理,检测和可观察性,安全策略实施以及其他平凡但必不可少的任务,而这会让您无所适从在您的应用程序代码中实现。特别是在信息安全方面,即使在客户端库的帮助下,在应用程序层实现这些问题也从未如此容易,这也解释了商业API网关供应商的兴旺发展。
本文仅涉及Istio的表面。我们没有讨论诸如速率限制,断路器,退避和重试之类的弹性模式。我们也没有涵盖故障注入或混乱测试-可靠性工程的整个领域又节省了一天。Istio的高级负载平衡功能,证书管理和授权功能都被忽略了。在文章变得霸道之前,只能容纳这么多文章。尽管如此,您现在应该已经具备了在应用程序生态系统中开始使用Istio的必要知识和工具。
毫无疑问,要熟练掌握Istio,必须进行大量练习,但是与Kubernetes陡峭的学习曲线相比,这是一种缓慢的提升。此外,与正确地隔离实现每个功能并长期保持这些功能所需的努力相比,回报确实使投资看起来非常可行。
文丨Soundhearer
图丨来源于网络