Fork me on GitHub

kubernetes系列之《Service》

简单了解Service:

  • 防止Pod失去联系(服务发现)
  • 定义一组Pod的访问策略(负载均衡)
  • 支持ClusterIP,NodePort以及LoadBalancer三种类型
  • Service的底层实现主要有iptables和ipvs两种网络模式

Services在kubenetes中,是帮助Pod提供网络服务的。比如你要访问Pod里的应用,需要通过端口来访问,而Service可以通过端口代理转发,让你通过Node节点上的端口能够访问到你的Pod应用。

一、Pod与Service的关系

  • 通过lable-selector相关联
  • 通过Service实现Pod的负载均衡(TCP/UDP 4层)

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
30
31
32
33
34
35
[root@k8s-master-128 dome]# cat deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels: # 这里是定义Deployment的标签
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx # 选择关联Deployment标签
template:
metadata:
labels: # 给Pod定义一个标签,方便其他服务关联这个Pod
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector: # Service 的selector 指定标签 app:nginx 来进行对Pod进行关联 ;(这里的app:nginx就是上面Deployment配置里labels定义的标签 )
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort

可以通过以下方式查看Service与Pod的关联:

首先查看创建的Service,通过-o wide输出详细信息

1
2
3
4
[root@k8s-master-128 dome]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 5d5h <none>
nginx-service NodePort 10.1.230.224 <none> 80:30234/TCP 24h app=nginx

通过 kubectl describe pod 查看pod的详情,里面就有标签信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@k8s-master-128 dome]# kubectl describe pod nginx-deployment-6dd86d77d-kxkmt
Name: nginx-deployment-6dd86d77d-kxkmt
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: k8s-node-130/172.16.194.130
Start Time: Mon, 20 May 2019 16:30:32 +0800
Labels: app=nginx # 这里就是pod定义的标签
pod-template-hash=6dd86d77d
Annotations: <none>
Status: Running
IP: 10.244.2.14
Controlled By: ReplicaSet/nginx-deployment-6dd86d77d
···略···

也可以通过-o wide查看Deployment的标签信息

1
2
3
[root@k8s-master-128 dome]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deployment 3/3 3 3 24h nginx nginx:1.7.9 app=nginx

二、Service的三种类型

发布的服务类型有三种:ClusterIP、NodePort和LoadBalancer
官网地址:https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types

2.1、ClusterIP

分配一个内部集群IP地址,只能在集群内部访问(同Namespaces内的Pod),不对外提供访问服务!默认ServiceTpye。

来看一个示例说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@k8s-master-128 dome]# cat service-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80

[root@k8s-master-128 dome]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 5d5h
nginx-service ClusterIP 10.1.0.32 <none> 80/TCP 24h

我们能看到CLUSTER-IP下显示着 Service所提供集群内部使用的IP地址,这个地址只能在k8s集群内部访问哦!
再看PORT(S)字段:80/TCP

  • 80是暴露给集群的端口,通过集群ip加端口可以访问:curl http://10.1.0.32:80

Node节点上能查看到创建的iptables规则:

1
2
3
[root@k8s-node-129 ~]# iptables-save |grep 10.1.0.32
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.1.0.32/32 -p tcp -m comment --comment "default/nginx-service: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.1.0.32/32 -p tcp -m comment --comment "default/nginx-service: cluster IP" -m tcp --dport 80 -j KUBE-SVC-GKN7Y2BSGW4NJTYL

能看到我们创建了Service后,在所有Node节点上都会自动创建转发规则,来实现Pod的网络访问。

2.2、NodePort

分配一个内网集群IP地址,并在内个节点上启用一个端口来暴露服务,可以在集群外部访问。
访问地址::

接上面ClusterIP的官网Yaml示例,继续研究NodePort:

1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80 # 需要暴露的集群端口
targetPort: 9376 # 容器的端口
type: NodePort

上面说过Service默认的类型是ClusterIP,如果需更改成NodePort类型,则需要将type字段指定类型即可;

说说type: NodePort

1
2
3
4
5
[root@k8s-master-128 dome]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 5d6h <none>
nginx-service NodePort 10.1.230.224 <none> 80:30234/TCP 25h app=nginx
# 创建出来的NodePort服务,也会有一个cluster ip;

根据上面的信息,nginx-service这个服务的NodePort所对应的则是30234,而这个端口是在Node节点上由kube-proxy来启动并监听的,因此我们可以通过NodeIP+端口的方式直接进行访问,就是因为kube-proxy进行了代理。
继续扩展说明,kube-proxy是如何代理访问到容器的呢?因为kube-proxy在启动的时候通过--proxy-mode=ipvs可以指定底层内核代理模式,默认是iptables进行代理转发,kube-proxy通过这两种模式来代理直接对外提供服务。

2.3、LoadBalancer

分配一个内部集群IP地址,并在每个节点上启用一个端口来暴露服务。
除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。

LoadBalancer只适用于云平台,AWS默认就支持,阿里云社区开发也支持。

三、Service代理模式

service有三组代理模式:userspace、iptables和ipvs

3.1、Userspace模式

  1. 客户端访问ServiceIP,ServiceIP将请求交给了kube-proxy,然后分发到Pod进行通讯。
  2. 多了kube-proxy转发,效率较低!kube-proxy工作在用户态,故是Userspace模式。

3.2、Iptables模式

  1. 客户端访问ServiceIP,通过iptables转发给Pod。1.9x版本默认代理模式。
  2. iptables基于linux内核(Netfilet)实现的,运行在内核态,内核直接处理请求,因此效率较高。

3.3、Ipvs模式

  1. ipvs在k8s1.10以上版本中,将会是默认代理模式。
  2. 客户端访问ServierIP,通过虚拟服务器将请求转发给RS(也就是Pod),该模式采用LVS技术,早在linux发行版本中就已将lvs嵌入进去,lvs运行在内核态,处理效率相比上面两个是最优的。

3.4、Iptables模式 vs Ipvs模式

目前用到最多的就是这两个模式,上面也提到了ipvs会是将来版本中默认的代理模式,这里进行简单的对比:

  • iptables:
    • 灵活性,功能强大
    • 规则遍历匹配和更新,呈线性延迟
    • 可扩展性
  • ipvs:
    • 工作在内核,有更高的性能
    • 调度算法丰富:rr, wrr, lc, wlc, ip hash;LVS的调度算法皆可用

参考文章:

-------------本文结束感谢您的阅读-------------