K8S集群部署istio

简介

Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,而不需要对服务的代码做任何改动。
istio 适用于容器或虚拟机环境(特别是 k8s),兼容异构架构。
istio 使用 sidecar(边车模式)代理服务的网络,不需要对业务代码本身做任何的改动。
HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡。
istio 通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制;支持访问控制、速率限制和配额。
istio 对出入集群入口和出口中所有流量的自动度量指标、日志记录和跟踪。

对比国内阿里云和K8S官方维护的Nginx Ingress Controller及 Istio Gateway 比较

  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]#

设置可视化界面kiali为外部访问模式并查询nodeport号

[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 

K8S集群部署istio_第1张图片

 默认登陆账户和密码为admin/admin

K8S集群部署istio_第2张图片

也可以创建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

在istio上部署测试应用bookinfo

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

K8S集群部署istio_第3张图片

 重复刷新可以发现星星发生变化说明部署成功

istio-http流量管理

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


405 Method Not Allowed

Method Not Allowed


The method is not allowed for the requested URL.


注意点:
rewrite 方法与 redirect 方法的不同之处在于: 在 rewrite 方法的 match 字段必须包含对目标的定义;
rewrite 方法与 redirect 方法不能共存。

参考地址:
https://blog.csdn.net/weixin_44144334/article/details/107788292
https://developer.aliyun.com/article/636511

https://www.cnblogs.com/huanglingfa/p/13895297.html

你可能感兴趣的:(K8S集群部署istio)