一、服务注册
服务注册过程指的是在服务注册表中登记一个服务,以便让其它服务发现。
Kubernetes 使用 DNS 作为服务注册表。为了满足这一需要,每个 Kubernetes 集群都会在 kube-system
命名空间中用 Pod 的形式运行一个 DNS 服务(kube-dns/coredns),通常称之为集群 DNS。
1.1 注册过程
- 1、向API Server用POST方式提交一个新的Service定义
- 2、这个请求需要经过认证、鉴权以及其他的准入策略检查过程之后才会放行
- 3、Service得到一个ClusterIP(虚拟IP地址),并保存到集群数据仓库
- 4、在集群范围内传播Service配置
- 5、集群DNS服务得知该Service的创建,据此创建必要的DNS记录
其中step5是关键环境。集群DNS使用的是CoreDNS,实现了一个控制器,会对API Server进行监听,一旦发现有新建的Service对象,就创建一个从Service名称映射到ClusterIP的域名记录。这样Service就不必自行向DNS进行注册。
DNS 中注册的名称就是 metadata.name
,而 ClusterIP 则由 Kubernetes 自行分配
Service 对象注册到集群 DNS 之中后,就能够被运行在集群中的其它 Pod 发现了
1.2 Endpoint
Service的创建成功并注册到DNS之后,后端会包含一个pod列表,Service对象会把流量分发给这些pod。毫无疑问,这些pod列表需要是最新的。
Service对象有一个Label Selector字段,这个字段是个标签,符合这个标签条件的pod就会被服务纳入到服务的流量负载均衡范围之内。参见下图:
k8s自动为每个Service创建Endpoints对象。Endpoints对象的职责就是保存一个符合Service标签选择器标准的pod列表,这些pod将接收来自Service的流量。
二、服务发现
通过在Kuberneters中创建服务(Service),就可以通过一个单一稳定的 IP 地址访问pod 。在服务整个生命周期内这个地址保持不变。
那么客户端要如何知道服务的IP和端口呢?Kuberneters为客户端提供了发现服务IP和端口的方式
2.1 环境变量
在pod 开始运行的时候,Kuberneters会初始化一系列的环境变量指向现在存在的服务。
通过命令
$ kubectl exec pod-hash env
可以看到
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
REDIS_HA_ANNOUNCE_2_PORT_26379_TCP_PORT=26379
REDIS_HA_ANNOUNCE_0_SERVICE_PORT_SERVER=6379
REDIS_HA_ANNOUNCE_0_PORT_6379_TCP=tcp://10.96.127.200:6379
REDIS_HA_ANNOUNCE_0_PORT_26379_TCP_ADDR=10.96.127.200
REDIS_HA_ANNOUNCE_1_SERVICE_PORT=6379
REDIS_HA_ANNOUNCE_2_PORT_26379_TCP_PROTO=tcp
REDIS_HA_ANNOUNCE_0_PORT=tcp://10.96.127.200:6379
REDIS_HA_ANNOUNCE_0_PORT_6379_TCP_PROTO=tcp
...
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
REDIS_HA_ANNOUNCE_2_SERVICE_HOST=10.96.141.101
MYSQL_SERVICE_HOST=10.107.17.186
可以看到环境变量中有MYSQL_SERVICE_HOST
, REDIS_HA_ANNOUNCE_2_SERVICE_HOST
等HOST信息以及端口信息。服务名称中的横杆被转换为下划线,并且当服务名称用作环境变量名称中的前缀时,所有的字母都是大写的。
2.2 通过DNS发现服务
kube-system命名空间中有一个kube-dns
的pod,这个pod运行DNS服务,在集群中的其他pod都被配置成使用其作为dns(k8s通过修改每个容器中的/etc/resolv.conf文件实现的)
- 注意:pod是否使用内部的DNS服务器是根据pod中spec的dnsPolicy属性来决定的
由于DNS中记录的是服务名称到ClusterIP映射的记录,因此如果想要通过DNS发现目标服务,有一个前提:需要知道目标服务的服务名称