HeadLiness类型的Service
-
在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询。
-
在 Kubernetes 中,存在一种不分配 Cluster IP 的 Service 类型,称为 "Headless Service"。
-
Headless Service 的特点如下:
-
不分配 Cluster IP:与标准的 ClusterIP 类型 Service 不同,Headless Service 不会为服务分配一个虚拟 IP 地址。
-
通过域名访问:Pods 可以通过 Service 的 DNS 名称直接访问到后端的 Pods。由于没有 Cluster IP,客户端不能直接通过一个固定的 IP 地址来访问服务,而是通过 DNS 解析来获取后端 Pods 的实际 IP 地址。
-
自定义负载均衡:开发者可以自由地实现自己的负载均衡策略,而不是依赖 Kubernetes 提供的内置负载均衡。
-
DNS 解析:Kubernetes 会为每个后端 Pod 创建一个 DNS 记录。这意味着通过 DNS 查询,客户端可以获取到后端所有 Pod 的 IP 地址。
-
适用于无头服务:Headless Service 特别适合于那些需要直接与 Pod 通信的场景,例如,当使用 StatefulSets 部署具有唯一身份的 Pods 时。
-
[root@k8s-master ~]# cat service-headliness.yaml
---
apiVersion: v1
kind: Service
metadata:name: svc-clusteripnamespace: test
spec:selector:app: nginx-podclusterIP: None #这里IP设为Nonetype: ClusterIPsessionAffinity: ClientIPports:- port: 80targetPort: 80[root@k8s-master ~]# kubectl apply -f service-headliness.yaml
service/svc-clusterip created
[root@k8s-master ~]# kubectl describe service/svc-clusterip -n test
Name: svc-clusterip
Namespace: test
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.169.132:80,10.244.36.80:80,10.244.36.81:80
Session Affinity: ClientIP
Events: <none>
[root@k8s-master ~]# kubectl get svc,pod -n test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/svc-clusterip ClusterIP None <none> 80/TCP 2m44sNAME READY STATUS RESTARTS AGE
pod/pc-deployment-7b7c9c7cfd-4m68g 1/1 Running 0 3h17m
pod/pc-deployment-7b7c9c7cfd-ctdtf 1/1 Running 0 3h17m
pod/pc-deployment-7b7c9c7cfd-gjn74 1/1 Running 0 3h17m
[root@k8s-master ~]# kubectl exec -it pod/pc-deployment-7b7c9c7cfd-4m68g -n test /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pc-deployment-7b7c9c7cfd-4m68g:/# cat /etc/resolv.conf
nameserver 10.96.0.10
search test.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5
root@pc-deployment-7b7c9c7cfd-4m68g:/# ^C
root@pc-deployment-7b7c9c7cfd-4m68g:/# exit
exit
command terminated with exit code 130
[root@k8s-master ~]# dig @10.96.0.10 service-headliness.test.svc.cluster.local
-bash: dig: command not found
[root@k8s-master ~]# dig @10.96.0.10 service-headliness.test.svc.cluster.local; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.16 <<>> @10.96.0.10 service-headliness.test.svc.cluster.local
; (1 server found)
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48627
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;service-headliness.test.svc.cluster.local. IN A;; AUTHORITY SECTION:
cluster.local. 30 IN SOA ns.dns.cluster.local. hostmaster.cluster.local. 1737550192 7200 1800 86400 30;; Query time: 17 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Wed Jan 22 07:58:04 EST 2025
;; MSG SIZE rcvd: 163[root@k8s-master ~]# nslookup svc-clusterip.test.svc.cluster.local 10.96.0.10
Server: 10.96.0.10
Address: 10.96.0.10#53Name: svc-clusterip.test.svc.cluster.local
Address: 10.244.36.81
Name: svc-clusterip.test.svc.cluster.local
Address: 10.244.36.80
Name: svc-clusterip.test.svc.cluster.local
Address: 10.244.169.132
NodePort类型的Service
-
之前的样例中,创建的Service的ip地址只有集群内部才可以访问,如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上,然后就可以通过
NodeIp: NodePort
来访问Service了。 -
NodePort 类型的 Service 是 Kubernetes 中用于将服务暴露给集群外部的一种方式。下面是 NodePort 类型 Service 的一些关键点:
-
端口映射:NodePort 类型的 Service 会在集群的所有节点上打开一个静态端口(NodePort),这个端口范围通常是 30000-32767。这个端口将被映射到 Service 所代理的后端 Pods 的端口上。
-
通过节点 IP 访问:外部用户可以通过
<NodeIP>:<NodePort>
的形式访问到这个 Service。这里的NodeIP
是集群中任何节点的 IP 地址,而NodePort
是 Service 映射的端口号。 -
无需额外配置:与 LoadBalancer 类型相比,NodePort 不需要云服务商提供的额外配置或支持,因此它在不支持 LoadBalancer 的环境中非常有用。
-
安全性考虑:由于 NodePort 会在所有节点上开放端口,因此需要考虑到安全性问题。通常建议使用防火墙规则来限制访问,只允许特定的 IP 地址访问这些端口。
-
适用于简单的外部访问:NodePort 适合于简单的外部访问需求,但对于生产环境,通常推荐使用 LoadBalancer 或 Ingress,因为它们提供了更好的性能、安全性和高级路由功能。
-
[root@k8s-master ~]# vim service-nodeport.yaml
---
apiVersion: v1
kind: Service
metadata:name: svc-nodeportnamespace: test
spec:selector:app: nginx-podtype: NodePortports:- port: 80 # Service 在所有节点上监听的端口号nodePort: 32522 # 默认的取值范围是:30000-32767, 如果不指定,会默认分配targetPort: 80 # 后端 Pod 监听的端口号
[root@k8s-master ~]# kubectl apply -f service-nodeport.yaml
service/svc-nodeport created
[root@k8s-master ~]# kubectl get svc -n test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-clusterip ClusterIP None <none> 80/TCP 13m
svc-nodeport NodePort 10.96.150.190 <none> 80:32522/TCP 10s
[root@k8s-master ~]# kubectl get svc,pod -n test -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/svc-clusterip ClusterIP None <none> 80/TCP 13m app=nginx-pod
service/svc-nodeport NodePort 10.96.150.190 <none> 80:32522/TCP 26s app=nginx-podNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/pc-deployment-7b7c9c7cfd-4m68g 1/1 Running 0 3h28m 10.244.36.81 k8s-node1 <none> <none>
pod/pc-deployment-7b7c9c7cfd-ctdtf 1/1 Running 0 3h28m 10.244.169.132 k8s-node2 <none> <none>
pod/pc-deployment-7b7c9c7cfd-gjn74 1/1 Running 0 3h28m 10.244.36.80 k8s-node1 <none> <none>
[root@k8s-master ~]# curl 10.244.36.81:80
10.244.36.81 web-01[root@k8s-master ~]# curl 192.168.58.231:32522
10.244.36.81 web-01
[root@k8s-master ~]# ipvsadm -Ln | grep -A3 32522
TCP 192.168.58.231:32522 rr-> 10.244.36.80:80 Masq 1 0 1 -> 10.244.36.81:80 Masq 1 0 1 -> 10.244.169.132:80 Masq 1 0 0
--
TCP 10.244.235.192:32522 rr-> 10.244.36.80:80 Masq 1 0 0 -> 10.244.36.81:80 Masq 1 0 0 -> 10.244.169.132:80 Masq 1 0 0
TCP 127.0.0.1:32522 rr-> 10.244.36.80:80 Masq 1 0 0 -> 10.244.36.81:80 Masq 1 0 0 -> 10.244.169.132:80 Masq 1 0 0
TCP 172.17.0.1:32522 rr-> 10.244.36.80:80 Masq 1 0 0 -> 10.244.36.81:80 Masq 1 0 0 -> 10.244.169.132:80 Masq 1 0 0