Istio1.6访问VM工作负载三种方式(新的WorkloadEntry)

上次说到,Istio 1.6新版本引入了Workload Entry来增强对于非K8S(虚拟机和裸机)工作负载的支持。在理论上,网格内的服务彼此之间可以通过服务名互相调用,但是对于网格外的服务,有哪些访问方式呢?本宝宝专门花了很大的功夫做了实验,今天就一起来看看。

先来看一些理论

目前,Istio对于外部服务的支持有三种:

  1. 通过istioctl register 注册一个Service和一个Endpoint;
  2. 通过ServiceEntry定义;
  3. 通过WorkloadEntry + ServiceEntry 组合定义。

第一种方式 istioctl register

在这种方式下,你需要将每个网格外服务都通过istioctl register进行注册,这个命令将自动创建并部署对应的serviceendpoint。注册进来的服务将被分配网格内部的域名,使用mTLS,并且直接受Istio管理。VM需要安装Istio各个组件(Envoy proxy、node-agent、istio-agent),并且保证可被istio控制平面访问。

第二种方式 ServiceEntry

什么是ServiceEntry?

先来看官网对ServiceEntry的定义:

ServiceEntry enables adding additional entries into Istio’s internal service registry, so that auto-discovered services in the mesh can access/route to these manually specified services.

也就是说,他是将其他非网格内服务加入Istio的服务发现,像网格内的服务一样进行管理。这里没有直接使用“外部服务”,是因为ServiceEntry适用的主体不仅仅包括网格外的服务(比如Web API),还包括一些处于网格内部但却不存在于平台的服务注册表中的服务(例如需要和 Kubernetes 服务沟通的一组虚拟机服务)。在这种方式下,该服务所处VM不需要安装Istio组件,只需要保证Istio能访问该服务即可。

ServiceEntry怎么定义外部服务?

对于外部服务,你需要按照下面的规则来配置:

  • hosts :指定外部服务对应的主机名或DNS域名。对于HTTP流量,就是HTTP Header的Host;对于HTTPS/TLS的流量,就是SNI。
  • location :指定为MESH_EXTERNAL,表示它是在网格外部,需要通过API来访问的接口。
  • ports :外部服务的端口。
  • resolution :表示服务发现的模式
    • 如果是一个明确IP,配置为NONE
    • 如果使用了endpoints,配置为STATIC
    • 如果使用了DNS域名,配置为DNS

比如,如果想将外部网页服务注册到istio中,可以这样配置:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-svc-https
spec:
  hosts:
  - api.dropboxapi.com
  - www.googleapis.com
  - api.facebook.com
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS
---
ServiceEntry怎么定义内部服务?

在定义内部服务时,ServiceEntry需要和DestinationRule配合使用,也就是说,通过ServiceEntry定义服务,通过DestionationRule初始化到istio到服务的mTLS连接。

在这种方式下,你需要将每个网格外服务的地址都显式定义在ServiceEntry的endpoints字段中,但你不需要在VM或裸机上安装Istio。

第三种方式 WorkloadEntry

什么是WorkloadEntry?

WorkloadEntry的出现就是为了将ServiceEntry中的endpoints定义与ServiceEntry本身进行分离,使ServiceEntry专注定义非网格内部服务,而WorkloadEntry定义该服务来源(VM或裸机)的信息。引用官网的介绍,

WorkloadEntry enables operators to describe the properties of a single non-Kubernetes workload such as a VM or a bare metal server as it is are onboarded into the mesh. A WorkloadEntry must be accompanied by an Istio ServiceEntry that selects the workload through the appropriate labels and provides the service definition for a MESH_INTERNAL service (hostnames, port properties, etc.).

也就是说,WorkloadEntry也是与ServiceEntry配套使用的,那么由于ServiceEntry是和DestinationRule配套使用的,因此他们三个要一起使用。

在这种方式下,你可以用WorkloadEntry定义VM,再用ServiceEntry定义非网格内服务,并且可以选择一个或多个运行在K8S和非K8S上的服务,实现了最大程度的灵活性。

实验做什么

下面,我们就分别用这三种方式尝试将虚拟机上的服务注册到istio中进行管理。实验基于Istio提供的示例应用Bookinfo,增加Ratings服务的新版本,使其调用运行在VM上的mysql作为后端。应用架构图如下:


实验架构

环境说明

为了做实验,专门用了一台阿里云和一台华为云,配置了安全组,使其相互能访问。其中,阿里云上跑Istio,华为云作为VM跑mysql服务:

  • 阿里云ECS:4核8G、CentOS 8.0、Docker(v18.06.1)、kubectl(v1.15.0)、minikube(v1.2.0阿里社区版)、istio(1.6.2)

  • 华为云云耀云:2核4G、Ubuntu 18.04、Docker(v19.03.11)、kubectl(v1.15.0)、minikube(v1.1.0阿里社区版)、mysql(v10.1.44-MariaDB)

(由于目前sidecar安装只提供了deb版本,对于CentOS需要手动make编译安装,因此VM直接选用Ubuntu。)

实验怎么做

在本宝宝看了大量文档连蒙带猜后,终于理出了头绪,因此专门分开介绍在VM和Istio两端分别需要做怎样的配置。

首先说VM端

VM起一个Mysql服务,里面放评分数据,并作为ratings服务的后端。

  1. 安装Envoy sidecar
curl -L https://storage.googleapis.com/istio-release/releases/1.6.3/deb/istio-sidecar.deb
sudo dpkg -i istio-sidecar.deb 
  1. 配置Mysql
    Mysql默认只允许本地访问,于是先要配置使其允许远程访问。详细步骤请参考《填坑指南 1.如何开启Mysql远程访问》。

  2. 将评分数据加入Mysql

curl -q https://raw.githubusercontent.com/istio/istio/release-1.6/samples/bookinfo/src/mysql/mysqldb-init.sql | mysql -u root -ppassword

示例使用名为test的数据库,可以查询并自定义评分数据。

MariaDB [(none)]> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [test]> select * from ratings;
+----------+--------+
| ReviewID | Rating |
+----------+--------+
|        1 |      3 |
|        2 |      2 |
+----------+--------+
2 rows in set (0.01 sec)

至此,VM需要配置的内容就结束了。下面来看Istio端。

再说istio端

Istio端需要将VM上的Mysql加入网格中,并配置服务调用策略,使Ratings服务调用VM上的Mysql服务查询评分数据。

  1. 启用Istio meshExpansion。
    在安装Istio的时需要开启meshExpansion功能。
    istioctl install --set profile=demo --set values.global.meshExpansion.enabled=true

2(*). 开启Kiali
Kiali是为Istio提供图形化界面Dashboard的开源项目,可以通过它监控网格内服务的实时状态,以及网格配置。为了能够监测流量流向,我们开启Kiali,详细步骤请参考《填坑指南->2. 如何开启Kaili进行流量监控?》。

  1. 部署并应用v2-mysql版本的ratings服务。
    查看了应用源码,发现在ratings服务的源码中,是从环境变量中取值初始化DB连接。
image.png
image.png

因此,在ratings服务的Deployment中,也需要将后端DB连接信息传入环境变量。
部署并应用v2-mysql版本ratings,MYSQL_DB_HOST使用服务名mysqldb,istio会自动寻找注册过的名为mysqldb的Service或ServiceEntry。

  1. 部署并应用应用新版本VirtualService。
    使用virtual-service-ratings-mysql.yaml,使流量应用v3版本的reviews服务和v2-mysql版本的ratings服务。

  2. 在Istio中注册”mysqldb“。

上文介绍到有三种方式配置非K8S服务,下面就分别试一下。

方式一:使用istioctl register

  1. 注册mysqldb服务。
    它会默认创建出来同名的Service和endpoints。
[root@node2 kube]# istioctl register mysqldb 124.**.65.221 3306
2020-06-23T06:58:15.842443Z warn    Got 'services "mysqldb" not found' looking up svc 'mysqldb' in namespace 'default', attempting to create it
2020-06-23T06:58:15.852592Z warn    Got 'endpoints "mysqldb" not found' looking up endpoints for 'mysqldb' in namespace 'default', attempting to create them
  1. 确认service和endpoint状态。
[root@node2 kube]# kubectl get svc
NAME           TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
details        ClusterIP      10.101.253.166           9080/TCP         50m
frontend       NodePort       10.102.61.100            80:30004/TCP     16d
kubernetes     ClusterIP      10.96.0.1                443/TCP          17d
mongodb        ClusterIP      10.100.95.126            27017/TCP        14d
mysqldb        ClusterIP      10.97.255.81             3306/TCP         114s
productpage    ClusterIP      10.109.248.58            9080/TCP         50m
ratings        ClusterIP      10.99.19.120             9080/TCP         50m
reviews        ClusterIP      10.100.95.201            9080/TCP         50m
[root@node2 kube]# kubectl get endpoints
NAME           ENDPOINTS                                            AGE
details        172.17.0.21:9080,172.17.0.7:9080                     48m
kubernetes     172.26.205.16:8443                                   17d
mongodb        172.17.0.24:27017                                    14d
mysqldb        124.**.65.221:3306                                   35s
productpage    172.17.0.9:9080                                      48m
ratings        172.17.0.14:9080,172.17.0.26:9080                    48m
reviews        172.17.0.10:9080,172.17.0.11:9080,172.17.0.25:9080   48m
  1. 访问bookinfo应用。
    先在华为云上将评分数据更新为五星,五星,之后调用productpage。可以看到评分已经发生变化。


    image.png

使用Kiali查看调用路径,可以看到v2-mysql版本的ratings调用了mysqldb服务。


image.png

方式二:使用ServiceEntry

  1. 定义并部署ServiceEntry
  • hosts :对于非HTTP的流量,该字段不生效,它将后面通过address或endpoint定义的服务映射为网格内部的一个虚拟服务,以hosts标识,并遵循istio内部的服务名定义格式 。
  • endpoints :表示与网格服务相关的网络地址,可以是IP或主机名,也可以用多个address组成一个vip组。

按照上述规则,在hosts里填mysqldb,在endpoints里填VM的IP。

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: mysqldb-se
spec:
  hosts:
  - mysqldb
  location: MESH_INTERNAL
  ports:
  - number: 3306
    name: mysql
    protocol: mysql
  resolution: STATIC
  endpoints:
  - address: 124.**.65.221
---
  1. 定义并部署DestinationRule
  • hosts :表示规则适用的对象,这里指定以ServiceEntry方式注册的网格外服务名称。
  • trafficPolicy :规则内容的定义,这里只规定了tls的模式,在ISTIO_MUTUAL 模式下,Istio 会依据内部实现机制自动设置密钥和证书的路径,不需要手动指定clientCertificate、 privateKey和 caCertificates的位置。

按照上述规则,在host里填mysqldb

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: mtls-mysqldb
spec:
  host: mysqldb
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
---
  1. 访问bookinfo应用。
    先在华为云上将评分数据更新为三星和五星,之后调用productpage。可以看到评分已经发生变化。


    image.png

使用Kiali查看调用路径,可以看到v2-mysql版本的ratings调用了ServiceEntry类型的mysqldb-se,同时出现了PassthroughtCluster。想了解PassthroughCluster,请参考《填坑指南->3. PassthroughCluster是什么鬼?》

image.png

方式三:使用WorkloadEntry

  1. 定义并部署WorkloadEntry
  • address : 表示与网格服务相关的网络地址,可以是IP或主机名。

按照上述规则,在adddress中配置VM的IP,并添加标签”mysqlvm“。

apiVersion: networking.istio.io/v1alpha3
kind: WorkloadEntry
metadata:
  name: mysqldb-we
spec:
  address: 124.**.65.221
  labels:
    app: mysqlvm
    instance-id: ubuntu-vm-mariadb
    class: vm
---
  1. 定义并部署ServiceEntry
  • workloadSelector :通过label来选择K8S上有这个标签的Pod,或通过WorkloadEntry定义的VM上的工作负载。也就是说,通过这种方式,就不需要关心工作负载是跑在哪里的了,只需要指定应用的标签,istio会自动选择有相应标签的工作负载。

按照上述规则,在hosts里填mysqldb,在workloadSelector通过标签”mysqlvm“定义相应的WorkloadEntry。

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: mysqldb-vm-se
spec:
  hosts:
  - mysqldb
  location: MESH_INTERNAL
  ports:
  - number: 3306
    name: mysql
    protocol: mysql
  resolution: STATIC
  workloadSelector:
    labels:
      app: mysqlvm
---
  1. 定义并部署DestinationRule
    在DestinationRule中配置使用ISTIO_MUTUAL连接mysqldb
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: mtls-mysqldb-vm
spec:
  host: mysqldb
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
---
  1. 访问bookinfo应用。
    先在华为云上将评分数据更新为一星和一星,之后调用productpage。可以看到评分已经发生变化。


    image.png

使用Kiali查看调用路径,可以看到v2-mysql版本的ratings调用了ServiceEntry类型的mysqldb-vm-se

image.png

吐槽加总结一下

这次做实验本来是为了尝试了新版本的WorkloadEntry,但是由于Istio的文档实在是太乱,网上的经验帖又太少,看了不下几十个链接,最终只能连蒙带猜,根据属性说明尝试配置,算是成功了,但总觉得Istio乱花渐欲的配置实在是太迷,还有很多不是理解不够深刻的地方。

走了很多弯路,特意总结出这三种访问外部服务的方式,附带填坑指南供大家参考。
喜欢本宝宝就请多多关注哦。

填坑指南

1. 如何开启Mysql远程访问?

1)注释掉bing-address。
Mariadb的配置文件位置和普通Mysql有所不同,bind-address在/etc/mysql/mariadb.conf.d/50-server.cnf这里。

vi /etc/mysql/mariadb.conf.d/50-server.cnf

# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
#bind-address           = 127.0.0.1

2) 使用GRANT命令增加允许远程访问的host。

GRANT ALL ON *.* to root@'39.**.145.34' IDENTIFIED BY 'password';
FLUSH PRIVILEGES;  
MariaDB [mysql]> select host, user from user;
+---------------+------+
| host          | user |
+---------------+------+
| %             | root |
| 39.**.145.34 | root |
| localhost     | root |
+---------------+------+
3 rows in set (0.00 sec)

2. 如何开启Kiali进行流量监控?

1)查看Kiali服务状态。

[root@node2 ~]# kubectl get svc -n istio-system
NAME                        TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                                                                                   AGE
...
kiali                       ClusterIP      10.103.7.219             20001/TCP                                                                                                                                 3d5h
...

2)启用port-forward,将20001端口直接暴露出来。

kubectl -n istio-system port-forward --address 0.0.0.0 $(kubectl -n istio-system get pod -l app=kiali -o jsonpath='{.items[0].metadata.name}') 20001:20001 &

3)打开浏览器,使用:20001直接访问Kiali Dashboard,默认用户名和密码都为admin。

3. PassthroughCluster是什么鬼?

参考官网说明,监控被阻止的和透传的外部服务流量。

为了更好的监控外部流量,Istio 控制平面使用了预定义集群BlackHoleClusterPassthrough来配置 sidecar 代理,它们的作用分别是阻止和通过所有流量。当将global.outboundTrafficPolicy.mode设置为 ALLOW_ANY时, PassthroughCluster 是在 Envoy 配置中创建的虚拟集群。在此模式下,允许流向外部服务的所有流量。

为了实现此目的,将使用 SO_ORIGINAL_DST 且监听 0.0.0.0:15001 的默认虚拟出站监听器设置为 TCP 代理,并将 PassthroughCluster 作为静态集群。 对于每个基于端口/协议的监听器,虚拟路由配置都会添加 PassthroughCluster 以作为默认路由,发向PassthroughCluster的请求会被直接发送到其请求中要求的原始目地的,Envoy不会对请求进行重新路由。

你可能感兴趣的:(Istio1.6访问VM工作负载三种方式(新的WorkloadEntry))