1 Service
Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种能够访问它们的策略 —— 一般被称为微服务。这一组 Pod 可以被 Service 访问到,一般是经过selector 实现的。
举例:考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪一个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不必知道,并且也不需要跟踪这一组 backend 的状态。Service 定义的抽象可以解耦这种关联。
Service能够提供负载均衡的能力,可是使用上存在以下限制
- 只能提供4层负载均衡能力,而没有7层功能。有时咱们可能须要更多的匹配规则来转发请求,这点上4层负载均衡是不支持的
web访问的service服务示例图
2 service暴露端口的方式
2.1 clusterIP
此类型会提供一个集群内部的虚拟IP(与pod不在同一网段),以供集群内部的pod之间通信使用。clusterIP 也是kubernetes service 的默认类型,主要需要以下几个组件的协同工作
apiservice :在创建service 时,apiserver 接收到请求以后将数据存储到etcd 中。kube-proxy :k8s的每个节点中都有该进程,负责实现service功能,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables 中 -iptables :使用NAT等技术将virtuallp 的流量转至endpoint 中
2.2 NodePort
NodePort 模式除了使用clusterip 外,也将service 的port映射到每个node的一个指定内部的port上,映射的每个node的内部port都一样。为每个节点暴露一个端口,通过nodeIP+nodeport 可以访问你这个服务,同时服务依然会有cluster 类型的ip+port 。内部通过clusterip 方式访问,外部通过nodeport 方式访问
2.3 loadbalancer
loadbalancer 在nodeport 基础上,k8s可以请求底层云平台创建一个负载均衡器,将每个node作为后端,进行服务分发,该模式需要底层云平台(例如GCE)支持
2.4 lngress
lngress 是一种http 方式的路由转发机制由lngress controller 和http 代理服务器组合而成,lngress controller 实例监控kubernetes api 实时更新http 代理服务器的转发规则。http 代理服务器有GCE load-balancer、haproxy、nginx 等开源方案
service 是一个抽象概念,定义了一个服务的多个pod逻辑合集和访问pod的策略,一般把service 称为微服务.举个例子一个a服务运行3个pod,b服务怎么访问a服务的pod,pod的ip都不是持久化的重启之后就会有变化。这时候b服务可以访问跟a服务绑定的service ,service 信息是固定的提前告诉b就行了,service 通过Label Selector 跟a服务的pod绑定,无论a的pod如何变化对b来说都是透明的
3 kubernetes代理方式
在Kubernetes 集群中,每一个 Node 运行一个kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)的形式,而不是 ExternalName 的形式
从Kubernetes v1.0 开始,已经可使用 userspace 代理模式。Kubernetes v1.1 添加了 iptables 代理模式,在Kubernetes v1.2 中kube-proxy 的 iptables 模式成为默认设置。Kubernetes v1.8 添加了ipvs 代理模式
3.1 userspace代理模式
这种模式kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。 对每一个 Service 它会在本地 Node 上打开一个端口(随机选择)。 任何链接到代理端口 的请求,都会被代理到 Service 的backend Pods 中的某个上面(如 Endpoints 所报告的同样)。 使用哪一个 backend Pod ,是 kube-proxy 基于 SessionAffinity 来肯定的
它配置iptables 规则,捕获到达该 Service 的 clusterIP (是虚拟 IP)和 Port 的请求,并重定向到代理端口,代理端口再代理请求到 backend Pod
默认状况下,userspace 模式下的kube-proxy 经过循环算法选择后端,默认的策略是,经过round-robin 算法来选择 backend Pod
3.2 iptables 代理模式
这种模式,kube-proxy 会监视Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每一个 Service 它会配置iptables 规则,从而捕获到达该Service 的clusterIP 和端口的请求进而将请求重定向到Service 的一组 backend 中的某个上面。对于每一个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个backend 组合。
默认的策略是kube-proxy 在 iptables 模式下随机选择一个backend
使用iptables 处理流量具备较低的系统开销,由于流量由Linux netfilter 处理,而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。
若是kube-proxy 在 iptables 模式下运行,而且所选的第一个Pod 没有响应,则链接失败。 这与userspace 模式不一样;在这种状况下kube-proxy 将检测到与第一个 Pod 的链接已失败,并会自动使用其余后端 Pod 重试。
咱们可使用Pod readiness 探测器 验证后端 Pod 是否能够正常工做,以便 iptables 模式下的kube-proxy 仅看到测试正常的后端。这样作意味着能够避免将流量经过kube-proxy 发送到已知已失败的Pod
3.3 IPVS 代理模式
在 ipvs 模式下kube-proxy 监视Kubernetes 服务Service 和端点Endpoints 调用 netlink 接口相应地建立 IPVS 规则, 并按期将 IPVS 规则与Kubernetes 服务Service 和端点Endpoints 同步。该控制循环可确保IPVS 状态与所需状态匹配。访问服务Service 时,IPVS 将流量定向到后端Pod之一
IPVS 代理模式基于相似于iptables 模式的 netfilter 挂钩函数,可是使用哈希表做为基础数据结构,而且在内核空间中工做。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的kube-proxy 重定向通讯的延迟要短,而且在同步代理规则时具备更好的性能。与其余代理模式相比,IPVS 模式还支持更高的网络流量吞吐量
IPVS 提供了更多选项来平衡后端Pod的流量
- rr: round-robin(循环)
- lc: least connection (smallest number of open connections) (最小连接(打开连接的最小数量))
- dh: destination hashing (目的地址哈希调度)
- sh: source hashing (源地址哈希调度)
- sed: shortest expected delay(最短的预期延迟)
- nq: never queue(无须队列等待)
注意: 要在IPVS 模式下运行kube-proxy 必须在启动kube-proxy 以前使IPVS Linux 在节点上可用。 当kube-proxy 以IPVS 代理模式启动时,它将验证IPVS 内核模块是否可用。 若是未检测到IPVS 内核模块,则 kube-proxy 将退回到以iptables 代理模式运行
4 Service服务类型
-
ClusterIP :默认类型,自动分配一个仅Cluster 内部能够访问的虚拟IP (只能在集群内部访问) -
NodePort :经过每一个 Node 上的 IP 和静态端口(NodePort)(范围30000-32767) 暴露服务。以ClusterIP 为基础NodePort 服务会路由到 ClusterIP 服务。经过请求<NodeIP>:<NodePort> 能够从集群的外部访问一个集群内部的 NodePort 服务ClusterIP 和路由规则会自动创建 -
LoadBalancer :使用云提供商的负载均衡器,能够向外部暴露服务。外部的负载均衡器能够路由到 NodePort 服务和 ClusterIP 服务 -
ExternalName 创建一个dns 别名指到service name 上,主要是防止service name 发生变化,要配合dns插件使用
5 实列
5.1 ClusterIP
[root@master ~]# vi network.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: v1
template:
metadata:
labels:
app: myapp
release: v1
spec:
containers:
- name: myapp
image: zhaojie10/httpd:v0.1
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: myapp-nodeport
namespace: default
spec:
type: ClusterIP
selector:
app: myapp
release: v1
ports:
- name: httpd
port: 80
targetPort: 80
# 应用资源清单文件,创建资源
[root@master ~]# kubectl apply -f network.yaml
deployment.apps/myapp-deploy created
service/myapp-nodeport created
# 查看pod,service运行情况
[root@master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/myapp-deploy-667bd747b6-6mkmq 1/1 Running 0 6m30s
pod/myapp-deploy-667bd747b6-wp65f 1/1 Running 0 6m30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d22h
service/myapp-nodeport ClusterIP 10.98.197.112 <none> 80/TCP 6m30s
# 查看iptables,规则
[root@master ~]# iptables -t nat -nvL | grep 'myapp-nodeport'
0 0 KUBE-MARK-MASQ all -- * * 10.244.2.173 0.0.0.0/0 /* default/myapp-nodeport:httpd */
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ tcp to:10.244.2.173:80
0 0 KUBE-MARK-MASQ all -- * * 10.244.1.126 0.0.0.0/0 /* default/myapp-nodeport:httpd */
2 120 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ tcp to:10.244.1.126:80
2 120 KUBE-SVC-UJB7KAYNZVW7NK6H tcp -- * * 0.0.0.0/0 10.98.197.112 /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
2 120 KUBE-MARK-MASQ tcp -- * * !10.244.0.0/16 10.98.197.112 /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
2 120 KUBE-SEP-WXLK2WHO6A3V7JDH all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-BXPFXJRGQ62K7TWT all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */
# 访问测试
[root@master ~]# curl 10.98.197.112
This is V1!
5.2 NodePort
[root@master ~]# vi network.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: v1
template:
metadata:
labels:
app: myapp
release: v1
spec:
containers:
- name: myapp
image: zhaojie10/httpd:v0.1
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: myapp-nodeport
namespace: default
spec:
type: NodePort // 指定NodePort类型
selector:
app: myapp
release: v1
ports:
- name: httpd
port: 80
targetPort: 80
nodePort: 30001 //指定对外端口
# 应用修改后的资源定义文件,重启pods
[root@master ~]# kubectl apply -f network.yaml
deployment.apps/myapp-deploy unchanged
service/myapp-nodeport configured
# 查看pods,service状态
[root@master ~]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/myapp-deploy-667bd747b6-6mkmq 1/1 Running 0 30m
pod/myapp-deploy-667bd747b6-wp65f 1/1 Running 0 30m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d23h
service/myapp-nodeport NodePort 10.98.147.133 <none> 80:30001/TCP 30m
# 查看iptables 规则
[root@master ~]# iptables -t nat -nvL | grep 'myapp-nodeport'
1 60 KUBE-SVC-UJB7KAYNZVW7NK6H tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ tcp dpt:30001
0 0 KUBE-MARK-MASQ all -- * * 10.244.2.173 0.0.0.0/0 /* default/myapp-nodeport:httpd */
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ tcp to:10.244.2.173:80
0 0 KUBE-MARK-MASQ all -- * * 10.244.1.126 0.0.0.0/0 /* default/myapp-nodeport:httpd */
1 60 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ tcp to:10.244.1.126:80
0 0 KUBE-SVC-UJB7KAYNZVW7NK6H tcp -- * * 0.0.0.0/0 10.98.147.133 /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
0 0 KUBE-MARK-MASQ tcp -- * * !10.244.0.0/16 10.98.147.133 /* default/myapp-nodeport:httpd cluster IP */ tcp dpt:80
1 60 KUBE-MARK-MASQ tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ tcp dpt:30001
1 60 KUBE-SEP-WXLK2WHO6A3V7JDH all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-BXPFXJRGQ62K7TWT all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/myapp-nodeport:httpd */
# 访问测试
[root@master ~]# curl 192.168.25.146:3000
This is V1!
5.3 ExternalName
[root@master ~]# vi network.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: v1
template:
metadata:
labels:
app: myapp
release: v1
spec:
containers:
- name: httpd
image: zhaojie10/httpd:v0.2 //此处将镜像,更换为基于contos编译的httpd镜像
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: myapp-externalname
namespace: default
spec:
type: ExternalName //指定类型
externalName: my.k8s.example.com
# 使用修改过后的资源定义文件,重启pods
[root@master ~]# kubectl apply -f network.yaml
deployment.apps/myapp-deploy configured
service/myapp-externalname unchanged
# 查看pod,service状态
[root@master ~]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/myapp-deploy-6768948cc-5gkk9 1/1 Running 0 9m8s
pod/myapp-deploy-6768948cc-gf5cnr 1/1 Running 0 9m6s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d
service/myapp-externalname ExternalName <none> my.k8s.example.com <none> 32m
# 此处Type,改为 ExternalName模式了
ExternalName 类型的Service 经过返回CNAME 和它的值,能够将服务映射到externalName 字段的内容(例如:my.k8s.example.com;能够实现跨namespace名称空间访问)。ExternalName Service 是Service 的特例,它没有selector 也没有定义任何的端口和Endpoint 。相反的,对于运行在集群外部的服务,它经过返回该外部服务的别名这种方式提供服务
|