该文是对于Nginx容器的配置,但非Nginx的容器通过服务名(域名)的方式与其他容器互相访问也是一样的;

在K8s中发布项目之后,项目之间使用nginx调用失败提示no resolver defined to resolve *****-web.****-namespace, client: 10.42.0.1因为使用service名对服务调用的时候,解析不到服务的容器IP,所以请求失败了,整理了一下解决的过程,如何配置可以成功使用nginx对service名进行调用

重点

  • 首先nginx的配置文件中如果使用service.namespace方式访问,就是域名方式,需要再nginx配置resolver寻找解析DNS
  • K8s集群中使用service.namespace访问不到相应的service下的pod,就将service改为无头服务(Headless Services)类型,修改service的yaml文件中spec.clusterIP=None,删除spec.type,然后删除重新创建service,其他调用service.namespace就可以访问service下面代理的pod了

下面详解说明

在这里插入图片描述
本文主要说明集群内各Service之间的调用方法,对于Service的发布、配置等不作过多说明,示例结构、IP、端口等均按照本人遇到的实际情况简化。

示例声明:

一般发布后各Service在一个网段,各Pod在一个网段,如图示例
发布的服务区分内外暴露端口,图中使用In表示内部访问使用端口,Ex表示外部访问端口
各Service有名称,相互访问使用该名称
如果跨命名空间的Service访问还需要Namespace名称

示例结构:

假设在k8s中有如图所示的部署结构
在deploy-namespace的命名空间中有4个服务,部署了4个service分别为service-a、b、c、d
各服务发布后的集群IP为10.4网段
每个service下有若干pod,各pod均为10.3网段
service-a暴露外网端口80,service-b暴露内网端口8080,service-c暴露内网端口9001,service-d暴露内网端口9002

场景:

用户从外网访问主机或节点的IP+80访问到服务A(nginx启动的前台http服务,并代理到服务B)
然后服务A需要依赖服务B(访问B的配置在服务A的nginx中),就需要服务A内部调用服务B
B服务又依赖服务C、D,就需要服务B内部调用服务C、D

特意强调A服务为nginx是因为nginx在使用域名配置代理时,需要额外配置resolver信息,所以如果有nginx的话注意。

如果使用云厂商的服务,则使用LoadBalance类型的Service就行了,LoadBalance本身就会负载到下面的Pod,下面是Kubernetes官方文档对LoadBalance的介绍
在这里插入图片描述

期望效果(看一下是否符合个人所需,再看是否使用下面的方案):

由于有多个Pod,需要负载,不能只选择一个Pod的IP调用
且每次发布IP都会发生变化,没法确定IP,所以一般不会使用Pod IP访问

但是服务B的Pod都会标记到Service-b下面,调用service-b就可以了,然后service会自动负载到服务B的各个pod,开发人员知道服务名和端口就可以直接开发调用了
调用服务使用service名(+namespace名,跨namespace时)就可以了

如图就是,在服务A中使用:service-b.deploy-namespace:8080,就可以访问到服务B

所需服务及配置:

如果有nginx的话在nginx.conf中。增加配置resolver <k8s-dns.ip>;在http, server, location中都可以,按照自己需要

  • k8s-dns.ip查询方式:
kubectl get svc kube-dns -n kube-system
# 也可能是coredns,不知道就使用 kubectl get svc -n kube-system 查询所有,找dns相关的服务

NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.43.0.10   <none>        53/UDP,53/TCP   8h

valid=1s 该配置是nginx缓存dns解析的时间,配置的短一点,因为k8s的pod每次启动都会更新IP,需要及时更新映射
在这里插入图片描述

因为K8s默认策略是所有容器间可以互相通信,service之间隔离,Pod 是非隔离的,所以直接使用service名调用就会出现开头提示的错误,Pod节点无法访问Service的IP。

无头服务(Headless Services)

使用K8s中的无头服务(Headless Services)就可以,无头服务就是Service没有了Cluster IP,所以解析service.namespace时就会直接匹配service后端的多个Pod IP,并却使用默认的轮转策略访问。

**但是要是注意,使用无头服务(Headless Services)时,该服务暴露的端口需要和容器组的暴露端口一致,因为Service没有ip了,不会做路由了,所以就会将请求直接负载到容器组,包括端口信息,所以需要暴露端口一致,也便于维护

无头服务(Headless Services)
有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。

Headless Service 并不会分配 Cluster IP,kube-proxy也不会处理, 而且K8s平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。

“无头(Headless)” 服务(没有Cluster IP)也会以 my-svc.my-namespace.svc.cluster-domain.example 这种名字的形式被指派一个 DNS A 或 AAAA 记录, 具体取决于服务的 IP 协议族。 与普通服务不同,这一记录会被解析成对应服务所选择的 Pod 集合的 IP。 客户端能够使用这组 IP或者使用标准的轮转策略从这组 IP 中进行选择。(CoreDNS的默认loadbalance是一个轮转式 DNS 负载均衡器, 它在应答中随机分配 A、AAAA 和 MX 记录的顺序。比如有多个Pod是轮转式访问的)

修改service的yaml

在这里插入图片描述

删除原来的service

使用更新后的yaml文件创建服务

然后就可以了,再试着调用一下

参考:
https://kubernetes.io/zh/docs/concepts/services-networking/dns-pod-service/
https://kubernetes.io/zh/docs/concepts/services-networking/service/#headless-services
https://kubernetes.io/zh/docs/tasks/administer-cluster/dns-custom-nameservers/#coredns-configmap-options
https://github.com/kubernetes/dns/blob/master/docs/specification.md

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐