简介
Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,而不需要对服务的代码做任何改动。
istio 适用于容器或虚拟机环境(特别是 k8s),兼容异构架构。
istio 使用 sidecar(边车模式)代理服务的网络,不需要对业务代码本身做任何的改动。
HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡。
istio 通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制;支持访问控制、速率限制和配额。
istio 对出入集群入口和出口中所有流量的自动度量指标、日志记录和跟踪。
Istio Gateway | 阿里云Ingress Controller | NGINX Ingress Controller | |
根据HTTP Header选择路由规则 | 支持 | 支持 | 仅支持单个Header,不支持多个Header组合 |
Header规则支持正则表达式 | 支持 | 支持 | 支持 |
服务之间设置权重拆分流量 | 支持 | 支持 | 支持 |
Header和权重规则组合使用 | 支持 | 支持 | 支持 |
路由规则检查 | 支持 | 不支持 | 不支持 |
路由规则粒度 | service下的不同pod | service | service |
支持的协议 | HTTP1.1/HTTP2/gRPC/TCP/Websockets/MongoDB | HTTP1.1/HTTP2/gRPC/TCP/Websockets | HTTP1.1/HTTP2/gRPC/TCP/Websockets |
部署istio
1、下载istio官方的部署包网址:https://github.com/istio/istio/releases/tag/1.6.7
wget https://github.com/istio/istio/releases/download/1.6.7/istio-1.6.7-linux-amd64.tar.gz
2、解压安装包并加入环境变量中
mkdir /application/
tar xvf istio-1.6.7-linux-amd64.tar.gz -C /application /
echo "export PATH=$PATH:/application/istio-1.6.7/bin" >>/etc/profile && source /etc/profile
3、安装istio(ps:一定要保证k8s集群正常运行)
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 7d2h v1.18.0
node-1 Ready 7d2h v1.18.0
node-2 Ready 7d2h v1.18.0
[root@k8s-master ~]#
4、安装
[root@k8s-master bin]# istioctl manifest apply --set profile=demo
Detected that your cluster does not support third party JWT authentication. Falling back to less secure first party JWT. See https://istio.io/docs/ops/best-practices/security/#configure-third-party-service-account-tokens for details.
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Egress gateways installed
✔ Addons installed
✔ Installation complete
[root@k8s-master bin]#
查询部署完成情况
root@k8s-master bin]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 10.100.91.88 3000/TCP 2m5s
istio-egressgateway ClusterIP 10.106.229.1 80/TCP,443/TCP,15443/TCP 2m6s
istio-ingressgateway LoadBalancer 10.111.48.40 15021:30045/TCP,80:31929/TCP,443:31560/TCP,31400:31134/TCP,15443:31166/TCP 2m6s
istiod ClusterIP 10.101.173.49 15010/TCP,15012/TCP,443/TCP,15014/TCP,853/TCP 2m30s
jaeger-agent ClusterIP None 5775/UDP,6831/UDP,6832/UDP 2m5s
jaeger-collector ClusterIP 10.103.41.41 14267/TCP,14268/TCP,14250/TCP 2m5s
jaeger-collector-headless ClusterIP None 14250/TCP 2m5s
jaeger-query ClusterIP 10.97.12.213 16686/TCP 2m5s
kiali ClusterIP 10.105.102.92 20001/TCP 2m5s
prometheus ClusterIP 10.98.88.198 9090/TCP 2m5s
tracing ClusterIP 10.97.49.170 80/TCP 2m5s
zipkin ClusterIP 10.111.114.233 9411/TCP 2m5s
[root@k8s-master bin]# kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-b54bb57b9-4ncvl 1/1 Running 0 2m28s
istio-egressgateway-64bc874f5c-bxqb8 1/1 Running 0 2m29s
istio-ingressgateway-6b947b8c5d-xdttt 1/1 Running 0 2m29s
istio-tracing-9dd6c4f7c-vljvl 1/1 Running 0 2m28s
istiod-654b4b468b-lfhgf 1/1 Running 0 2m54s
kiali-d45468dc4-q6wbn 1/1 Running 0 2m28s
prometheus-77566c9987-285jt 2/2 Running 0 2m28s
[root@k8s-master bin]#
[root@k8s-master bin]# kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort"}}'
service/kiali patched
[root@k8s-master bin]# kubectl describe svc -n istio-system kiali
Name: kiali
Namespace: istio-system
Labels: app=kiali
install.operator.istio.io/owning-resource=installed-state
install.operator.istio.io/owning-resource-namespace=istio-system
operator.istio.io/component=AddonComponents
operator.istio.io/managed=Reconcile
operator.istio.io/version=1.6.7
release=istio
Annotations: Selector: app=kiali
Type: NodePort
IP: 10.105.102.92
Port: http-kiali 20001/TCP
TargetPort: 20001/TCP
NodePort: http-kiali 31822/TCP #节点访问的端口
Endpoints: 10.244.247.6:20001
Session Affinity: None
External Traffic Policy: Cluster
Events:
[root@k8s-master bin]#
访问node节点加上端口 192.168.10.112:31822
默认登陆账户和密码为admin/admin
也可以创建ingress文件:istio-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: istio
namespace: istio-system
spec:
rules:
- host: istio.grafana.com
http:
paths:
- path: /
backend:
serviceName: grafana
servicePort: 3000
- host: kiali.k8s.com
http:
paths:
- path: /
backend:
serviceName: kiali
servicePort: 20001
- host: istio.prometheus.com
http:
paths:
- path: /
backend:
serviceName: prometheus
servicePort: 9090
1、开启sidecar自动注入
kubectl label namespace default istio-injection=enabled
2、使用kubectl部署bookinfo并创建网关
kubectl apply -f /application/istio-1.6.7/samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f /application/istio-1.6.7/samples/bookinfo/networking/bookinfo-gateway.yaml
3、设置访问网关的 INGRESS_HOST 和 INGRESS_PORT 变量,查询是否有外部负载均衡器
kubectl get svc istio-ingressgateway -n istio-system
EXTERNAL-IP是none或是pending说明没有问题
修改istio的网关为nodeport模式
kubectl patch service istio-ingressgateway -n istio-system -p '{"spec":{"type":"NodePort"}}'
采用nodeport方式暴露istio-ingressgateway
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}')
#获取 ingress IP 地址:
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o 'jsonpath={.items[0].status.hostIP}')
查询URL
echo $INGRESS_HOST:$INGRESS_PORT
192.168.10.112:30637
使用浏览器访问bookinfo
http://192.168.10.112:30637/productpage
重复刷新可以发现星星发生变化说明部署成功
1. 定义目标与规则
istio 服务网格中对服务进行了进一步抽象:
可以使用 Pod 标签对具体的服务进程进行分组;
可以定义服务的负载均衡策略;
可以为服务指定 TLS 要求;
可以为服务设置连接池大小。
istio 中,同一服务不同组别的后端被称为 子集(Subset) ,也经常被称为 服务版本 。
在 istio 中,建议为每个网格都设置明确的目标访问规则,在通过 istio 流量控制之后,会选择明确的子集,根据规则或在子集中规定的流量策略来进行访问,
这种规则被称为 DestinationRule ,样例如下:
cat flaskapp-destinationrule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: flaskapp
spec:
host: flaskapp.default.svc.cluster.local
trafficPolicy:
loadBalancer:
simple: LEAST_CONN
subsets:
- name: v1
labels:
version: v1
trafficPolicy:
loadBalancer: ROUND_ROBIN
- name: v2
labels:
version: v2
规则需要注意的地方如下:
host: 必要字段,代表1个 Service 资源,或1个 ServiceEntry 定义的外部服务。
建议:为防止不同命名空间服务重名,可以使用完全限定名。
trafficPolicy: 流量策略,在 DestinationRule 与 Subset 都可以定义,Subset 中的级别更高。
subsets: 该字段使用标签选择器定义不同的子集。
2. 定义默认路由
2.1 定义默认路由
建议每个服务都创建1个默认路由,在没有特定的路由规则时,使用默认路由规则访问指定子集,一以此确保服务在默认情况下的行为稳定性,样例如下:
cat flaskapp-default-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: flaskapp
spec:
hosts:
- flaskapp.default.svc.cluster.local
http:
- route:
- destination:
host: flaskapp.default.svc.cluster.local
subset: v1
VirtualService: istio 流量控制过程中的枢纽,负责对流量进行甄别与转发。
针对主机名工作,但 hosts 字段是一个数组内容,可以针对多个主机名进行工作。
可以为多种协议的流量提供服务,如 http ,tcp ,tls等。
在 http 的下一级,即具体的路由规则。
支持多条路由。
2.2 验证
# 应用目标规则与默认路由
kubectl apply -f flaskapp-destinationrule.yaml
kubectl apply -f flaskapp-default-vs.yaml
# 验证,可同步观察 kiali & Jaeger 等
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v1 -o jsonpath='{.items..metadata.name}') /bin/bash
bash-4.4# for i in `seq 100` ; do http --body http://flaskapp.default/env/version ; done
2.3 总结
在 istio 中部署1个业务应用时,建议:
使用 app 标签表明应用身份;
使用 version 标签表明应用版本;
创建目标规则;
创建默认路由规则,默认路由得配置清单应该成为服务网格环境下的必要部署内容。
3. 流量拆分与迁移
3.1 权重
cat flaskapp-default-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: flaskapp
spec:
hosts:
- flaskapp.default.svc.cluster.local
http:
- route:
- destination:
host: flaskapp.default.svc.cluster.local
subset: v1
weight: 70
- destination:
host: flaskapp.default.svc.cluster.local
subset: v2
weight: 30
# 应用
kubectl apply -f flaskapp-default-vs.yaml
# 验证,可同步观察 kiali & Jaeger 等
# 因是权重的原因,验证时样本量需要大一些
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v1 -o jsonpath='{.items..metadata.name}') /bin/bash
bash-4.4# for i in `seq 100` ; do http --body http://flaskapp.default/env/version ; done | awk -F "v1" '{print NF-1}'
注意点:
流量分配是有权重的,且权重总和必须是 100 ;
如果不显示声明权重,则默认值是 100 。
3.2 获取 istio 对象
kubectl get , kubectl api-resources 列出当前集群支持的所有对象类型
Kiali --> Istio Config
4. 金丝雀部署
金丝雀部署:在发布新版本时,部署的新版本并不对外开放,而选择一小部分用户为测试目标,这部分用户对服务的访问会指向特定的版本,通过对这些金丝雀用户的使用情况的观察,来确定新版本服务的发布效果,在确定结果之前,所有其他用户都继续使用原有版本。
4.1 金丝雀部署
cat flaskapp-default-vs-canary.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: flaskapp
spec:
hosts:
- flaskapp.default.svc.cluster.local
http:
- match:
- headers:
lab:
exact: canary
route:
- destination:
host: flaskapp.default.svc.cluster.local
subset: v2
- route:
- destination:
host: flaskapp.default.svc.cluster.local
subset: v1
注意点:
match 字段提供来丰富的匹配功能,匹配范围不仅包括 http header , 还包含 uri , scheme , method , authority , 端口 , 来源标签及 gateway 等;
exact 代表完全匹配,另有 prefix 代表前缀, regex 代表正则表达式的匹配方式
4.2 验证
bash-4.4# for i in `seq 10` ; do http --body http://flaskapp.default/env/version lab:canary ; done
5. 根据来源服务进行路由
cat flaskapp-default-vs-src.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: flaskapp
spec:
hosts:
- flaskapp.default.svc.cluster.local
http:
- match:
- sourceLabels:
app: sleep
version: v1
route:
- destination:
host: flaskapp.default.svc.cluster.local
subset: v1
- route:
- destination:
host: flaskapp.default.svc.cluster.local
subset: v2
# 应用
kubectl apply -f flaskapp-default-vs-src.yaml
测试
# 验证
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v1 -o jsonpath='{.items..metadata.name}') /bin/bash
bash-4.4# for i in `seq 10` ; do http --body http://flaskapp.default/env/version; done
# sleep v1
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v2 -o jsonpath='{.items..metadata.name}') /bin/bash
bash-4.4# for i in `seq 10` ; do http --body http://flaskapp.default/env/version; done
# sleep v2
6. 对URI进行重定向
6.1 redirect
cat flaskapp-default-vs-uri.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: flaskapp
spec:
hosts:
- flaskapp.default.svc.cluster.local
http:
- match:
- sourceLabels:
app: sleep
version: v1
uri:
exact: "/env/HOSTNAME"
redirect:
uri: "/env/version"
- route:
- destination:
host: flaskapp.default.svc.cluster.local
subset: v2
# 应用
kubectl apply -f flaskapp-default-vs-uri.yaml
测试 # 验证 sleep v2,正常返回
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v2 -o jsonpath='{.items..metadata.name}') -- \
http http://flaskapp.default/env/HOSTNAME
HTTP/1.1 200 OK
content-length: 28
content-type: text/html; charset=utf-8
date: Wed, 12 Jun 2019 08:05:25 GMT
server: envoy
x-envoy-upstream-service-time: 1
flaskapp-v2-59b5b6cb94-jdfp4
# 验证 sleep v1
# 返回 "301" 重定向代码
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v1 -o jsonpath='{.items..metadata.name}') -- \
http http://flaskapp.default/env/HOSTNAME
HTTP/1.1 301 Moved Permanently
content-length: 0
date: Wed, 12 Jun 2019 08:06:17 GMT
location: http://flaskapp.default/ev/version
server: envoy
# "--follow" 跟随重定向指令,重验证
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v1 -o jsonpath='{.items..metadata.name}') -- \
http --follow http://flaskapp.default/env/HOSTNAME
HTTP/1.1 200 OK
content-length: 2
content-type: text/html; charset=utf-8
date: Wed, 12 Jun 2019 08:09:26 GMT
server: envoy
x-envoy-upstream-service-time: 2
v2注意点:
redirect 指令会把 URI 整体替换,灵活性不高;
301 指令无法支持 Post 方法, istio 提供了 rewrite 方式来提供这种在调用前进行 URI 重写的支持。
6.2 rewrite
cat httpbin-default-vs.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- httpbin.default.svc.cluster.local
http:
- match:
- uri:
exact: "/get"
rewrite:
uri: "/post"
route:
- destination:
host: httpbin.default.svc.cluster.local
- route:
- destination:
host: httpbin.default.svc.cluster.local
测试
# 访问测试
kubectl exec -it -c sleep $(kubectl get pod -l app=sleep,version=v2 -o jsonpath='{.items..metadata.name}') -- http -f POST http://httpbin:8000/get data=nothing
# 返回信息
HTTP/1.1 405 Method Not Allowed
access-control-allow-credentials: true
access-control-allow-origin: *
allow: GET, OPTIONS, HEAD
content-length: 178
content-type: text/html
date: Wed, 12 Jun 2019 12:39:28 GMT
server: envoy
x-envoy-upstream-service-time: 5
The method is not allowed for the requested URL.
参考地址:
https://blog.csdn.net/weixin_44144334/article/details/107788292
https://developer.aliyun.com/article/636511
https://www.cnblogs.com/huanglingfa/p/13895297.html