Kubernetes Service原理解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes Service原理解析相关的知识,希望对你有一定的参考价值。

参考技术A Service 是为一组具有相同功能的Pod提供一个统一的入口地址,并将请求进行负载均衡地分发到各个Pod上。

ClusterIP类型的Service是Kubernetes集群默认的Service, 它只能用于集群内部通信。不能用于外部通信。K8s会为每个Service分配一个虚拟IP,即ClusterIP。这个虚拟IP只能在集群内部访问。

。NodePort类型的Service会在集群内部的所有Node节点打开一个指定的端口。之后所有的流量直接发送到这个端口之后,就会转发的Service去对真实的服务进行访问。

LoadBalancer类型的Service通常和云厂商的LB结合一起使用,用于将集群内部的服务暴露到外网,云厂商的LoadBalancer会给用户分配一个IP,之后通过该IP的流量会转发到你的Service。

Ingress 其实不是Service的一个类型,但是它可以作用于多个Service,作为集群内部服务的入口。Ingress 能做许多不同的事,比如根据不同的路由,将请求转发到不同的Service上等等。

虽然Service解决了Pod的服务发现问题,但不提前知道Service的IP,怎么发现service服务呢?k8s提供了两种方式进行服务发现:

endpoint是k8s集群中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址。service配置selector,endpoint controller才会自动创建对应的endpoint对象;否则,不会生成endpoint对象。
例如,k8s集群中创建一个名为k8s-classic-1113-d3的service,就会生成一个同名的endpoint对象,如下图所示。其中ENDPOINTS就是service关联的pod的ip地址和端口。

endpoint controller是k8s集群控制器的其中一个组件,其功能如下:

kube-proxy负责service的实现,即实现了k8s内部从pod到service和外部从node port到service的访问。
kube-proxy作为一个控制器,作为k8s和Linux kernel Netfilter交互的一个枢纽。监听kubernetes集群Services和Endpoints对象的变化,并根据kube-proxy不同的模式(iptables or ipvs), 对内核设置不同的规则,来实现路由转发。

在Iptables模式下,kube-proxy通过在目标node节点上的Iptables中的NAT表的PREROUTIN和POSTROUTING链中创建一系列的自定义链(这些自定义链主要是”KUBE-SERVICE”链, “KUBE-POSTROUTING”链,每个服务对应的”KUBE-SVC-XXXXXX”链和”KUBE-SEP-XXXX”链),然后通过这些自定义链对流经到该Node的数据包做DNAT和SNAT操作从而实现路由,负载均衡和地址转化。

kube-proxy中,客户端的请求数据包在Iptables规则中具体的匹配过程为:

通过上面的这个设置便实现了基于Iptables实现了负载均衡。但是Iptbles做负载均衡存在一些问题:

为了解决Iptables当前存在的这些问题,华为开源团队的同学为社区贡献了IPVS模式。请参考: https://xigang.github.io/2019/07/21/kubernetes-service/

16Service名称解析ClusterDNS

Service名称解析ClusterDNS
Cluster DNS(CoreDNS)是Kubernetes集群的必备附件,负责为Kubernetes提供名称解析和服务发现
⚫ 每个Service资源对象,在CoreDNS上都会自动生成一个遵循“<service>.<ns>.svc.<zone>”格式的名称
◆ <service>:当前Service对象的名称
◆ <ns>:当前Service对象所属的名称空间
◆ <zone>:当前Kubernetes集群使用的域名后缀,默认为“cluster.local”
⚫ 围绕该名称会生成一些DNS格式的资源记录

CoreDNS会持续监视API Server上的Service资源对象的变动,并实时反映到相关的DNS资源记录中

Pod中各容器默认会在/etc/resolv.conf中,将nameserver指向CoreDNS相关的Service的ClusterIP
⚫ 由kubelet创建Pod时根据指定的配置自动注入
集群只要部署完成,service在网络当中有两个地址被固定征用
kube-dns在kube-system名称空间下会自动被生成
[root@K8s-master01 chapter7]#kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 8d
kube-dns地址是固定的,10.96.0.10是可用地址范围内的第十个地址


这个地址段的第一个地址也被kubernetes固定使用
[root@K8s-master01 chapter7]#kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
ClusterDNS服务的名称:
ClusterDNS服务的名称:kube-dns.kube-system.svc.cluster.local
固定的地址:Cluster Network地址范围内的第10个地址;

ClusterDNS服务会使用标签选择器选择合理的pod数量作为后端的端点,默认ClusterDNS工作为两个pod
[root@K8s-master01 chapter7]#kubectl get pods -n kube-system --show-labels
NAME READY STATUS RESTARTS AGE LABELS
coredns-565d847f94-ql7cb 1/1 Running 0 78m k8s-app=kube-dns,pod-template-hash=565d847f94
coredns-565d847f94-sr27n 1/1 Running 5 (11h ago) 8d k8s-app=kube-dns,pod-template-hash=565d847f94
查看pod所在的地址和节点
[root@K8s-master01 chapter7]#kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-565d847f94-ql7cb 1/1 Running 0 81m 10.244.2.2 k8s-master03 <none> <none>
coredns-565d847f94-sr27n 1/1 Running 5 (11h ago) 8d 10.244.0.12 k8s-master01 <none> <none>
查看service的详细信息
[root@K8s-master01 chapter7]#kubectl describe svc kube-dns -n kube-system
Name: kube-dns
Namespace: kube-system
Labels: k8s-app=kube-dns
kubernetes.io/cluster-service=true
kubernetes.io/name=CoreDNS
Annotations: prometheus.io/port: 9153
prometheus.io/scrape: true
Selector: k8s-app=kube-dns
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.0.10
IPs: 10.96.0.10
Port: dns 53/UDP
TargetPort: 53/UDP
Endpoints: 10.244.0.12:53,10.244.2.2:53
Port: dns-tcp 53/TCP
TargetPort: 53/TCP
Endpoints: 10.244.0.12:53,10.244.2.2:53
Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 10.244.0.12:9153,10.244.2.2:9153
Session Affinity: None
Events: <none>
也可发现其所在的端点ip
Pod中各容器默认会在/etc/resolv.conf中,将nameserver指向CoreDNS相关的Service的ClusterIP
由kubelet创建Pod时根据指定的配置自动注入
[root@K8s-master01 chapter7]#kubectl exec demoapp-55c5f88dcb-6g9k4 -- cat /etc/resolv.conf 
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
客户端对service进行解析
查看service
[root@K8s-master01 ~]#kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
demoapp-svc ClusterIP 10.97.72.1 <none> 80/TCP 5h57m

创建客户端对service进行域名解析
[root@K8s-master01 chapter7]#kubectl run client-$RANDOM --image=ikubernetes/admin-box:v1.2 --restart=Never -it --command -- /bin/bash
If you dont see a command prompt, try pressing enter.
root@client-22289 /# host -t A demoapp-svc

demoapp-svc.default.svc.cluster.local has address 10.97.72.1

对service进行IP解析
root@client-22289 /# host -t PTR 10.97.72.1

1.72.97.10.in-addr.arpa domain name pointer demoapp-svc.default.svc.cluster.local.

对service进行端口解析
root@client-22289 /# host -t SRV _http._tcp.demoapp-svc.default.svc.cluster.local.

_http._tcp.demoapp-svc.default.svc.cluster.local has SRV record 0 100 80 demoapp-svc.default.svc.cluster.local.
pod上的DNS解析策略和名称解析机制
DNS解析策略
1、Default:从运行在的节点继承DNS名称解析相关的配置
如:
[root@K8s-master01 chapter7]#host -t A www.baidu.com
www.baidu.com is an alias for www.a.shifen.com.
www.a.shifen.com has address 220.181.38.150
www.a.shifen.com has address 220.181.38.149
2、ClusterFirst:于集群DNS服务上解析集群域内的名称,其他域名的解析则交由从节点继承而来的上游名称服务器
3、ClusterFirstWithHostNet:专用于在设置了hostNetwork的Pod对象上使用的ClusterFirst策略
4、None:用于忽略Kubernetes集群的默认设定,而仅使用由dnsConfig自定义的配置


DNS名称解析机制
⚫ nameservers <[]string>:DNS名称服务器列表,附加于由dnsPolicy生成的DNS名称服务器之后
⚫ searches <[]string>:DNS名称解析时的搜索域,附加由于dnsPolicy生成的搜索域之后
⚫ options <[]Object>:DNS解析选项列表,同dnsPolicy生成的解析选项合并成最终生效的定义
自定义pod上的DNS解析策略
[root@K8s-master01 chapter7]#cat pod-with-dnspolicy.yaml 
apiVersion: v1
kind: Pod
metadata:
name: pod-with-dnspolicy
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
dnsPolicy: None
dnsConfig:
nameservers:
- 10.96.0.10
- 223.5.5.5
- 223.6.6.6
searches:
- svc.cluster.local
- cluster.local
- ilinux.io
options:
- name: ndots
value: "5"
创建pod
[root@K8s-master01 chapter7]#kubectl apply -f pod-with-dnspolicy.yaml
pod/pod-with-dnspolicy created

查看域名解析
[root@K8s-master01 chapter7]#kubectl exec pod-with-dnspolicy -- cat /etc/resolv.conf
nameserver 10.96.0.10
nameserver 223.5.5.5
nameserver 223.6.6.6
search svc.cluster.local cluster.local ilinux.io
options ndots:5
如何去配置DNS服务
[root@K8s-master01 chapter7]#kubectl get cm -n kube-system
NAME DATA AGE
coredns 1 8d
extension-apiserver-authentication 6 8d
kube-proxy 2 8d
kube-root-ca.crt 1 8d
kubeadm-config 1 8d
kubelet-config 1 8d

把DNS配置文件导出来修改,在用kubectl apply -f <文件名>
[root@K8s-master01 chapter7]#kubectl get cm coredns -o yaml -n kube-system > DNS.yaml
apiVersion: v1
data:
Corefile: |
.:53
errors
health
lameduck 5s

ready
kubernetes cluster.local in-addr.arpa ip6.arpa
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30

prometheus :9153
forward . /etc/resolv.conf
max_concurrent 1000

cache 30
loop
reload
loadbalance

kind: ConfigMap
metadata:
creationTimestamp: "2022-11-07T02:23:24Z"
name: coredns
namespace: kube-system
resourceVersion: "241"
uid: cde90501-030a-465a-979f-d3253c71583f
具体配置方法可互联网搜索

以上是关于Kubernetes Service原理解析的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes Ingress Controller的使用及高可用落地

Kubernetes(k8s)底层网络原理刨析

详解 Kubernetes Pod 的实现原理

Istio入门实战与架构原理——使用Docker Compose搭建Service Mesh

k8s 服务注册与发现Kubernetes内部域名解析原理

k8s 服务注册与发现Kubernetes内部域名解析原理