本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net
一、service 服务:
在 k8s 集群中,service 是一个抽象概念,它通过一个虚拟的 IP 映射指定的端口,将代理客户端发来的请求转到后端一组 pod 中的一个上。
这是个神马意思呢?pod 中的容器经常在不停地销毁和重建,因此 pod 的 IP 会不停的改变,如果客户端不知道 pod 的 IP 已经变化,继续访问之前的 IP 是无法访问容器。就算客户端知道了 pod 的 IP 变化了,每次重建后访问都需要更换 IP,效率极为低下。这时候就有了 service 代理服务,类似于 nginx 代理,作为客户端和 pod 的中间层,在通过 service.yaml 创建 service 资源后,随机虚拟创建一个固定的 ip 和 port,这时候在创建 pod,比如 deployment 类型的 nginx,service 资源通过标签选择器查找同名称空间下标签为刚才创建的 deployment 类型的名字为 nginx 资源进行绑定,就算 pod 不停地销毁和重建,并且不管有几个 nginx 的 pod,都会跟这一个固定 ip 和 port 绑定,kubernetes 内部会时刻更新这组关联关系,客户端访问固定 ip 和 port,后端进行负载均衡机制分别访问不同的 nginx 的 pod。pod 的 IP 会不停的改变,但是 service 的 ip 和 port 不变。
其中上述讲到,如果 pod 控制器使用 rc 创建了多个 pod 副本,service 还是固定一个 ip 和 port,客户端访问固定 ip 和 port,后端通过 kube-proxy,实现负载均衡
vi service.yaml kind: Service apiVersion: v1 metadata: name: nginx namespace: default spec: ports: - protocol: TCP port: 80 targetPort: 8080 selector: app: nginx其中这个service代理了所有deglut命名空间下具有app: nginx标签的pod,service资源定义了targetPort,访问我service资源固定IP+8080端口,负载均衡被重定向到后端pod的80端口,使用的TCP协议进行流量访问。 每个node节点都有一个组件kube-proxy,实际上是为service服务的,通过kube-proxy,实现流量从service到pod的转发,kube-proxy也可以实现简单的负载均衡功能。 kube-proxy代理模式:userspace方式:kube-proxy 在节点上为每一个服务创建一个临时端口,service的IP:port 过来的流量转发到这个临时端口上,kube-proxy会用内部的负载均衡机制(轮询),选择一个后端pod,然后建立iptables,把流量导入这个pod里面
其实 service 在 kubernetes 版本迭代中,有过几次变更。在 kubernetes v1.0 中开始使用 userspace proxy mode(用户空间代理态代理模式),kubernetes v1.1 增加了 iptables 代理模式,kubernetes v1.2 默认把 iptables 当成 kube-proxy 的代理模式。在 kubernetes v1.8 增加了性能更强劲的 ipvs proxy mode。
例子:
创建一个 nginx 的 dp 和 svc,查看过程:
了解:不同的命名空间是有隔离性的。各种资源只能在相同命名空间下,通过标签互相构建连接。所以不同名命空间下可以存在相同名字的标签,互不影响。
[root@hdss7-21 ~]# vi nginx-dp-svc.yaml
apiVersion: v1
kind: Service
metadata:
labels: ## 定义标签
app: nginx-dp ## 定义了svc在标签叫nginx-dp
name: nginx-dp ## 在命名空间下显示这个server资源的名字是nginx-dp
namespace: kube-system ## 在kube-system命名空间下
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-cs ## 标签选择器selector定义了要跟(server同命空间下的标签为nginx-cs的pod容器连接)
sessionAffinity: None
type: ClusterIP
创建 server 资源:
[root@hdss7-21 ~]# kubectl apply -f nginx-dp-svc.yaml
查看 server 资源:
[root@hdss7-21 ~]# kubectl get svc -o wide -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-dp ClusterIP 192.168.39.130 <none> 80/TCP 8s app=nginx-cs
[root@hdss7-21 ~]# curl 192.168.39.130:80
curl: (7) Failed connect to 192.168.39.130:80; Connection refused
创建 deployment 资源:
[root@hdss7-21 ~]# vi nginx-cs-dp.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: nginx-cs ## 定义了标签叫nginx-cs
name: nginx-cs ## 在命名空间下显示这个Deployment资源的名字是nginx-cs
namespace: kube-system ## 在kube-system命名空间下
spec:
replicas: 1
selector:
matchLabels:
app: nginx-cs
template:
metadata:
labels:
app: nginx-cs
spec:
tolerations:
- key: bxj
effect: NoSchedule
containers:
- image: nginx:latest
imagePullPolicy: IfNotPresent
name: nginx
创建 Deployment 资源:
[root@hdss7-21 ~]# kubectl apply -f nginx-cs-dp.yaml
查看容器,并访问容器 80 无问题:
[root@hdss7-21 ~]# kubectl get pod -o wide -n kube-system
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-cs-7679bbd57d-9v8p2 1/1 Running 0 8s 172.7.22.8 hdss7-22.host.com <none> <none>
[root@hdss7-21 ~]# curl 172.7.22.8:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
访问 server 的 ClusterIP:
[root@hdss7-21 ~]# kubectl get svc -o wide -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-dp ClusterIP 192.168.39.130 <none> 80/TCP 3m46s app=nginx-cs
[root@hdss7-21 ~]# curl 192.168.39.130:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
给容器缩容为 0,在访问 server 的 ClusterIP:
[root@hdss7-21 ~]# kubectl scale deployment nginx-cs --replicas=0 -n kube-system
[root@hdss7-21 ~]# curl 192.168.39.130:80
curl: (7) Failed connect to 192.168.39.130:80; Connection refused
[root@hdss7-21 ~]#
总结:server 资源的标签,命名空间下的名字,都可以随意起。但是命名空间必须跟 delpoyment 资源是一个,否则无法连接。
二、常规的 service 服务和无头服务的区别:
常规的service服务和无头服务的区别
● service:一组Pod访问策略,提供cluster-IP群集之间通讯,还提供负载均衡和服务发现
● Headless service 无头服务,不需要cluster-IP,clusterIP为None的service,直接绑定具体的Pod的IP,无头服务经常用于statefulset的有状态部署。
注:server资源默认分配给cluster-IP是为了让客户端能访问。而server还提供了pod之间的相互发现,互相访问资源,他们不需要cluster-IP
无头服务yaml格式:
apiVersion: v1
kind: Service
metadata:
name: myweb-service
spec:
selector:
python: myweb
type: ClusterIP
clusterIP: None ## 集群IP为None
ports:
- port: 81
targetPort: 80
正常的service的yaml格式:
apiVersion: v1
kind: Service
metadata:
name: myweb-service
spec:
selector:
python: myweb
ports:
- port: 81
targetPort: 80
在yaml中,默认不写代表分配集群ClusterIP,声明None无ClusterIP
进入工具型 Pod,并且在 pod 中查询 service 的解析地址 {ServiceName}.{Namespace}.svc.{ClusterDomain}
三、无头服务使用场景:
1、无头服务用于服务发现机制的项目或者中间件,如 kafka 和 zookeeper 之间进行 leader 选举,采用的是实例之间的实例 IP 通讯。
2、既然不需要负载均衡,则就不需要 Cluster IP,如果没有 Cluster IP 则 kube-proxy 不会处理它们, 并且 kubernetes 平台也不会给他创建负载均衡。
四、k8s 内部资源互相调用解析:
通过 deployment 资源,生成 pod 控制器,通过控制器生成一份或多份的 pod。同命名空间下,创建 service 资源,service 资源的 yaml 配置连接同命名空间下的那个标签 lables 的资源,通过此方式连接了刚刚创建的 pod 控制器资源,同时默认 service 资源的 yaml 配置生成一个集群 IP+port,也就是反向代理后端刚刚连接上的 deployment(pod 控制器)资源,客户端访问集群 IP+port,就会负载均衡的方式访问绑定的 pod,通过 kube-proxy 组件进行资源的调度,负载。而内部的资源,比如另一个 pod 控制器想访问 deployment(pod 控制器)的资源,由于 deployment 可能启动多份 pod,而且 pod 的 IP 也会变化,所以 k8s 内部资源通过 IP 方式互相通信是不可能的。但是 lables 是不变,而 serice 操作了此过成,通过 service 资源绑定后,访问 service 资源的解析地址 (nginx-ds.default.svc.cluster.local.) 即可进行容器的服务互相发现。调用方式不是集群 IP+port
解决 Debian 系统错误:E: Unable to locate package vim_fgx_123456 的博客 - CSDN 博客
[root@7-22 ~]# cat nginx-ds.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: nginx-ds
spec:
template:
metadata:
labels:
app: nginx-ds
spec:
containers:
- name: my-nginx
image: harbor.od.com:180/public/nginx:v1.7.9
ports:
- containerPort: 80
root@nginx-ds-68w5b:/etc/apt# curl 192.168.189.12
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
...
root@nginx-ds-68w5b:/etc/apt# curl nginx-ds.default.svc.cluster.local. # 容器内部可通过sercie资源访问同命名空间下的其他资源
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
...
root@nginx-ds-68w5b:/etc/apt#
五、无头服务使用环境:
4.1、中间件场景(识别未就绪的 pod)
无头服务有一个很重要的场景是发现所有的 pod(包括未就绪的 pod),只有准备就绪的 pod 能够作为服务的后端。但有时希望即使 pod 没有准备就绪,服务发现机制也能够发现所有匹配服务标签选择器的 pod。
比如 zk 集群,zk 节点 pod 之间必须互相识别之后进行选举,pod 状态才会变为就绪,使用无头服务完美的解决这个问题。
4.2、当不需要负载均衡以及Service IP时
还是以 zk 场景为例,zk 节点之间通讯的端口是2888和3888,确实也不需要负载均衡以及Service IP。而提供给客户端的端口是2181,只有它需要,所以结合以上 2 个场景:
无头服务(用于 zk pod 之间彼此的通讯和选举的):
apiVersion: v1
kind: Service
metadata:
name: zk-hs
labels:
app: zk
spec:
# 这使得服务成为无头服务
clusterIP: None
ports:
- port: 2888
name: server
- port: 3888
name: leader-election
selector:
app: zk
正常的 service 给客户端的(需要负载均衡和 cluster ip 的):
apiVersion: v1
kind: Service
metadata:
name: zk-cs
labels:
app: zk
spec:
ports:
- port: 2181
name: client
selector: