到istio的release地址下载安装包,我目前使用1.0.0版:
$ wget https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
解压:
$ tar -zxvf istio-1.0.0-linux.tar.gz
如果手动注入sidecar的话需要使用这个命令,自动注入的话不装这个也行:
$ sudo cp istio-1.0.0/bin/istioctl /usr/local/bin/
$ kubectl apply -f istio-1.0.0/install/kubernetes/helm/istio/templates/crds.yaml
核心组件的部署,官方给出了四种方式,我选择了“without mutual TLS authentication between sidecars”的方式:
$ kubectl apply -f istio-1.0.0/install/kubernetes/istio-demo.yaml
注意:
启动文件默认配置的通过外部LoadBalancer访问istio-ingressgateway,如果没有外部LoadBalancer,需要修改启动文件使用NodePort访问istio-ingressgateway:
sed -i 's/LoadBalancer/NodePort/g' istio-1.0.0/install/kubernetes/istio-demo.yaml
gcr.io和quay.io相关的镜像下载不了的话可以替换为我做好的墙内的镜像:
查看是否所有服务和pod都正常:
Istio装好后,如果想sidecar在应用启动时自动注入到pod中,还需要配置如下4步:
<1>安装istio-sidecar-injector
默认已安装istio-sidecar-injector,安装了istio-sidecar-injector后,kubectl create起应用的时候sidecar容器会直接自动注入到pod中,而不用手动注入。
<2>启用mutating webhook admission controller(k8s 1.9以上支持)
在kube-apiserver的启动参数的admission controller中按正确顺序加入如下两个controller:
注意:1.12.0以上版本,MutatingAdmissionWebhook默认是enable的,只要再在apiserver启动参数–enable-admission-plugins加上ValidatingAdmissionWebhook就行了。
<3>启用admissionregistration api
查看admissionregistration api是否已启用:
$ kubectl api-versions | grep admissionregistration
admissionregistration.k8s.io/v1beta1
<4>为需要自动注入sidecar的namespace打label。
istio-sidecar-injector会为打了istio-injection=enabled
label的namespace中的pod自动注入sidecar:
$ kubectl create namespace istio-test
$ kubectl label namespace istio-test istio-injection=enabled
$ kubectl get namespace -L istio-injection
NAME STATUS AGE ISTIO-INJECTION
default Active 16d
istio-system Active 33m disabled
istio-test Active 56s enabled
kube-public Active 16d
kube-system Active 16d
rook-ceph Active 7d7h
rook-ceph-system Active 7d7h
以上都配置好后,就可以参照官方例子启动samples下的bookinfo示例应用(自动注入sidecar方式):
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/platform/kube/bookinfo.yaml
可以看到每个pod中的容器都是2个,自动注入了一个sidecar容器:
$ kubectl get pods -n istio-test
NAME READY STATUS RESTARTS AGE
details-v1-876bf485f-8ssq5 2/2 Running 0 3m32s
productpage-v1-8d69b45c-vp8tg 2/2 Running 0 3m32s
ratings-v1-7c9949d479-tlhhk 2/2 Running 0 3m32s
reviews-v1-85b7d84c56-mfg2r 2/2 Running 0 3m32s
reviews-v2-cbd94c99b-5bd6z 2/2 Running 0 3m32s
reviews-v3-748456d47b-csdg5 2/2 Running 0 3m32s
注意: 应用的http流量必须使用HTTP/1.1或HTTP/2.0协议,HTTP/1.0协议不支持。
Istio Gateway用来实现bookinfo应用从k8s集群外部可访问。为bookinfo应用创建一个gateway和virtualservice对象:
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/bookinfo-gateway.yaml
$ kubectl get gateway -n istio-test
NAME AGE
bookinfo-gateway 14s
$ kubectl get virtualservice -n istio-test
NAME AGE
bookinfo 10m
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/destination-rule-all.yaml
这个实验演示istio对网络流量的管理功能。
首先打开的Productage页面,由于Productpage的后端有三个不同版本的Reviews实例,默认情况下流量会随机路由到其中一个后端上。可以看到每次刷新,页面中Book Reviews里会随机出现没星、黑星和红星三种情况:
<1>设定所有流量都导到v1版本后端
下面创建一个virtualservice使得所有流量都导向v1版本(没星)的实例:
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-all-v1.yaml
virtual-service-all-v1.yaml中Reviews相关的路由规则如下所示:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
可以看到只有到v1的路由。此时再刷新Productpage的页面,始终都是无星版。
<2>设定jason用户的流量导到v2版本后端
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
virtual-service-reviews-test-v2.yaml内容如下所示:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
这时候再打开网页,用jason用户登录(密码随意),每次刷新页面,都是黑星版。
初始化应用版本路由
如果没有做过3.1.1的请求路由实验,首先执行上面实验中的两步,初始化应用版本路由:
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-all-v1.yaml
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
为jason用户在reviews:v2和ratings两个微服务的访问路径之间注入一个7s延迟的人工“bug”,来测试bookinfo应用的弹性:
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml
查看延迟是否注入成功:
$ kubectl get virtualservice ratings -n istio-test -o yaml
reviews:v2微服务在连接ratings的代码里硬编码了一个10s的连接超时机制,所以尽管引入了一个7s的延迟bug,两个服务之前的端到端流程理论上依然应该是正常的。
以jason用户登录/productpage,我们原本以为bookinfo的页面会在7s后正常加载,但是实际上Reviews区域有报错:
这样,通过注入延迟我们发现了一个bug。
虽然我们引入的7s的延迟在reviews:v2和ratings之间10s的超时机制允许范围内,但是productpage和reviews:v2两个服务的超时时间仅有6s(单次3s加一次重试机制),这导致了最终productpage报错。
以上是企业内部不同微服务独立开发时经常会遇到的一个bug。istio的故障注入机制可以使你在不影响终端用户的情况下发现此类异常。
为jason用户注入一个HTTP Abort故障规则:
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml
查看延迟是否注入成功:
kubectl get virtualservice ratings -n istio-test -o yaml
以jason用户名登录, 看到页面显示:“Ratings service is currently unavailable”:
登出jason,页面显示恢复正常:
这个实例将展示如何将逐渐地将流量从微服务的一个版本切换到另一个版本。
在istio中可以设置一系列的规则将流量按百分比在服务间进行路由。下面这个例子首先各发50%的流量到reviews:v1和reviews:v3,然后通过设置将流量全部发到reviews:v3。
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-all-v1.yaml
打开/product页面,由于所有流量都发送到v1版本,所以,页面一直展示无星版:
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml
验证规则有更新:
kubectl get virtualservice reviews -n istio-test -o yaml
此时不断刷新页面,会在无星版(v1)和红星版(v3)中等概率切换。
kubectl apply -n istio-test -f istio-1.0.0/samples/bookinfo/networking/virtual-service-reviews-v3.yaml
验证规则有更新:
kubectl get virtualservice reviews -n istio-test -o yaml
这个实验使用Istio的加权路由功能将流量从旧版本的 reviews 服务逐渐切换到新版本。
注意,这和使用容器编排平台的部署功能来进行版本迁移完全不同,后者使用了实例扩缩来对流量进行切换。
使用Istio,两个版本的 reviews 服务可以独立地进行扩容和缩容,并不会影响这两个版本服务之间的流量分发。
如果想了解自动伸缩的版本路由,请查看这篇博客使用istio进行金丝雀部署。
更多示例请见官方文档:https://istio.io/docs/tasks/traffic-management/request-timeouts/
此部分将演示如何通过mixer和sidecar获取统一的遥测指标、日志和不同服务间的跟踪信息。这些信息无需开发人员对应用做任何修改,一切都是istio来实现。
这个实验将演示如何配置istio使mesh自动收集服务的遥测指标。
创建一个可以使istio自动产生和收集遥测指标和日志流的yaml文件new_telemetry.yaml:
# Configuration for metric instances
apiVersion: "config.istio.io/v1alpha2"
kind: metric
metadata:
name: doublerequestcount
namespace: istio-system
spec:
value: "2" # count each request twice
dimensions:
reporter: conditional((context.reporter.kind | "inbound") == "outbound", "client", "server")
source: source.workload.name | "unknown"
destination: destination.workload.name | "unknown"
message: '"twice the fun!"'
monitored_resource_type: '"UNSPECIFIED"'
---
# Configuration for a Prometheus handler
apiVersion: "config.istio.io/v1alpha2"
kind: prometheus
metadata:
name: doublehandler
namespace: istio-system
spec:
metrics:
- name: double_request_count # Prometheus metric name
instance_name: doublerequestcount.metric.istio-system # Mixer instance name (fully-qualified)
kind: COUNTER
label_names:
- reporter
- source
- destination
- message
---
# Rule to send metric instances to a Prometheus handler
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: doubleprom
namespace: istio-system
spec:
actions:
- handler: doublehandler.prometheus
instances:
- doublerequestcount.metric
---
# Configuration for logentry instances
apiVersion: "config.istio.io/v1alpha2"
kind: logentry
metadata:
name: newlog
namespace: istio-system
spec:
severity: '"warning"'
timestamp: request.time
variables:
source: source.labels["app"] | source.workload.name | "unknown"
user: source.user | "unknown"
destination: destination.labels["app"] | destination.workload.name | "unknown"
responseCode: response.code | 0
responseSize: response.size | 0
latency: response.duration | "0ms"
monitored_resource_type: '"UNSPECIFIED"'
---
# Configuration for a stdio handler
apiVersion: "config.istio.io/v1alpha2"
kind: stdio
metadata:
name: newhandler
namespace: istio-system
spec:
severity_levels:
warning: 1 # Params.Level.WARNING
outputAsJson: true
---
# Rule to send logentry instances to a stdio handler
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: newlogstdio
namespace: istio-system
spec:
match: "true" # match for all requests
actions:
- handler: newhandler.stdio
instances:
- newlog.logentry
---
生成配置:
kubectl apply -f new_telemetry.yaml
curl 10.142.232.150:31380/productpage
#####<3>验证指标数据成功产生和收集:
将Prometheus改成用nodePort暴露给外部访问:
kubectl edit svc prometheus -n istio-system
ports:
- name: http-prometheus
port: 9090
protocol: TCP
targetPort: 9090
nodePort: 30090
selector:
app: prometheus
sessionAffinity: None
type: NodePort
打开Prometheus的console tab,查看数据:
更多指标请参看:Querying Istio Metrics,还可以结合grafana进行可视化展示
查看请求过程中生成的日志流:
kubectl -n istio-system logs $(kubectl -n istio-system get pods -l istio-mixer-type=telemetry -o jsonpath='{.items[0].metadata.name}') -c mixer | grep \"instance\":\"newlog.logentry.istio-system\"
还是使用上面的Prometheus做一些查询。打开Prometheus,在Graph页面的Expression输入框中输入查询语句进行查询。
istio_requests_total{destination_service="productpage.istio-test.svc.cluster.local"}
istio_requests_total{destination_service="reviews.istio-test.svc.cluster.local", destination_version="v3"}
rate(istio_requests_total{destination_service=~"productpage.*", response_code="200"}[5m])
这个实验展示Istio-enabled应用是怎样通过配置来收集跟踪信息的。跟踪功能是语言、框架、平台无关的。
将Jaeger dashboard通过nodePort暴露给外部访问:
kubectl edit svc jaeger-query -n istio-system
ports:
- name: query-http
port: 16686
protocol: TCP
targetPort: 16686
nodePort: 30686
selector:
app: jaeger
sessionAffinity: None
type: NodePort
在 Jaeger dashboard里从Service下选择productpage,点击Find Traces
按钮,可以看到跟踪信息:
1.官方部署文档
2.注入sidecar的一些细节
3.官方bookinfo示例应用
4.设置ingress
5.智能路由之–请求路由
6.智能路由之–故障注入
7.智能路由之–流量切换
8.深度检测之–指标收集
9.深度检测之–指标查询
10.深度检测之–分布式追踪