# istio安装以及相关概念 ## 安装 > 下载 ``` [root@kube-mas ~]# curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.8 TARGET_ARCH=x86_64 sh 指定版本为1.6.8 架构为x86_64,如果下载速度慢,建议使用本地迅雷下载之后再传到服务器上 ``` > 解压并设置环境变量 ``` [root@kube-mas ~]# tar -xf istio-1.6.8-linux-amd64.tar.gz [root@kube-mas ~]# vim /etc/profile ... export PATH=/root/istio-1.6.8/bin:$PATH [root@kube-mas ~]# source /etc/profile ``` > 安装部署 ``` 需要注意1.6之前的版本和1.6之后的版本安装会有细微区别,具体看帮助 [root@kube-mas ~]# istioctl install --set profile=demo -y [root@kube-mas ~]# kubectl get po -n istio-system NAME READY STATUS RESTARTS AGE grafana-b54bb57b9-jvfsf 1/1 Running 0 7m20s istio-egressgateway-7447bd847b-8qz29 1/1 Running 0 7m21s istio-ingressgateway-59c788fd4f-ktgpf 1/1 Running 0 7m21s istio-tracing-9dd6c4f7c-jp89b 1/1 Running 0 7m20s istiod-54d84dc79c-hppjw 1/1 Running 0 8m34s kiali-d45468dc4-d4v9l 1/1 Running 0 7m20s prometheus-79fb649b4d-68x98 2/2 Running 0 7m20s ``` ### 常用命令 > 查看所有profile类型 ``` [root@kube-mas ~]# istioctl profile list Istio configuration profiles: preview remote default demo empty minimal ``` 下图为对应类型会安装的组件,但是到1.7版本之后,有很多组件都不会自动安装了 ![image-20210527164422548](/images/posts/image-20210527164422548.png) > 导出某个profile的yaml模板 ``` [root@kube-mas ~]# istioctl profile dump demo > demo.yaml //导出demo profile的yaml模板 ``` > 安装 ``` 1.7 版本之前 istioctl manifest apply --set profile=demo 例如,当前我不想安装kiali、prometheus、jaeger,可以用如下方法安装 [root@kube-mas ~]# istioctl manifest apply --set profile=demo -y --set values.kiali.enabled=false --set values.prometheus.enabled=false --set values.tracing.enabled=false 1.7 版本之后 istioctl manifest install --set profile=demo ``` > 卸载 ``` 卸载程序将删除 RBAC 权限、istio-system 命名空间和所有相关资源。可以忽略那些不存在的资源的报错,因为它们可能已经被删除掉了 [root@kube-mas ~]# istioctl manifest generate --set profile=demo | kubectl delete -f - ``` ### 安装组件 **注意到1.7版本后有很多组件不会自动安装了,比如demo 只会安装egressgateway、ingressgateway、istiod** > 安装kiali、prometheus、jaeger ``` 1.7版本之前安装 [root@kube-mas ~]# istioctl manifest apply --set profile=demo -y --set values.kiali.enabled=true --set values.prometheus.enabled=true --set values.tracing.enabled=true 1.7版本之后安装 [root@kube-mas ~]# istioctl manifest install --set profile=demo --set values.kiali.enabled=true --set values.prometheus.enabled=true --set values.tracing.enabled=true 部署jaeger [root@kube-mas ~]# kubectl apply -f istio-1.6.8/samples/addons/jaeger.yaml [root@kube-mas ~]# kubectl patch svc -n istio-system jaeger-query -p '{"spec":{"type":"NodePort"}}' ``` ### 将ingressgateway网关类型改为nodeport ``` [root@kube-mas ~]# kubectl patch svc istio-ingressgateway -n istio-system -p '{"spec":{"type":"NodePort"}}' service/istio-ingressgateway patched [root@kube-mas ~]# kubectl get svc -n istio-system | grep ingress istio-ingressgateway NodePort 10.96.61.36 15021:30167/TCP,80:32099/TCP,443:32266/TCP,31400:30597/TCP,15443:31792/TCP 13m ``` ## istio的注入方式 ### 手动注入方式 > 示例 ``` 创建一个测试的名称空间 [root@kube-mas ~]# kubectl create ns test 创建一个简单的nginx deploy资源 [root@kube-mas ~]# mkdir test [root@kube-mas ~]# cd test/ [root@kube-mas test]# cat nginx-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-dep labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.19.1 imagePullPolicy: IfNotPresent [root@kube-mas test]# kubectl apply -f nginx-deploy.yaml -n test istio注入之前pod的资源状态 [root@kube-mas test]# kubectl get po -n test NAME READY STATUS RESTARTS AGE nginx-dep-7c68497bd9-ktrqt 1/1 Running 0 15s 使用kube-inject手动注入,先导出配置文件 导出方法1: [root@kube-mas test]# istioctl kube-inject -f nginx-deploy.yaml -o nginx-deploy-inject.yaml 导出方法2: [root@kube-mas test]# istioctl kube-inject -f nginx-deploy.yaml > nginx-deploy-inject.yaml 直接注入 [root@kube-mas test]# istioctl kube-inject -f nginx-deploy.yaml | kubectl apply -n test -f - istio注入后的pod的资源状态 [root@kube-mas test]# kubectl get po -n test NAME READY STATUS RESTARTS AGE nginx-dep-6966cf86fd-7mqbb 2/2 Running 0 46s 可以看到pod被注入了一个新的容器,这个再导出来的yaml文件中也可以看到相关配置 ``` ### 自动注入方式 > 示例 ``` 自动注入是很简单的,只需要在名称空间上加上label标签 istio-injection=enabled即可 [root@kube-mas test]# kubectl label ns test istio-injection=enabled 验证,把之前手动注入的deploy资源删除,然后直接应用没有被注入过的deploy的yaml文件 [root@kube-mas test]# kubectl delete -f . -n test deployment.apps "nginx-dep" deleted [root@kube-mas test]# kubectl apply -f nginx-deploy.yaml -n test [root@kube-mas test]# kubectl get po -n test NAME READY STATUS RESTARTS AGE nginx-dep-7c68497bd9-vbfl6 2/2 Running 0 42s 可以看到这里自动注入了istio的边车pod ``` ### 注入原理以及细节 **注意,应用注入,实际上并不是从原来的pod插入,而是重新启动了一个新的pod,然后再杀掉老的pod** 在手动注入的时候导出来的nginx-deploy-inject.yaml这个配置文件中,我们可以看到,注入之后,多出来了2个容器,一个初始化容器,一个主容器 > 初始化容器 name: istio-init image: docker.io/istio/proxyv2:1.6.8 可以通过查看日志来看initcontainer容器究竟做了什么操作? ``` [root@kube-mas test]# kubectl get po -n test NAME READY STATUS RESTARTS AGE nginx-dep-7c68497bd9-vbfl6 2/2 Running 0 16h [root@kube-mas test]# kubectl logs nginx-dep-7c68497bd9-vbfl6 -n test -c istio-init Environment: ------------ ENVOY_PORT= INBOUND_CAPTURE_PORT= ISTIO_INBOUND_INTERCEPTION_MODE= ISTIO_INBOUND_TPROXY_MARK= ISTIO_INBOUND_TPROXY_ROUTE_TABLE= ISTIO_INBOUND_PORTS= ISTIO_LOCAL_EXCLUDE_PORTS= ISTIO_SERVICE_CIDR= ISTIO_SERVICE_EXCLUDE_CIDR= Variables: ---------- PROXY_PORT=15001 PROXY_INBOUND_CAPTURE_PORT=15006 PROXY_UID=1337 PROXY_GID=1337 INBOUND_INTERCEPTION_MODE=REDIRECT INBOUND_TPROXY_MARK=1337 INBOUND_TPROXY_ROUTE_TABLE=133 INBOUND_PORTS_INCLUDE=* INBOUND_PORTS_EXCLUDE=15090,15021,15020 OUTBOUND_IP_RANGES_INCLUDE=* OUTBOUND_IP_RANGES_EXCLUDE= OUTBOUND_PORTS_EXCLUDE= KUBEVIRT_INTERFACES= ENABLE_INBOUND_IPV6=false Writing following contents to rules file: /tmp/iptables-rules-1622107917045002406.txt217260741 * nat -N ISTIO_REDIRECT -N ISTIO_IN_REDIRECT -N ISTIO_INBOUND -N ISTIO_OUTPUT -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001 -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006 -A PREROUTING -p tcp -j ISTIO_INBOUND -A ISTIO_INBOUND -p tcp --dport 22 -j RETURN -A ISTIO_INBOUND -p tcp --dport 15090 -j RETURN -A ISTIO_INBOUND -p tcp --dport 15021 -j RETURN -A ISTIO_INBOUND -p tcp --dport 15020 -j RETURN -A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT -A OUTPUT -p tcp -j ISTIO_OUTPUT -A ISTIO_OUTPUT -o lo -s 127.0.0.6/32 -j RETURN -A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT -A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT -A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN -A ISTIO_OUTPUT -j ISTIO_REDIRECT COMMIT iptables-restore --noflush /tmp/iptables-rules-1622107917045002406.txt217260741 Writing following contents to rules file: /tmp/ip6tables-rules-1622107917154183931.txt536994656 ip6tables-restore --noflush /tmp/ip6tables-rules-1622107917154183931.txt536994656 iptables-save # Generated by iptables-save v1.6.1 on Thu May 27 09:31:57 2021 *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT # Completed on Thu May 27 09:31:57 2021 # Generated by iptables-save v1.6.1 on Thu May 27 09:31:57 2021 *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :ISTIO_INBOUND - [0:0] :ISTIO_IN_REDIRECT - [0:0] :ISTIO_OUTPUT - [0:0] :ISTIO_REDIRECT - [0:0] -A PREROUTING -p tcp -j ISTIO_INBOUND -A OUTPUT -p tcp -j ISTIO_OUTPUT -A ISTIO_INBOUND -p tcp -m tcp --dport 22 -j RETURN -A ISTIO_INBOUND -p tcp -m tcp --dport 15090 -j RETURN -A ISTIO_INBOUND -p tcp -m tcp --dport 15021 -j RETURN -A ISTIO_INBOUND -p tcp -m tcp --dport 15020 -j RETURN -A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006 -A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN -A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT -A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT -A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN -A ISTIO_OUTPUT -j ISTIO_REDIRECT -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001 COMMIT # Completed on Thu May 27 09:31:57 2021 # Generated by iptables-save v1.6.1 on Thu May 27 09:31:57 2021 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Thu May 27 09:31:57 2021 ``` **从上面输出的日志,我们可以看到初始化容器实际上是做了一系列的iptables转发规则以及环境变量的初始化** > 主容器 name: istio-proxy image: docker.io/istio/proxyv2:1.6.8 这个主容器,主要启动了什么进程?使用了什么端口?可以通过如下命令查看 ``` [root@kube-mas test]# kubectl exec nginx-dep-7c68497bd9-vbfl6 -it -n test -c istio-proxy -- ps -ef UID PID PPID C STIME TTY TIME CMD istio-p+ 1 0 0 01:33 ? 00:00:03 /usr/local/bin/pilot-agent proxy sidecar --domain test.svc.cluster.local --serviceCluster nginx.test --proxyLogLevel=warning --proxyComponentLogLevel=misc:error --trust-domain=cluster.local --concurrency 2 istio-p+ 13 1 0 01:33 ? 00:00:06 /usr/local/bin/envoy -c etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time-s 60 --service-cluster nginx.test --service-node sidecar~10.244.1.69~nginx-dep-7c68497bd9-vbfl6.test~test istio-p+ 25 0 0 01:55 pts/0 00:00:00 ps -ef [root@kube-mas test]# kubectl exec nginx-dep-7c68497bd9-vbfl6 -it -n test -c istio-proxy -- ss -nltp State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 0.0.0.0:15021 0.0.0.0:* users:(("envoy",pid=13,fd=25)) LISTEN 0 128 0.0.0.0:80 0.0.0.0:* LISTEN 0 128 0.0.0.0:15090 0.0.0.0:* users:(("envoy",pid=13,fd=24)) LISTEN 0 128 127.0.0.1:15000 0.0.0.0:* users:(("envoy",pid=13,fd=14)) LISTEN 0 128 0.0.0.0:15001 0.0.0.0:* users:(("envoy",pid=13,fd=57)) LISTEN 0 128 0.0.0.0:15006 0.0.0.0:* users:(("envoy",pid=13,fd=58)) LISTEN 0 128 *:15020 *:* users:(("pilot-agent",pid=1,fd=7)) LISTEN 0 128 [::]:80 [::]:* ``` - **通过上面我们可以看出,istio-proxy容器,主要启动了2个进程,一个是pilot-agent,另一个是envoy,而且从进程的ppid可以得出envoy进程是由pilot-agent启动的** - **Pilot-agent进程会随时watch envoy进程,envoy进程死掉了,pilot-agent会重新启动envoy** 主要负责工作: - 生成envoy配置 - envoy的启动与监控 [参考文章](https://www.servicemesher.com/istio-handbook/concepts/pilot.html) #### 思考 > 为什么istio-init和istio-proxy都是使用的docker.io/istio/proxyv2:1.6.8 这个镜像,为什么istio-init 状态是Terminated而istio-proxy却是Running呢? ``` [root@kube-node ~]# docker inspect docker.io/istio/proxyv2:1.6.8 [ ... "Cmd": [ "/bin/sh", "-c", "#(nop) ", "ENTRYPOINT [\"/usr/local/bin/pilot-agent\"]" ], ... ] ``` 可以看到istio-proxy执行的是/usr/local/bin/pilot-agent,但是istio-init却没有执行这个,这是为什么呢? > 这里会涉及到一个作用于的问题,会有以下几种情况 - 如果k8s配置文件中的command和args没有配置,那么用docker的默认配置 - 如果command写了,args没有写,那么docker默认配置会被忽略而仅仅执行.yaml文件中的command(不带任何参数) - 如果command没有写,但是args写了,那么docker默认配置的entrypoint的命令会被执行,但是调用的参数是.yaml文件中配置的args - 如果command和args都写了,那么默认配置会被忽略,使用.yaml中的配置 ``` [root@kube-mas test]# kubectl exec nginx-dep-7c68497bd9-vbfl6 -it -n test -c istio-proxy -- bash istio-proxy@nginx-dep-7c68497bd9-vbfl6:/$ pilot-agent --help Istio Pilot agent runs in the sidecar or gateway container and bootstraps Envoy. Usage: pilot-agent [command] Available Commands: help Help about any command istio-clean-iptables Clean up iptables rules for Istio Sidecar istio-iptables Set up iptables rules for Istio Sidecar proxy Envoy proxy agent request Makes an HTTP request to the Envoy admin API version Prints out build version information Flags: -h, --help help for pilot-agent --log_as_json Whether to format output as JSON or in plain console-friendly format --log_caller string Comma-separated list of scopes for which to include caller information, scopes can be any of [all, authorization, cache, citadelclient, configmapcontroller, default, googleca, model, sds, secretfetcher, stsclient, stsserver, token, validation, vault] --log_output_level string Comma-separated minimum per-scope logging level of messages to output, in the form of :,:,... where scope can be one of [all, authorization, cache, citadelclient, configmapcontroller, default, googleca, model, sds, secretfetcher, stsclient, stsserver, token, validation, vault] and level can be one of [debug, info, warn, error, fatal, none] (default "default:info") --log_rotate string The path for the optional rotating log file --log_rotate_max_age int The maximum age in days of a log file beyond which the file is rotated (0 indicates no limit) (default 30) --log_rotate_max_backups int The maximum number of log file backups to keep before older files are deleted (0 indicates no limit) (default 1000) --log_rotate_max_size int The maximum size in megabytes of a log file beyond which the file is rotated (default 104857600) --log_stacktrace_level string Comma-separated minimum per-scope logging level at which stack traces are captured, in the form of :,,... where scope can be one of [all, authorization, cache, citadelclient, configmapcontroller, default, googleca, model, sds, secretfetcher, stsclient, stsserver, token, validation, vault] and level can be one of [debug, info, warn, error, fatal, none] (default "default:none") --log_target stringArray The set of paths where to output the log. This can be any path as well as the special values stdout and stderr (default [stdout]) Use "pilot-agent [command] --help" for more information about a command. ``` 从上面可以发现pilot-agent 不同args会有不同的作用,所以这里istio-init、istio-proxy对应的作用域中的第三种情况,通过args来使得他们的行为不一样。(在1.5版本以及之前,istio-init 对应的是第二种情况,通过command来改变docker运行的指令) ## 相关概念 ### 环境准备 以官方示例bookinfo为例子 ``` [root@kube-mas test]# cd /root/istio-1.6.8/samples/bookinfo/platform/kube/ [root@kube-mas kube]# kubectl apply -f . -n test [root@kube-mas kube]# kubectl get po -n test NAME READY STATUS RESTARTS AGE details-v1-558b8b4b76-chjvb 2/2 Running 0 8m28s details-v2-85d44f95c9-5bdqh 2/2 Running 0 8m30s mongodb-v1-78d87ffc48-7pgd9 2/2 Running 0 8m30s mysqldb-v1-6898548c56-rlq5x 2/2 Running 0 8m29s productpage-v1-6987489c74-lfrw2 2/2 Running 0 8m28s ratings-v1-7dc98c7588-5dfkw 2/2 Running 0 8m28s ratings-v2-86f6d54875-gl9zf 2/2 Running 0 8m28s ratings-v2-mysql-6b684bf9cd-phth6 2/2 Running 0 8m29s ratings-v2-mysql-vm-7748d7687d-xhg2r 2/2 Running 0 8m29s reviews-v1-7f99cc4496-9dggd 2/2 Running 0 8m28s reviews-v2-7d79d5bd5d-qk87n 2/2 Running 0 8m28s reviews-v3-7dbcdcbc56-kltv4 2/2 Running 0 8m28s ``` ### Gateway网关 ![image-20210528111341495](/images/posts/image-20210528111341495.png) Gateway用于管理进出网格的流量,指定可以进入或离开网格的流量。Gateway配置应用于网格边缘的独立的Envoy代理上,而不是服务负载的Envoy代理上。 Istio的Gateway资源仅允许配置4-6层的负载属性,如暴露的端口,TLS配置等,但是结合Istio的VirtualService,就可以像管理Istio网格中的其他数据面流量一样管理Gateway的流量。 主要用于管理ingress流量,但是也可以配置egress gateway。通过egress gateway可以配置流量离开网格的特定节点,限制哪些服务可以访问外部网络,或者通过egress安全控制来提高网格的安全性。Gateway可以用于配置一个纯粹的内部代理。 总而言之,**就是服务的进出口,要将服务暴露到外部,就得定义ingress-gateway** [详细参数信息](https://preliminary.istio.io/latest/zh/docs/reference/config/networking/gateway/) ![image-20210528112049105](/images/posts/image-20210528112049105.png) ``` 通过查看pod可以看到ingress和egress都是一个普通的pod,该pod仅包含一个istio-proxy容器 [root@kube-mas kube]# kubectl get po -n istio-system | grep gateway istio-egressgateway-7447bd847b-5gmsh 1/1 Running 0 21m istio-ingressgateway-59c788fd4f-7qd2n 1/1 Running 0 21m ``` > ingressGateway示例 ``` [root@kube-mas ~]# mkdir test/gw [root@kube-mas ~]# cd test/gw [root@kube-mas gw]# cat ingress-gw.yaml apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: bookinfo-gw namespace: test spec: selector: istio: ingressgateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "bookinfo.xieys.club" ``` #### 配置解释 > 第一部分 ``` selector: istio: ingressgateway ``` 将此配置下发到哪个pod,我们可以在默认的istio-ingressgateway中看到有`istio=ingressgateway`这个标签。所以此配置会配置到默认的ingress-gateway这个pod中 > 第二部分 ``` servers: - port: number: 80 name: http protocol: HTTP hosts: - "bookinfo.xieys.club" ``` port部分配置表示在网关上开启了80端口对应的是HTTP协议,注意这里是列表,可以开多个端口,根据自己要求而定 hosts部分,是指定对应的fqdn地址(网关域名),这里也是列表,可以绑定多个地址。如果没有具体的域名,这里也可以直接使用IP代替。 **不同服务可以单独配置自己的网关,然后跟virtualService**进行绑定即可 ### VirtualService 虚拟服务 VirtualService虚拟服务,可以将流量路由到istio服务网格中的服务,每个虚拟服务由一组路由规则组成,这些路由规则按顺序进行评估。 相比kubernetes service来说,使用virtualservice可以实现类似按百分比来分配流量等更加复杂、丰富、细粒度的流量控制。 [详细参数信息](https://preliminary.istio.io/latest/zh/docs/reference/config/networking/virtual-service/) **注意: 虚拟服务相当于 k8s service的sidecar,在原本k8s service的功能之上,提供了更加丰富的路由控制** > VirtualService示例1 ``` [root@kube-mas gw]# mkdir /root/test/vs [root@kube-mas gw]# cd !$ [root@kube-mas vs]# cat productpage-vs.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: productpage-vs namespace: test spec: gateways: - bookinfo-gw - mesh hosts: - "productpage.test.svc.cluster.local" http: - match: - uri: exact: /productpage - uri: prefix: /static - uri: exact: /login - uri: prefix: /api/v1/products route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 ``` > VirtualService示例2 (更有逻辑) ``` [root@kube-mas vs]# cat productpage-vs.yaml apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: productpage-vs namespace: test spec: gateways: - bookinfo-gw # 外部使用 - mesh # 内部使用 hosts: - "productpage.test.svc.cluster.local" # 内部的k8s fqdn地址 - "bookinfo.xieys.club" #外网域名 http: - match: - uri: exact: /productpage - uri: prefix: /static - uri: exact: /login - uri: prefix: /api/v1/products - gateways: - bookinfo-gw route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 - match: - gateways: - mesh #应用到网格中的所有服务 route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 - route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 ``` 这个示例区分了应用到内部的virtualservice以及应用到网关的virtualservice #### 参数解释 > 第一部分 ``` gateways: - bookinfo-gw # 外部使用 - mesh # 内部使用 ``` 当前Virtualservice绑定的ingressgateway网关,可向网格外暴露这些Host,网格内部通信存在一个默认的mesh保留字,mesh用来代指网格中的所有sidecar。 - 当没有定义gateway的时候,就会只是用缺省值(mesh),也就是针对网格中所有的sidecar生效 - 如果提供了gateways字段,这一规则就只会应用到声明的gateway之中。要让规则同时对gateway和网格内服务生效,需要显示的将mesh加入gateways列表中 > 第二部分 ``` hosts: - "productpage.test.svc.cluster.local" # 内部的k8s fqdn地址 - "bookinfo.xieys.club" #外网域名 ``` 一般为fqdn地址,通常是k8s的某个service地址,也可以是ip地址,dns域名或者依赖于平台的一个简称(例如k8s的服务短名称),隐式或显示的指向一个完全限定域名(FQDN),也可以使用通配符(*)前缀,让你创建一组所有服务的路由规则 > 第三部分 ``` http: - match: - uri: exact: /productpage - uri: prefix: /static - uri: exact: /login - uri: prefix: /api/v1/products - gateways: - bookinfo-gw route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 - match: - gateways: - mesh #应用到网格中的所有服务 route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 ``` http字段包含了Virtualservice的路由规则,描述匹配条件和根据所指定的host字段通过HTTP/1.1、HTTP2以及GRPC路由目标地址(也可以使用tcp和tls字段为TCP和TLS流量设置路由规则) - 匹配条件,在同一个match块某个规则,添加多个匹配条件,关系是AND的关系,例如 ``` - match: - uri: exact: /productpage uri: prefix: /produ ``` - 在match下添加的多个规则,关系是OR的关系,例如 ``` - match: - uri: exact: /productpage - uri: prefix: /static ``` 对于给定的virtualService,可以配置多条路由规则,比如基于负责的条件判断,或者想基于权重百分比分发流量(A/B测试或者金丝雀部署非常有用) 具体条件判断可以使用的字段和值可以参考:[官方文档](https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPMatchRequest ) - exact 为精准匹配 - prefix 为基于前缀匹配 - Regex 为正则匹配 route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 在match关键字下的route,如果条件匹配的话,定义匹配的路由规则。 一条路由规则包含零个或者多个匹配条件的目标地址,路由规则按照从上到下的顺序选择,第一条规则具有最高优先级,如果不满足第一条路由规则均流向下一条路由规则,如果都不满足,那么就走默认的路由规则(也就是第四部分定义在http关键字下跟match同级的route)。所以通常建议**定义一个默认的路由规则来确保virtualservice至少有一条匹配的路由**。 主要通过此定义去查找定义的DestinationRule(目标规则)资源。 >第四部分 ``` - route: - destination: host: productpage.test.svc.cluster.local subset: v1 port: number: 9080 ``` 为默认路由规则 #### 总结 **如果把virtualservice和nginx配置文件类比的话,Virtualservice就相当于nginx的location块** ### DestinationRule 目标规则 一个Virtualservice可以看作是如何将流量分发到给定的目标地址(相当于路由规则),然后调用DestinationRule来配置分发到该目标地址的流量(相当于后端真实的pod)。 需要注意的是,**DestinationRule是在VirtualService的路由规则之后才起作用** 由 VirtualService的match -> route -> destination里的host以及subset(对应到DestinationRule的host以及匹配到定义好的subsets列表中的一条配置)之后才起作用。通过它进行把流量分发到真实的service上。 可以使用DestinationRule来指定subsets服务子集,例如,根据版本对服务的实例进行分组,然后通过virtualservice的路由规则中的subset将控制流量分发到不同的服务实例中。 > 示例 ``` 前面以及定义好了Gateway以及VirtualService,但是现在还无法访问,因为还没有定义相应的目标规则 [root@kube-mas vs]# mkdir /root/test/dr [root@kube-mas vs]# cd !$ [root@kube-mas dr]# cat productpage-dr.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: productpage-dr namespace: test spec: host: productpage.test.svc.cluster.local subsets: - name: v1 labels: version: v1 ``` #### 参数解释 ``` host: productpage.test.svc.cluster.local ``` 对应k8s service的fqdn地址 ``` subsets: - name: v1 labels: version: v1 ``` 定义相应子集,这里相当于通过subset的名字为v1,可以匹配到productpage.test.svc.cluster.local这个服务打了标签为version: v1的pod DestinationRule允许在调用完整的目标服务或特定的服务子集(如倾向使用的负载均衡模型,TLS安全模型或断路器)时自定义Envoy流量策略。 iatio默认会使用轮训策略,此外istio也支持如下负载均衡模型,可以在DestinationRule中使用这些模型,将请求分发到特定的服务或服务子集。 - Random: 将请求转发到一个随机的实例上 - Weighted: 按照指定的百分比将请求转发到实例上 - Least requests: 将请求转发到具有最少请求数目的实例上。 > 例子 ``` [root@kube-mas dr]# cat my-test.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: my-test-dr namespace: test spec: host: my-test trafficPolicy: # 默认的负载均衡策略模型为随机 loadBalancer: simple: RANDOM subsets: - name: v1 # subset1,将流量转发到具有标签version: v1 的ood上 labels: version: v1 - name: v2 # subset2,将流量转发到具有标签version: v2的pod上,同时指定负载均衡为轮询 labels: version: v2 trafficPolicy: loadBalancer: simple: ROUND_ROBIN - name: v3 #subset3,将流量转发到具有标签version: v3的pod上 labels: version: v3 ``` 每一个子集由一个或多个labels定义,对应kubernetes中的对象(如pod)的labels(key/value对)。 除了定义子集外,DestinationRule还定义了该目的地中所有子集的默认流量策略,以及仅覆盖该子集的特定策略。默认策略定义在subset字段的统计字段trafficPolicy内,为v1和v3子集设置了随机负载均衡的默认策略,在v2策略中使用了特定策略轮询负载均衡 [详细参数信息](https://preliminary.istio.io/latest/zh/docs/reference/config/networking/destination-rule/#TLSSettings) #### 总结 跟nginx配置文件比较,destinationRule则相当于nginx proxy_pass 对应的后端节点(upstream块的后端节点) > 资源应用 ``` 应用前面所定义的所有资源 [root@kube-mas dr]# kubectl apply -f /root/test/gw/ingress-gw.yaml [root@kube-mas dr]# kubectl apply -f /root/test/vs/productpage-vs.yaml [root@kube-mas dr]# kubectl apply -f productpage-dr.yaml 查看ingressgateway对应80端口对应的nodeport端口 [root@kube-mas dr]# kubectl get svc -n istio-system | grep gateway istio-egressgateway ClusterIP 10.96.138.204 80/TCP,443/TCP,15443/TCP 19h istio-ingressgateway NodePort 10.96.61.36 15021:30167/TCP,80:32099/TCP,443:32266/TCP,31400:30597/TCP,15443:31792/TCP 19h ``` 通过域名访问 ![image-20210528125712691](/images/posts/image-20210528125712691.png) 可以到外网已经可以正常访问到了 ### VirtualService和DestinationRule的配置选项 ![image-20210528134730522](/images/posts/image-20210528134730522.png) ### ServiceEntry服务条目 ![image-20210528134823962](/images/posts/image-20210528134823962.png) > istio提供了三种访问外部服务的方法 - 允许sidecar将请求传递到未在网格内配置过的任何外部服务。使用这种方法时,无法监控到外部服务的访问,也不能利用istio的流量控制功能 - 配置ServiceEntry以提供对外部服务的受控访问。这是istio官方推荐使用的方法 - 对特定范围的IP,完全绕过sidecar。仅当处于性能或其他原因无法使用sidecar配置外部访问时,才建议使用该配置方法 使用ServiceEntry完成对网格外部服务的受控访问。使用服务条目资源可以将条目添加到istio内部维护的服务注册表中。添加服务条目后,Envoy代理可以将流量发送到该服务,就好像该服务条目是网格中的服务一样。通过配置服务条目,可以管理在网格外部运行的服务的流量。 同时,还可以配置VirtualService和DestinationRule,以更精细的方式来控制服务条目的流量,就像为网格中的其他任务服务配置流量一样。 对于sidecar对外部服务的处理方式,istio提供了两种选项: - ALLOW_ANY:默认值,表示istio代理允许调用未知的外部服务。上面的第一种方式就是使用了该配置项。(默认) - REGISTRY_ONLY:istio代理会阻止任何没有在网格中定义的HTTP服务或ServiceEntry的主机 [详细参数](https://preliminary.istio.io/latest/zh/docs/reference/config/networking/service-entry/) > 示例 ``` 部署官方sleep这个示例应用,用作发送请求的测试源 [root@kube-mas dr]# kubectl apply -f /root/istio-1.6.8/samples/sleep/sleep.yaml -n test 使用默认策略的时候,是允许Envoy代理将请求传递到未在网格内配置过的服务 [root@kube-mas dr]# export SOURCE_POD=$(kubectl get po -n test -l app=sleep -o jsonpath={.items..metadata.name}) [root@kube-mas dr]# kubectl exec -it $SOURCE_POD -n test -c sleep -- curl -I https://www.baidu.com | grep "HTTP/" HTTP/1.1 200 OK 修改默认策略为REGISTRY_ONLY [root@kube-mas dr]# kubectl edit cm istio -n istio-system -o yaml ... data: mesh: |- outboundTrafficPolicy: mode: REGISTRY_ONLY ... 在mesh 添加 字段outboundTrafficPolicy并设置mode为REGISTRY_ONLY 再次进行验证,访问https返回 [root@kube-mas dr]# kubectl exec -it $SOURCE_POD -n test -c sleep -- curl -I https://www.baidu.com | grep "HTTP/" command terminated with exit code 35 访问http返回 [root@kube-mas dr]# kubectl exec -it $SOURCE_POD -n test -c sleep -- curl -I http://www.baidu.com | grep "HTTP/" HTTP/1.1 502 Bad Gateway 可以发现修改默认策略后,没有在网格内配置过的服务已经被阻止了 配置一个ServiceEntry服务条目 [root@kube-mas dr]# mkdir /root/test/se [root@kube-mas dr]# cd !$ [root@kube-mas se]# cat baidu-se.yaml apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: baidu-se namespace: test spec: hosts: - www.baidu.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: https protocol: HTTPS resolution: DNS location: MESH_EXTERNAL [root@kube-mas se]# kubectl apply -f baidu-se.yaml 再次验证,访问https [root@kube-mas se]# kubectl exec -it $SOURCE_POD -n test -c sleep -- curl -I https://www.baidu.com | grep "HTTP/" HTTP/1.1 200 OK 访问http [root@kube-mas se]# kubectl exec -it $SOURCE_POD -n test -c sleep -- curl -I http://www.baidu.com | grep "HTTP/" HTTP/1.1 200 OK 已经都可以正常进行访问了 ``` #### 参数解析 > 第一部分 ``` hosts: - www.baidu.com ``` 将外部的那个fqdn或者ip,配置成网格内的serviceEntry资源 > 第二部分 ``` ports: - number: 80 name: http protocol: HTTP - number: 443 name: https protocol: HTTPS ``` 外部服务fqdn或者ip,服务所对应的端口 > 第三部分 ``` resolution: DNS ``` 设置对应主机的服务发现模式为DNS > 第四部分 ``` location: MESH_EXTERNAL ``` - MESH_EXTERNAL 表示服务在网格外部。通常用于指示通过API使用的外部服务 - MESH_INTERNAL 表示服务是网格的一部分。通常用于指示在扩展服务网格以包括不受管理的基础架构时显式添加的服务