目录

istio安装以及相关概念

安装

下载

1
2
[root@kube-mas ~]# curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.8 TARGET_ARCH=x86_64 sh 
指定版本为1.6.8 架构为x86_64,如果下载速度慢,建议使用本地迅雷下载之后再传到服务器上

解压并设置环境变量

1
2
3
4
5
[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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
需要注意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类型

1
2
3
4
5
6
7
8
[root@kube-mas ~]# istioctl profile list
Istio configuration profiles:
    preview
    remote
    default
    demo
    empty
    minimal

下图为对应类型会安装的组件,但是到1.7版本之后,有很多组件都不会自动安装了

/images/posts/image-20210527164422548.png

导出某个profile的yaml模板

1
[root@kube-mas ~]# istioctl profile dump demo > demo.yaml //导出demo profile的yaml模板

安装

1
2
3
4
5
6
7
8
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

卸载

1
2
卸载程序将删除 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
 2
 3
 4
 5
 6
 7
 8
 9
10
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

1
2
3
4
[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      <none>        15021:30167/TCP,80:32099/TCP,443:32266/TCP,31400:30597/TCP,15443:31792/TCP   13m

istio的注入方式

手动注入方式

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
创建一个测试的名称空间
[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文件中也可以看到相关配置

自动注入方式

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
自动注入是很简单的,只需要在名称空间上加上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容器究竟做了什么操作?

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
[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

这个主容器,主要启动了什么进程?使用了什么端口?可以通过如下命令查看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[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的启动与监控

参考文章

思考

为什么istio-init和istio-proxy都是使用的docker.io/istio/proxyv2:1.6.8 这个镜像,为什么istio-init 状态是Terminated而istio-proxy却是Running呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[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中的配置
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[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 <scope>:<level>,<scope>:<level>,... 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 <scope>:<level>,<scope:level>,... 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为例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[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网关

/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

详细参数信息

/images/posts/image-20210528112049105.png

1
2
3
4
通过查看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示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[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"

配置解释

第一部分

1
2
  selector:
    istio: ingressgateway

将此配置下发到哪个pod,我们可以在默认的istio-ingressgateway中看到有istio=ingressgateway这个标签。所以此配置会配置到默认的ingress-gateway这个pod中

第二部分

1
2
3
4
5
6
7
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可以实现类似按百分比来分配流量等更加复杂、丰富、细粒度的流量控制。

详细参数信息

注意: 虚拟服务相当于 k8s service的sidecar,在原本k8s service的功能之上,提供了更加丰富的路由控制

VirtualService示例1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[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 (更有逻辑)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[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

参数解释

第一部分

1
2
3
  gateways:
    - bookinfo-gw # 外部使用
    - mesh        # 内部使用

当前Virtualservice绑定的ingressgateway网关,可向网格外暴露这些Host,网格内部通信存在一个默认的mesh保留字,mesh用来代指网格中的所有sidecar。

  • 当没有定义gateway的时候,就会只是用缺省值(mesh),也就是针对网格中所有的sidecar生效
  • 如果提供了gateways字段,这一规则就只会应用到声明的gateway之中。要让规则同时对gateway和网格内服务生效,需要显示的将mesh加入gateways列表中

第二部分

1
2
3
  hosts:
  - "productpage.test.svc.cluster.local" # 内部的k8s fqdn地址
  - "bookinfo.xieys.club" #外网域名

一般为fqdn地址,通常是k8s的某个service地址,也可以是ip地址,dns域名或者依赖于平台的一个简称(例如k8s的服务短名称),隐式或显示的指向一个完全限定域名(FQDN),也可以使用通配符(*)前缀,让你创建一组所有服务的路由规则

第三部分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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的关系,例如
1
2
3
4
5
   - match:
    - uri:
        exact: /productpage
      uri:
        prefix: /produ
  • 在match下添加的多个规则,关系是OR的关系,例如
1
2
3
4
5
  - match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static

对于给定的virtualService,可以配置多条路由规则,比如基于负责的条件判断,或者想基于权重百分比分发流量(A/B测试或者金丝雀部署非常有用)

具体条件判断可以使用的字段和值可以参考:官方文档

  • exact 为精准匹配

  • prefix 为基于前缀匹配

  • Regex 为正则匹配

      route:
      - destination:
          host: productpage.test.svc.cluster.local
          subset: v1
          port:
            number: 9080
    

在match关键字下的route,如果条件匹配的话,定义匹配的路由规则。

一条路由规则包含零个或者多个匹配条件的目标地址,路由规则按照从上到下的顺序选择,第一条规则具有最高优先级,如果不满足第一条路由规则均流向下一条路由规则,如果都不满足,那么就走默认的路由规则(也就是第四部分定义在http关键字下跟match同级的route)。所以通常建议定义一个默认的路由规则来确保virtualservice至少有一条匹配的路由

主要通过此定义去查找定义的DestinationRule(目标规则)资源。

第四部分

1
2
3
4
5
6
  - 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将控制流量分发到不同的服务实例中。

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
前面以及定义好了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

参数解释

1
host: productpage.test.svc.cluster.local

对应k8s service的fqdn地址

1
2
3
4
  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: 将请求转发到具有最少请求数目的实例上。

例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[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策略中使用了特定策略轮询负载均衡

详细参数信息

总结

跟nginx配置文件比较,destinationRule则相当于nginx proxy_pass 对应的后端节点(upstream块的后端节点)

资源应用

1
2
3
4
5
6
7
8
9
应用前面所定义的所有资源
[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    <none>        80/TCP,443/TCP,15443/TCP                                                     19h
istio-ingressgateway        NodePort    10.96.61.36      <none>        15021:30167/TCP,80:32099/TCP,443:32266/TCP,31400:30597/TCP,15443:31792/TCP   19h

通过域名访问

/images/posts/image-20210528125712691.png

可以到外网已经可以正常访问到了

VirtualService和DestinationRule的配置选项

/images/posts/image-20210528134730522.png

ServiceEntry服务条目

/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的主机

详细参数

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
部署官方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
已经都可以正常进行访问了

参数解析

第一部分

1
2
  hosts:
  - www.baidu.com

将外部的那个fqdn或者ip,配置成网格内的serviceEntry资源

第二部分

1
2
3
4
5
6
7
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS

外部服务fqdn或者ip,服务所对应的端口

第三部分

1
  resolution: DNS

设置对应主机的服务发现模式为DNS

第四部分

1
  location: MESH_EXTERNAL
  • MESH_EXTERNAL 表示服务在网格外部。通常用于指示通过API使用的外部服务

  • MESH_INTERNAL 表示服务是网格的一部分。通常用于指示在扩展服务网格以包括不受管理的基础架构时显式添加的服务