Kubernetes服务发现总结

Kubernetes服务发现主要可以归为三种情形:1.Kubernetes集群内部间服务如何互相通信;2.Kuberntes集群外部如何访问集群内部服务;3.Kubernetes集群内部如何访问集群外部服务。这节针对这三种情况做个总结。

集群间服务通信

1.通过Pod IP相互通信,但是Pod具有不确定性,Pod IP会发生改变,所以这种方式并不推荐。

2.部署Pod对应的Service,访问Service IP,请求负载均衡转发服务到各个对应的Pod实例。

比如有如下配置文件demo.yml:

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
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-d
spec:
selector:
matchLabels:
name: web-app
replicas: 3
template:
metadata:
labels:
name: web-app
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-s
spec:
ports:
- port: 8080
targetPort: 80
protocol: TCP
selector:
name: web-app

运行该配置,查看Service对应的IP:

QQ截图20191203143956.png

通过Service IP和端口就能访问对应的Pod服务:

QQ截图20191203144119.png

但是我们事先并不知道Service的IP是多少,如果我们在启动服务后再去配置这个IP的话,这个过程也是非常麻烦的,所幸我们可以通过DNS解决这个问题,也就是下面这种方式:

3.部署Pod对应的Service,通过ServiceName,请求负载均衡转发服务到各个对应的Pod实例。

通过下面这段配置部署一个新的Pod服务:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Pod
metadata:
name: centos-pod
spec:
containers:
- name: centos
image: centos
command:
- sh
- -c
- 'while true; do sleep 360000000; done'

进入到该容器内部,测试下是否可以访问上面创建的Service:

QQ截图20191203145657.png

试着通过ServiceName访问Nginx服务:

QQ截图20191203145744.png

可以看到效果是一样的。这得益于Kube-dns,具体的格式为:<service_name>.<namespace>.svc.<cluster_domain>其中,<cluster_domain>默认值为cluster.local,可以通过kubelet的--cluster-domain=SomeDomain参数进行设置。为了在Pod中调用其他Service,kubelet会自动在容器中创建域名解析配置:

QQ截图20191203150831.png

所以除了使用curl nginx-s:8080访问外,以下这些也是等效的:

1
2
3
4
5
curl nginx-s.default:8080

curl nginx-s.default.svc:8080

curl nginx-s.default.svc.cluster.local:8080

所以我们现在可以不用事先知道Service的IP了,只要事先知道ServiceName即可(ServiceName是我们自己定义的)。

4.通过Headless Service,返回Pod的所有实例。

有时候我们并不需要Service的负载均衡功能,而是手动获取Service对应的Pod实例,自己决定如何访问。创建一个Headless Service配置:

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Service
metadata:
name: nginx-headless-s
spec:
ports:
- port: 8080
clusterIP: None
selector:
name: web-app

创建该Headless Service,然后到centos-pod容器内部查询DNS记录:

QQ截图20191203153848.png

如果没有nslookup命令,可以使用yum -y install bind-utils命令安装。

可以看到,通过解析nginx-headless-s DNS,返回了三个Nginx Pod实例地址。

集群外部访问内部

1.Pod指定hostPort,或者开启hostNetwork,这样外部就可以通过Pod宿主机IP+Pod端口访问了,但Pod调度的不确定性,这种方式不推荐;

2.通过Service的NodePort暴露服务,如果服务较多的话不推荐,因为这种方式会在集群中的所有节点上都暴露该端口,所以当服务多的时候很容易造成端口冲突,并且端口维护不便;

3.通过Ingress集中暴露服务,要暴露的服务较多的时候推荐。

这三种方式是前面博客中都有介绍到,所以就不赘述了。

集群内部访问外部

1.直接通过外部服务的IP和端口进行访问;

2.通过Service和Endpoint绑定,集群内的服务通过DNS访问集群外部服务(推荐)。

创建如下配置(test-remote.yml):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Service
metadata:
name: remote-s
spec:
ports:
- protocol: TCP
port: 8081
targetPort: 8080
---
apiVersion: v1
kind: Endpoints
metadata:
name: remote-s
subsets:
- addresses:
- ip: 192.168.73.42
ports:
- port: 8080

Service和Endpoints名称一样,所以他们会绑定上,通过访问remote-s Service便可以访问到对应的Endpoint地址192.168.73.42:8080服务(这是个我在集群外部,通过Spring Boot搭建的简单web服务)。

运行该配置后,在master节点上,测试是否可以访问:

QQ截图20191203165019.png

我们进到centos-pod容器内部,通过服务名称看看是否可以访问到:

QQ截图20191203165144.png

可以看到这种方式也是没问题的,推荐使用这种方式,可以降低耦合度。

请作者喝瓶肥宅水🥤

0