Kubernetes学习目录
1、基础知识
1.1、需求
在传统的系统部署中,服务运行在一个固定的已知的 IP 和端口上,如果一个服务需要调用另外一个服
务,可以通过地址直接调用,但是,在虚拟化或容器话的环境中,以我们的k8s集群为例,如果存在个位数个
service我们可以很快的找到对应的clusterip地址,进而找到指定的资源,虽然ip地址不容易记住,因为
service在创建的时候会为每个clusterip分配一个名称,我们同样可以根据这个名称找到对应的服务。但
是,如果我们的集群中有1000个Service,我们如何找到指定的service呢?
尤其是在k8s集群中,服务实例的启动和销毁是很频繁的,服务地址在动态的变化,所以传统的方式配置
DNS解析记录就不太好实现了。所以针对于这种场景,我们如果需要将请求发送到动态变化的服务实例上,可
以通过一下两个步骤来实现:
服务注册 — 创建服务实例后,主动将当前服务实例的信息,存储到一个集中式的服务管理中心。
服务发现 — 当A服务需要找未知的B服务时,先去服务管理中心查找B服务地址,然后根据该地址找到B服务
1.2、服务注册和发现的解决方案
专用于kubernetes集群中的服务注册和发现的解决方案就是KubeDNS。kubeDNS自从k8s诞生以来,其方案
的具体实现样式前后经历了三代,分别是 SkyDNS、KubeDNS、CoreDNS(目前默认的)。
对于k8s的容器环境来说,之前用的是Docker,那么对于docker本身来说,我们可以基于 手工环境变量 + --link参数方式实现有限的发现功能,所以环境变量也是一种服务发现方案。
所以,对于k8s环境来说,它主要有两种服务发现机制:
DNS解析
环境变量
2、方案解析
2.1、环境变量类型
2.1.1、Kubernetes Service环境变量
Kubernetes为每个Service资源生成包括以下形式的环境变量在内一系列环境变量,在同一名称空间中创建的Pod对象都会自动拥有这些变量:
{SVCNAME}_SERVICE_HOST、{SVCNAME}_SERVICE_PORT
举例:default名称空间,创建名为demoapp的Service,意味着default名称空间下的每个Pod内部会被自动注入
DEMOAPP_SERVICE_HOST:ClusterIP, DEMOAPP_SERVICE_PORT=80
注意:如果先创建pod然后关联到service是不生效的。
2.1.2、Docker Link形式的环境变量
Docker使用--link选项实现容器连接时所设置的环境变量形式,具体使用方式请参考Docker的相关文档。在创建Pod对象时,kubernetes也会把与此形式兼容的一系列环境变量注入到Pod对象中。
由于k8s准备下一个版本禁用dockershim,所以后续的k8s环境中,可能不再支持这种样式了。
2.2、环境变量-实践
2.2.1、创建service环境
cat >service-test.yml<<'EOF'
kind: Service
apiVersion: v1
metadata:
name: service-test
spec:
selector:
app: my-nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
EOF
2.2.2、创建pod对象,通过标签将其添加到service环境
master1 ]# kubectl apply -f service-test.yml
service/service-test created
master1 ]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d17h
service-test ClusterIP 10.102.251.155 <none> 80/TCP 2s
master1 ~]# kubectl create deployment my-nginx --image=192.168.10.33:80/k8s/pod_test:v0.1 --replicas=3
注意:
必须先创建service,后创建deployment,否则的话,无法演示后面的效果
2.2.3、分析环境变量
master1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
my-nginx-7c7dc654f6-7kqwf 1/1 Running 0 30s
my-nginx-7c7dc654f6-dnmnf 1/1 Running 0 30s
my-nginx-7c7dc654f6-qv6mr 1/1 Running 0 30s
master1 ~]# kubectl exec my-nginx-7c7dc654f6-qv6mr -- printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=my-nginx-7c7dc654f6-qv6mr
DEPLOYENV=Production
RELEASE=Stable
PS1=[\u@\h \w]\$
SERVICE_TEST_PORT=tcp://10.102.251.155:80
SERVICE_TEST_PORT_80_TCP_PORT=80
SERVICE_TEST_PORT_80_TCP_ADDR=10.102.251.155
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
SERVICE_TEST_SERVICE_HOST=10.102.251.155
SERVICE_TEST_SERVICE_PORT=80
SERVICE_TEST_PORT_80_TCP=tcp://10.102.251.155:80
SERVICE_TEST_PORT_80_TCP_PROTO=tcp
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
SERVICE_TEST_SERVICE_PORT_HTTP=80
HOME=/root
# 在容器内部,可以直接使用变量名来进行服务的访问,访问环境变量.
[root@my-nginx-7c7dc654f6-qv6mr /]# curl ${SERVICE_TEST_SERVICE_HOST}:${SERVICE_TEST_SERVICE_PORT}
kubernetes pod-test v0.1!! ClientIP: 10.244.3.216, ServerName: my-nginx-7c7dc654f6-7kqwf, ServerIP: 10.244.4.94!
2.2、DNS解析-实践
2.2.1、实现方式
Kubelet会为创建的每一个容器于/etc/resolv.conf配置文件中生成DNS查询客户端依赖到的必要配置,
相关的配置信息源自于kubelet的配置参数,各容器的DNS服务器由clusterDNS参数的值设定,它的取值为
kube-system名称空间中的Service对象kube-dns的ClusterIP,默认为10.96.0.10,而DNS搜索域的
值由clusterDomain参数的值设定,若部署Kubernetes集群时未特别指定,其值将为cluster.local、
svc.cluster.local和NAMESPACENAME.svc.cluster.local,下面的示例取自集群上的一个随机选择的Pod中的容器。
[root@my-nginx-7c7dc654f6-qv6mr /]# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
上述search参数中指定的DNS各搜索域,是以次序指定的几个域名后缀,它们各自的如下所示。
<ns>.svc.<zone>:附带有特定名称空间的域名,例如default.svc.cluster.local;
svc. <zone>:附带了Kubernetes标识Service专用子域svc的域名,例如svc.cluster.local;
<zone>:集群本地域名,例如cluster.local。
ndots:5,表示:如果手工查询时候给的域名包含的点“.”,不到5个,那么进行DNS查找,将使用非完全限定名称
即 <手工输入域名> 或者 <手工输入域名>.<search 部分给定的域名后缀>
如果你查询的域名包含点数大于等于5,那么DNS查询,默认会使用绝对域名进行查询。
即 <手工输入域名>
2.2.3、基于DNS的服务发现-3个类型的DNS资源记录
基于DNS的服务发现,对于每个Service对象,都会具有以下3个类型的DNS资源记录。
1)、根据ClusterIP的地址类型,为IPv4生成固定格式的 A记录,为IPv6生成AAAA记录;
<service>.<ns>.svc.<zone>. <ttl> IN A <cluster-ip>
<service>.<ns>.svc.<zone>. <ttl> IN AAAA <cluster-ip>
举例:
demoapp,
demoapp.default.svc.cluster.local.
注意:
cluster.local 是我们在初始化k8s集群中,自己通过dnsDomain属性定制的。
2)、为每个定义了名称的端口生成一个SRV记录,未命名的端口号则不具有该记录;
_<port>._<proto>.<service>.<ns>.svc.<zone>. <ttl> IN SRV <weight>
<priority> <port-number> <service>.<ns>.svc.<zone>.
3)、对于每个给定的A记录或AAAA记录都要生成PTR记录,它们各自的格式如下所示:
<d>.<c>.<b>.<a>.in-addr.arpa. <ttl> IN PTR <service>.<ns>.svc.<zone>.
h4.h3.h2.h1.g4.g3.g2.g1.f4.f3.f2.f1.e4.e3.e2.e1.d4.d3.d2.d1.c4.c3.c2.c1.b4.b3.b2
.b1.a4.a3.a2.a1.ip6.arpa <ttl> IN PTR <service>.<ns>.svc.<zone>.
例如,前面在default名称空间中创建Service对象demoapp-svc的地址为10.97.72.1,且为TCP协议的
80端口取名http,对于默认的cluster.local域名来说,此它会拥有如下3个DNS资源记录。
A记录:demoapp-svc.default.svc.cluster.local. 30 IN A 10.97.72.1;
SRV记录:_http._tcp.demoapp-svc.default.svc.cluster.local. 30 IN SRV 0 100 80
demoapp-svc.default.svc.cluster.local.
PTR记录:1.72.97.10.in-addr.arpa. 30 IN PTR demoappsvc.default.svc.cluster.local.
2.2.4、实践
master1 ~]# kubectl -n kube-system describe svc kube-dns
...
Port: dns 53/UDP
TargetPort: 53/UDP
Endpoints: 10.244.0.12:53,10.244.1.6:53
Port: dns-tcp 53/TCP
TargetPort: 53/TCP
Endpoints: 10.244.0.12:53,10.244.1.6:53
Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 10.244.0.12:9153,10.244.1.6:9153
...
master1 ~]# kubectl -n kube-system get pod -l k8s-app=kube-dns -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-75c9cf9bd7-qcwcf 1/1 Running 0 6d17h 10.244.1.6 master2 <none> <none>
coredns-75c9cf9bd7-sdsq5 1/1 Running 0 6d17h 10.244.0.12 master1 <none> <none>
------
# pod里面查看相关的配置信息
[root@my-nginx-7c7dc654f6-qv6mr /]# cat /etc/hosts
# Kubernetes-managed hosts file.
...
10.244.3.216 my-nginx-7c7dc654f6-qv6mr
[root@my-nginx-7c7dc654f6-qv6mr /]# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
[root@my-nginx-7c7dc654f6-qv6mr /]# curl service-test
kubernetes pod-test v0.1!! ClientIP: 10.244.3.1, ServerName: my-nginx-7c7dc654f6-qv6mr, ServerIP: 10.244.3.216!
[root@my-nginx-7c7dc654f6-qv6mr /]# curl service-test.default.svc.cluster.local
kubernetes pod-test v0.1!! ClientIP: 10.244.3.216, ServerName: my-nginx-7c7dc654f6-dnmnf, ServerIP: 10.244.3.215!
[root@my-nginx-7c7dc654f6-qv6mr /]# curl service-test.default.svc.cluster.local.
kubernetes pod-test v0.1!! ClientIP: 10.244.3.216, ServerName: my-nginx-7c7dc654f6-7kqwf, ServerIP: 10.244.4.94!
注意:
一旦我们将service删除后,就无法正常删除了,
3、DNS记录解析-实践
3.1、正向解析记录
master1 ~]# kubectl exec -it my-nginx-7c7dc654f6-qv6mr -- /bin/sh
[root@my-nginx-7c7dc654f6-qv6mr /]# nslookup
> service-test.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: service-test.default.svc.cluster.local
Address: 10.102.251.155
> kube-dns.kube-system.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kube-dns.kube-system.svc.cluster.local
Address: 10.96.0.10
3.2、反向解析记录
# 反向解析
[root@master1 ~]# kubectl exec -it my-nginx-7c7dc654f6-qv6mr -- /bin/sh
[root@my-nginx-7c7dc654f6-qv6mr /]# nslookup
> 10.244.3.215
215.3.244.10.in-addr.arpa name = 10-244-3-215.service-test.default.svc.cluster.local.
> 10.244.3.216
216.3.244.10.in-addr.arpa name = 10-244-3-216.service-test.default.svc.cluster.local.
> 10.244.4.94
94.4.244.10.in-addr.arpa name = 10-244-4-94.service-test.default.svc.cluster.local.
3.3、查询域名的A记录
# 查询域名的A记录,对应SVC IP地址
[root@my-nginx-7c7dc654f6-qv6mr /]# nslookup -query=A service-test.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: service-test.default.svc.cluster.local
Address: 10.102.251.155
master2 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d18h
service-test ClusterIP 10.102.251.155 <none> 80/TCP 44m
4、CoreDNS配置
4.1、配置解析
4.1.1、查询configmap的coredns
# coredns的配置依然是存放在 configmap
master2 ~]# kubectl -n kube-system get cm | grep coredns
coredns 1 6d18h
4.1.2、查看coredns配置
# 查询CoreDNS配置
master2 ~]# kubectl -n kube-system describe configmap coredns
...
====
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 # dns记录负载
}
对于我们之前所说的企业级的dns解决方案,我们可以通过 forward 来实现,格式如下
forward <域名> <转发后的地址> { # 转发配置,如果集群内部无法解析
的话,交由宿主机文件解析
max_concurrent 最大连接配置
except 排除的域名
}
注意: 如果仅仅对某个域名进行转发的话,只需要将 <域名> 部分设置为指定的域名即可。
生产中不推荐直接将 "." 的转发地址使用公网的dns地址,推荐在当前主机
的/etc/resolv.conf中配置外网,实现间接的效果
# 添加dns解析
hosts {
192.168.8.100 www.example.com
fallthrough
}
4.2、实践:不使用默认的转发策略,使用自定义的转发策略
4.2.1、编辑coredns配置文件
master1 ~]# kubectl edit configmap coredns -n kube-system
...
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
except www.baidu.com.
}
hosts {
192.168.10.33 harbor.test.com
fallthrough
}
cache 30
...
注意:
多个dns地址间用空格隔开
排除的域名最好在末尾添加 “.”,对于之前的旧版本来说可能会出现无法保存的现象。
4.2.2、同步dns的配置信息
master1 ~]# kubectl -n kube-system delete pod -l k8s-app=kube-dns
4.2.3、测试自定义DNS解析是否正常
# 删除svc,重新创建
master1 ]# kubectl delete service service-test
cat >service-test.yml<<'EOF'
kind: Service
apiVersion: v1
metadata:
name: service-test
spec:
selector:
app: my-nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
EOF
kubectl apply -f service-test.yml
kubectl create deployment my-nginx --image=192.168.10.33:80/k8s/pod_test:v0.1 --replicas=3
master1 ]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d19h
service-test ClusterIP 10.104.128.244 <none> 80/TCP 4s
[root@master1 service]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
my-nginx 3/3 3 3 7s
master1 ]# kubectl get pod
NAME READY STATUS RESTARTS AGE
my-nginx-768865db6b-fbpk9 1/1 Running 0 13s
my-nginx-768865db6b-lftcm 1/1 Running 0 13s
my-nginx-768865db6b-n6mcb 1/1 Running 0 13s
# 验证域名配置是否生效
[root@my-nginx-768865db6b-fbpk9 /]# ping www.baidu.com
ping: bad address 'www.baidu.com'
[root@my-nginx-768865db6b-fbpk9 /]# ping harbor.test.com
PING harbor.test.com (192.168.10.33): 56 data bytes
64 bytes from 192.168.10.33: seq=0 ttl=63 time=1.279 ms
5、会话粘滞
5.1、需求
kubernetes的Service功能可以通过多种方式将pod对象提供的服务对外开放,但是当pod多的时候,
用户访问service的时候,service默认是按照轮训的情况进行转发,如果我们的用户请求由一定的会话要
求,即希望同一个客户能访问一个pod的时候,我们可以使用service的affinity机制来实现,它能将同一
个客户端的请求始终转发至同一个后端Pod对象,它是由kube-proxy的ipvs机制来实现的。
默认情况下,service所提供的会话粘性效果默认在10800s(3小时)后会重新调度,而且仅能基于客户端IP进行识别,调度粒度较粗,不推荐使用
5.2、属性解析
5.2.1、属性信息
spec.sessionAffinity,定义粘性会话的类型,可为 None 和 ClientIP
spec.sessionAffinityConfig.clientIP,配置会话保持时长,默认10800s 范围 1-86400
5.2.2、配置样式
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
5.3、默认没有使用会话粘滞
5.3.1、删除原来的配置
# 删除原来的配置
kubectl delete deployments.apps my-nginx
kubectl delete service service-test
5.3.2、重新创建service和deployment
# 重新创建service和 deployment
cat >service-test.yml<<'EOF'
kind: Service
apiVersion: v1
metadata:
name: service-test
spec:
selector:
app: my-nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
EOF
kubectl apply -f service-test.yml
kubectl create deployment my-nginx --image=192.168.10.33:80/k8s/pod_test:v0.1 --replicas=3
5.3.3、访问测试
# 可以看到,每次都是不一样的IP地址
master1 ]# for i in {1..3}; do curl 10.104.82.193; done
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: my-nginx-5fc6bb8b-7z4fk, ServerIP: 10.244.3.223!
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: my-nginx-5fc6bb8b-6mrn2, ServerIP: 10.244.3.222!
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: my-nginx-5fc6bb8b-45bdt, ServerIP: 10.244.4.98!
5.4、修改会话配置-实现会话粘滞
5.4.1、定义资源配置清单
cat >nginx-service.yml<<'EOF'
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: my-nginx
sessionAffinity: ClientIP
EOF
5.4.2、应用资源配置清单
master1 ]# kubectl apply -f nginx-service.yml
service/nginx-service created
master1 ]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d19h
nginx-service LoadBalancer 10.101.186.100 <pending> 80:30140/TCP 5s
5.4.3、验证是否生效
master1 ]# kubectl apply -f nginx-service.yml
service/nginx-service created
master1 ]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d19h
nginx-service ClusterIP 10.101.164.147 <none> 80/TCP 8s
master1 ]# for i in {1..3};do curl 10.101.164.147;done
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: my-nginx-5fc6bb8b-45bdt, ServerIP: 10.244.4.98!
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: my-nginx-5fc6bb8b-45bdt, ServerIP: 10.244.4.98!
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: my-nginx-5fc6bb8b-45bdt, ServerIP: 10.244.4.98!
6、Headless Service-无头服务
6.1、需求
到现在为止,我们所遇到的用户访问,用户将请求交给service对象的流程是,kube-proxy其实是将
用户访问的域名解析给了service对象所对应的cluster_ip,然后再由cluster_ip将请求转发给后端的
pod,然后在交给pod内部的容器,这样一个请求经过了两层转发才到容器里面的服务,流程有些繁琐。
目前我们集群的资源调度主要是针对的是无状态的服务,但是对于一些特定场景状态服务,我们虽然可以
基于会话粘滞来实现,但是毕竟需要经过两层跳转,如果转发量太大的话,效果不是太好。
对于某些特殊的负载均衡场景,既然pod有专门的ip地址,那么我可以无需经过cluster_ip,直接定向
到Pod_ip就行了,那么和普通Service相比,这种没有配置ClusterIP项的场景,我们称之为Headless
Service。
6.2、简介
无头服务场景下,k8s会将一个集群内部的所有成员提供唯一的DNS域名来作为每个成员的网络标识,集
群内部成员之间使用域名通信,这个时候,就特别依赖service的selector属性配置了。
无头服务管理的域名是如下的格式:
$(service_name).$(k8s_namespace).svc.cluster.local。
dns解析记录
A记录
<a>-<b>-<c>-<d>.<service>.<ns>.svc.<zone> A PodIP
PodIP的PTR反解析记录
<d>.<c>.<b>.<a>.in-addr.arpa IN PTR <hostname>.<service>.<ns>.svc.<zone>
关键点:
svc_name的解析结果从常规Service的ClusterIP,转为各个Pod的IP地址;
反解,则从常规的clusterip解析为service name,转为从podip到hostname, <a>-<b>-<c>-<d>.<service>.<ns>.svc.<zone>
<hostname>指的是a-b-c-d格式,而非Pod自己的主机名;
6.3、实践
6.3.1、方法1:命令行的创建
master1 ]# kubectl create service clusterip service-headless-cmd --clusterip="None"
service/service-headless created
master1 ]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d19h
service-headless-cmd ClusterIP None <none> <none> 3s
6.3.2、方法2:资源配置清单的创建
cat >service-headless.yml<<'EOF'
apiVersion: v1
kind: Service
metadata:
name: service-headless
spec:
selector:
app: my-nginx
clusterIP: "None"
EOF
kubectl apply -f service-headless.yml
master1 ]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d19h
service-headless ClusterIP None <none> <none> 3s
6.3.3、创建deployment
kubectl create deployment my-nginx --image=192.168.10.33:80/k8s/pod_test:v0.1 --replicas=3
6.3.4、查询定义的service详细信息
master1 ]# kubectl describe service service-headless
Name: service-headless
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=my-nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Session Affinity: None
Events: <none>
master1 ]# kubectl describe ep service-headless
Name: service-headless
Namespace: default
Labels: service.kubernetes.io/headless=
Annotations: endpoints.kubernetes.io/last-change-trigger-time: 2023-03-23T07:53:08Z
Subsets:
Addresses: 10.244.3.224,10.244.3.225,10.244.4.99
NotReadyAddresses: <none>
注意:
有可能因为dns的原因,这里面的无头服务可能无法显示对应的subnets相关的信息,但是不影响无头服
务的正常使用可以正常的进入到pod内部进行测试.
6.3.5、验证是否生效
master1 ]# kubectl exec -it my-nginx-b5fb867f7-dcsr6 -- /bin/sh
[root@my-nginx-b5fb867f7-dcsr6 /]# nslookup 10.244.4.99
99.4.244.10.in-addr.arpa name = 10-244-4-99.service-headless.default.svc.cluster.local.
master1 ]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-nginx-b5fb867f7-dcsr6 1/1 Running 0 107m 10.244.4.99 node2 <none> <none>
my-nginx-b5fb867f7-mkp2h 1/1 Running 0 107m 10.244.3.224 node1 <none> <none>
my-nginx-b5fb867f7-t9s6t 1/1 Running 0 107m 10.244.3.225 node1 <none> <none>
[root@my-nginx-b5fb867f7-dcsr6 /]# nslookup service-headless.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: service-headless.default.svc.cluster.local
Address: 10.244.3.225
Name: service-headless.default.svc.cluster.local
Address: 10.244.4.99
Name: service-headless.default.svc.cluster.local
Address: 10.244.3.224
结总:
从上面解析结果发现,解析出来的是pod的三个IP地址,说明headless生效,,不是通过ClusterIp中转,直接把请求直接转发到pod地址处理。
6.3.6、注意事项
headless service 在statefulSet资源对象中会重点使用
headless service是一个四层调度,因为iptables/ipvs都是四层的,所以我们如果要建立一个https
服务的话,每一个服务都必须配置一个https的主机,因为四层调度是无法卸载https回话的。
7、Service是如何做到服务发现的
7.1、查询
7.1.1、查询svc资源Endpoints信息
]# kubectl describe svc deployment-service | grep -i Endpoints
Endpoints: 10.244.3.85:80,10.244.3.86:80,10.244.4.120:80 + 1 more...
# 发现Endpoint资源对象,关于pod的IP地址
7.1.2、查询Endpoints资源对象
]# kubectl get endpoints deployment-service
NAME ENDPOINTS AGE
deployment-service 10.244.3.85:80,10.244.3.86:80,10.244.4.120:80 + 1 more... 5m47s
可以查询得到:Kubernetes正是通过Endpoints监控到Pod的IP,从而让Service能够发现Pod。
7.2、Endpoints、svc、pod关系图
如果删除一个pod,deployment控制器会重新创建pod,获取到新的ip地址,endpoints也会相应更新IP地址信息。
7.3、服务发现的原理
7.3.1、Pod X访问Service流程图
7.3.2、pod、service流程说明
在Kubernetes集群架构中介绍过Node节点上的kube-proxy,实际上Service相关的事情都由节点上的kube-proxy处理。
在Service创建时Kubernetes会分配IP给Service,同时通过API Server通知所有kube-proxy有新Service创建了,
kube-proxy收到通知后通过iptables记录Service和IP/端口对的关系,从而让Service在节点上可以被查询到。
上图是一个实际访问Service的图示,Pod X访问Service(10.247.124.252:8080),在往外发数据包时,在节点上根据iptables规则目的IP:Port被随机替换为Pod1的IP:Port,从而通过Service访问到实际的Pod。
除了记录Service和IP/端口对的关系,kube-proxy还会监控Service和Endpoint的变化,从而保证Pod重建后仍然能通过Service访问到Pod。