前言
Pod 曾经胜利运行起来了,然而有两个问题。
一是这些 Pod 无奈从集群内部间接拜访到,二是 Pod 呈现故障自愈后,IP 会发生变化。
如何解决这两个问题,这里有一个十分重要的概念:Service
更新历史
- 20200625 – 初稿 – 左程立
- 原文地址 – https://blog.zuolinux.com/2020/06/25/about-service.html
Service 的意义和特点
- 对一组 Pod 提供负载平衡(工作在 TCP/UDP 4 层)
- 避免 Pod 更换 IP 失联,即服务发现
- 通过 label selector 关联 Pod
Service 工作原理
Service 是由 kube-proxy 组件加上 iptables/LVS 独特实现。
说白了就是通过 kube-proxy 生成了一堆 iptables 规定,通过 iptables 规定来转发数据。
iptables 转发:
- K8S 默认的转发设置。
- 抉择后端 Pod 为随机抉择。
- 当 Pod 没有响应,连贯会失败,并没有健康检查机制。
- 须要配合 Pod 就绪探测器来确保拜访到衰弱的 Pod。
- 当集群规模达到上万个服务时,iptables 转发效率会显著升高。
LVS 转发:
- 基于内核哈希表,性能弱小,具备更高网络吞吐量。
- 实用于 Pod 量级大,转发规定更多的大规模集群。
- LVS 反对更多的 Pod 负载平衡调度算法。
- LVS 只负责负载平衡和代理性能,残余的包过滤和 SNAT 等操作还是须要 iptables 解决,但这些操作规定数量不会因 Pod 数量的减少而减少。
- 也叫 IPVS。
Service 的默认工作形式
创立 Pod 和 默认 Service,进行默认工作状态的测试。
先创立 3 个 Pod
cat nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
创立一个默认类型的 Service,名称为 nginx-service
cat nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
protocol: TCP
port: 80
是 service 在集群外部的 VIP 端口
targetPort: 80
是 Pod 的端口
执行创立
kubectl apply -f nginx.yaml
kubectl apply -f nginx-service.yaml
查看运行状况
[root@master01 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-d46f5678b-cldf4 1/1 Running 0 21m 192.10.137.153 work03 <none> <none>
nginx-deployment-d46f5678b-lnxh9 1/1 Running 0 21m 192.10.205.252 work01 <none> <none>
nginx-deployment-d46f5678b-th8xq 1/1 Running 0 21m 192.10.75.89 work02 <none> <none>
[root@master01 ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP 192.20.150.26 <none> 80/TCP 13m
查看名称为 nginx-service 的 service 胜利挂载的后端 Pod
[root@master01 ~]# kubectl get endpoints nginx-service
NAME ENDPOINTS AGE
nginx-service 192.10.137.153:80,192.10.205.252:80,192.10.75.89:80 14m
能够看到咱们创立的名为 nginx-service 的 Service 后端挂载了 3 个 Pod
给 3 个 Pod 写入内容,拜访 Pod 时返回本身的主机名
kubectl exec nginx-deployment-d46f5678b-cldf4 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
kubectl exec nginx-deployment-d46f5678b-lnxh9 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
kubectl exec nginx-deployment-d46f5678b-th8xq -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
咱们拜访 Service IP 看看
[root@master01 ~]# curl 192.20.150.26
nginx-deployment-d46f5678b-th8xq
[root@master01 ~]# curl 192.20.150.26
nginx-deployment-d46f5678b-cldf4
[root@master01 ~]# curl 192.20.150.26
nginx-deployment-d46f5678b-lnxh9
能够看到 Service 胜利将申请代理到了后端的一组 Pod,并且进行了流量的调配。
这是 Service 的默认工作类型,只能在集群所属的节点上拜访到,来到集群后无奈被拜访到。
这种工作类型叫做 ClusterIP。
Service 对外提供服务的三种形式
上一节能够看到,Service 默认不对集群内部提供服务,那么如何能力在集群内部拜访到呢,有三种计划。
externalIPs 形式
Service 中配置能够 externalIPs,IP 为本集群中 work 节点宿主机 IP。
apiVersion: v1
kind: Service。。。。。。spec:。。。。。。externalIPs:
- 192.168.10.16
- 192.168.10.17
在 192.168.10.16/17 上执行 ss -lntp 能够看到 Service 定义的裸露端口。
在集群内部拜访 192.168.10.16/17 上 Service 裸露的端口即可。
NodePort 形式
革新 nginx-service.yaml,减少一行 type: NodePort
cat nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
protocol: TCP
创立 service
kubectl apply -f nginx-service.yaml
查看运行状况
[root@master01 ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 192.20.167.221 <none> 80:30913/TCP 13m
参数 PORT(S) 80:30913/TCP,其中 30913 就是用来集群内部拜访的端口。
能够拜访任何一台物理宿主机的 ip:30913 来拜访到 Pod。
30913 是 K8S 从固定范畴 30000-32767 中抉择的,也能够通过参数 nodePort 指定固定端口。
可抉择范畴能够通过 kube-apiserver 的 –service-node-port-range 参数来批改。
[root@master01 ~]# ss -nltp | grep 30913
LISTEN 0 128 *:30913 *:*
能够看到宿主机上监听了 30913 端口。
测试
在没有运行 K8S 集群的机器上拜访 K8S 宿主机
[root@192-168-10-18 ~]# curl 192.168.10.12:30913
nginx-deployment-d46f5678b-2pmts
[root@192-168-10-18 ~]# curl 192.168.10.12:30913
nginx-deployment-d46f5678b-zv8m4
[root@192-168-10-18 ~]# curl 192.168.10.12:30913
nginx-deployment-d46f5678b-2pmts
能够看到从集群内部能够胜利拜访到 Pod 中内容,并且为随机调配。
原理
kube-proxy 在宿主机上创立了 iptables 规定,对宿主机 IP:30913 的拜访将被转发到 Service IP,而后 Service 再通过本人的 iptables 规定散发到 Pod
LoadBalancer 形式
NodePort 形式中,如果要正式对外提供服务,咱们须要在集群内部再创立一个高可用的负载均衡器,以不便把流量转发到宿主机凋谢的端口上,如果宿主机凋谢端口产生了变更,咱们须要手工批改前端负载均衡器。
私有云的 LoadBalancer 自动化了这一过程。
LoadBalancer 这种形式利用于私有云,提交一个 type: LoadBalancer 的 Service 创立申请后,私有云会帮咱们创立一个负载均衡器,该负载均衡器会把申请间接分发给 Pod,同时 Pod IP 发生变化后,会自动更新到负载均衡器上。
其余:Headless Service
通过指定 spec.clusterIP 的值为 “None” 能够创立 Headless Service。
Headless Service 不会调配 Cluster IP,kube-proxy 不会解决它们,而且平台也不会为它们进行负载平衡和路由。
定义了 selector 的无头服务,Endpoint 控制器会在 API 中创立 Endpoints 记录,并且批改 DNS 配置返回 A 记录,通过这个地址,申请能够间接达到 Service 的后端 Pod 上。
结束语
Service 对 IP 信息易变的 Pod 提供了服务发现、负载平衡等治理性能,同时提供了内部拜访的能力,从而使内部用户可能稳固的拜访到运行在集群外部的 Pod 提供的服务。
下面说的三种工作形式有如下问题:
- ClusterIP 形式默认工作在集群外部,应用参数 externalIPs 可指定哪个及诶按裸露端口,但无奈进行 7 层的 URL 跳转等管制
- NodePort 形式下,全副节点都会裸露该端口,但一个端口只能对应一个业务,适宜业务比拟少的环境或者测试环境,业务多了当前无奈无效治理
- LoadBalance 形式只适宜于现有的私有云平台,无奈用于自建集群,同时还须要额定费用
这些问题导致无奈间接利用于生产环境中。
如果想提供给自建集群的生产环境应用,须要在 Service 后面再加一层 Ingress Controller。
分割我
微信公众号:zuolinux_com