k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题

网易公开课,开课啦!

主讲内容:docker/kubernetes 云原生技术,大数据架构,分布式微服务,自动化测试、运维。

7月1号-7月29号 8折优惠!!!
7月1号-7月29号 8折优惠!!!
7月1号-7月29号 8折优惠!!!


全栈工程师开发手册 (作者:栾鹏)
架构系列文章

验证一个域名的ip地址可以使用

nslookup  xx.xx..xx

在kubernets中不同命名空间的服务相互访问

涉及到的是Pod和Service之间的相互访问,主要格式如下:

    访问Pod:(注意下面不是直接pod的ip,而是由pod的ip组成的字符串)
    {pod-ip}.{namespace}.pod.cluster.local
  例如某pod的ip为  1.2.3.4,在命名空间default与DNS名称cluster.local将有一个域名:1-2-3-4.default.pod.cluster.local。

    {hostname}.{subdomain}.{namespace}.svc.cluster.local
    subdomain是在创建pod设定的属性,和hostname可以一起设置
    
    访问StatefulSet:
    {pod-name}.{service-name}.{namespace}.svc.cluster.local
    可以进入到pod中查看/etc/hosts
    
    访问Service:
    {service-name}.{namespace}.svc.cluster.local

当你创建一个Service时,Kubernetes会自动创建一个形如..svc.cluster.local的DNS项。如果集群中另一个服务调用这个服务时,仅仅指定了,那么Kubernetes会使用调用方所在的Namespace将补全。因此如果调用方和被调用方不处于同一个Namespace,你必须使用包含Namespace的service name

修改pod的hostname和subdomain

可以在 Pod /Deployment中指定pod的 hostname 和 subdomain:,例如:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: busybox-subdomain
  containers:
  name: busybox
  - image: busybox
    command:
    - sleep
    - "3600"

因为pod的访问域名是hostname.custom-subdomain.default.svc.cluster.local

所以该 Pod 的域名是 busybox-1.busybox-subdomain.default.svc.cluster.local。

使用 HostAliases 向 Pod /etc/hosts 文件添加条目

当 DNS 配置以及其它选项不合理的时候,通过向 Pod 的 /etc/hosts 文件中添加条目,可以在 Pod 级别覆盖对主机名的解析。在 1.7 版本,用户可以通过 PodSpec 的 HostAliases 字段来添加这些自定义的条目。

建议通过使用 HostAliases 来进行修改,因为该文件由 Kubelet 管理,并且可以在 Pod 创建/重启过程中被重写。

默认 hosts 文件内容

让我们从一个 Nginx Pod 开始,给该 Pod 分配一个 IP:

$ kubectl get pods --output=wide
NAME     READY     STATUS    RESTARTS   AGE    IP           NODE
nginx    1/1       Running   0          13s    10.200.0.4   worker0

默认,hosts 文件只包含 ipv4 和 ipv6 的样板内容,像 localhost 和主机名称。

通过 HostAliases 增加额外的条目

除了默认的样板内容,我们可以向 hosts 文件添加额外的条目,将 foo.local、 bar.local 解析为127.0.0.1,将 foo.remote、 bar.remote 解析为 10.1.2.3,我们可以在 .spec.hostAliases 下为 Pod 添加 HostAliases。

hostaliases-pod.yaml docs/concepts/services-networking  Copy hostaliases-pod.yaml to clipboard
apiVersion: v1
kind: Pod
metadata:
  name: hostaliases-pod
spec:
  hostAliases:
  - ip: "127.0.0.1"
    hostnames:
    - "foo.local"
    - "bar.local"
  - ip: "10.1.2.3"
    hostnames:
    - "foo.remote"
    - "bar.remote"
  containers:
  - name: cat-hosts
    image: busybox
    command:
    - cat
    args:
    - "/etc/hosts"

hosts 文件的内容看起来类似如下这样:

$ kubectl logs hostaliases-pod
# Kubernetes-managed hosts file.
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
fe00::0	ip6-mcastprefix
fe00::1	ip6-allnodes
fe00::2	ip6-allrouters
10.200.0.4	hostaliases-pod
127.0.0.1	foo.local
127.0.0.1	bar.local
10.1.2.3	foo.remote
10.1.2.3	bar.remote

在最下面额外添加了一些条目。

限制

在 1.7 版本,如果 Pod 启用 hostNetwork,那么将不能使用这个特性,因为 kubelet 只管理非 hostNetwork 类型 Pod 的 hosts 文件。目前正在讨论要改变这个情况。

为什么 Kubelet 管理 hosts文件?

kubelet 管理 Pod 中每个容器的 hosts 文件,避免 Docker 在容器已经启动之后去 修改 该文件。

因为该文件是托管性质的文件,无论容器重启或 Pod 重新调度,用户修改该 hosts 文件的任何内容,都会在 Kubelet 重新安装后被覆盖。因此,不建议修改该文件的内容。

参考:https://kubernetes.io/zh/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/

Pod 之间是如何找到彼此呢 - DNS Service Discovery

介绍 DNS 是什么 ?

DNS,全名为 Domain Name System。DNS 会有一张表格,记录每个 domain name 相对应的 IP 位址。如此,我们不再需要去记录该服务的 IP address,而是可以透过该服务的域名来连接到该服务。以 www.google.com.tw 为例,当我们在浏览器输入 www.google.com.tw 时,DNS会帮我们找到该域名相对应的 IP,并连接到该服务.

如果想知道某个特定的域名相对应的 IP 位址,可以在终端机输入 host 指令,

在这里插入图片描述

介绍 Kubernetes 內部插件 kube-dns

而 Kubernetes 本身提供了 DNS 的套件,kube-dns。 kube-dns 帮助在同一个 Kubernetes Cluster 中的所有 Pods ,都能透过 Service 的名称找到彼此。透过 kubectl get 指令,会发现 kube-dns 也是一个在 Cluster 中运行的服务,一旦 Kubernetes Cluster 被建立后,便会自动运行。
k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题_第1张图片

而 kube-dns 的相关设定档则放是放在 master node 的 /etc/kubernetes/addons 资料夹底下,以 minikube 为例,minikube 运行的 VM 本身就是 master node,所以我们先透过 minikube ssh 指令登入,
k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题_第2张图片

在 /etc/kubernetes/addons 资料夹底下,除了可以看到 kube-dns 的相关设定档外,也可以看到 Kubernetes 其他套件的设定档。

kube-dns 如何运作

如上图我们可以看到 kube-dns 是运行在 Kubernetes Cluster 的一个 Pod,而这个 kube-dns-86f6f55dd5-cht2h Pod,也有一个相对应的 Service 物件。
在这里插入图片描述

Kubernetes 在每一个 Pod 创建时,都会在该 Pod 的 /etc/resolve.conf 档案中,自动加入 kube-dns service 的 domain name 与相对应的 IP 位址。因此 其他 Pods 可以透过名称为 kube-dns 的 Service 物件,找到正在运行的 kube-dns,以下图为例:
在这里插入图片描述
我们在 Kubernetes Cluster 跑起 alpine Pod,并 ssh 进到 alpine 的 shell,用 cat 指令查看 /etc/resolve.conf 内容,

若是与上上图比对,会发现 /etc/resolve.conf 中的 nameserver 指向的 IP 位置,就是 kube-dns 的 Service。或者是dnsmasq的service

配置Kubernetes DNS服务kube-dns

DNS服务有很多中方式, 官方推荐安装的是kube-dns, 我们这里先介绍这个. 如果你的k8s上dns服务不是使用这个插件进行管理的,可以跳过.

kube-dns是Kubernetes中的一个内置插件,目前作为一个独立的开源项目维护,见https://github.com/kubernetes/dns。

前提要求

Kubernetes 1.6 及以上版本。
集群必须使用 kube-dns 插件进行配置。

kube-dns 介绍

从 Kubernetes v1.3 版本开始,使用 [cluster add-on 插件管理器回自动启动内置的 DNS。

Kubernetes DNS pod 中包括 3 个容器:

  • kubedns:kubedns 进程监视 Kubernetes master 中的 Service 和 Endpoint 的变化,并维护内存查找结构来服务DNS请求。
  • dnsmasq:dnsmasq 容器添加 DNS 缓存以提高性能。
  • sidecar:sidecar 容器在执行双重健康检查(针对 dnsmasq 和 kubedns)时提供单个健康检查端点(监听在10054端口)。

k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题_第3张图片

Kube-DNS以Pod的形式部署到kubernetes集群系统;
Kube-DNS对SkyDNS进行封装优化,由4个容器变成3个;
kubedns容器:基于skydns实现;监视k8s Service资源并更新DNS记录;替换etcd,使用TreeCache数据结构保存DNS记录并实现SkyDNS的Backend接口;接入SkyDNS,对dnsmasq提供DNS查询服务;
dnsmasq容器:为集群提供DNS查询服务,即简易的dns server;设置kubedns为upstream;提供DNS缓存,降低kubedns负载,提高性能;
sidecar容器:监控健康模块,同时向外暴露metrics记录;定期检查kubedns和dnsmasq的健康状态;为k8s活性检测提供HTTP API。

上面的DNS pod 具有静态 IP 并作为 Kubernetes 服务暴露出来。该静态 IP 分配后,kubelet 会将使用 --cluster-dns = 标志配置的 DNS 传递给3个容器的每个容器。

DNS 名称也需要域名。本地域可以使用标志 --cluster-domain = 在 kubelet 中配置。

Kubernetes集群DNS服务器基于 SkyDNS 库。它支持正向查找(A 记录),服务查找(SRV 记录)和反向 IP 地址查找(PTR 记录)

kube-dns 支持的 DNS 格式

kube-dns 将分别为 service 和 pod 生成不同格式的 DNS 记录。

Service

  • A记录:生成my-svc.my-namespace.svc.cluster.local域名,解析成 IP 地址,分为两种情况:
    • 普通 Service:解析成 ClusterIP
    • Headless Service:解析为指定 Pod 的 IP 列表
  • SRV记录:为命名的端口(普通 Service 或 Headless Service)生成 _my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local 的域名

Pod

  • A记录:生成域名 pod-ip.my-namespace.pod.cluster.local

继承节点的 DNS

运行 Pod 时,kubelet 将预先配置集群 DNS 服务器到 Pod 中,并搜索节点自己的 DNS 设置路径。如果节点能够解析特定于较大环境的 DNS 名称,那么 Pod 应该也能够解析。请参阅下面的已知问题以了解警告。

自定义pod中的dns服务器

如果您不想要这个,或者您想要为 Pod 设置不同的 DNS 配置,您可以给 kubelet 指定 --resolv-conf 标志。将该值设置为 “” 意味着 Pod 不继承 DNS。将其设置为有效的文件路径意味着 kubelet 将使用此文件而不是 /etc/resolv.conf 用于 DNS 继承。

配置存根域和上游 DNS 服务器

通过为 kube-dns (kube-system:kube-dns)提供一个 ConfigMap,集群管理员能够指定自定义存根域和上游 nameserver。

例如,下面的 ConfigMap 建立了一个 DNS 配置,它具有一个单独的存根域和两个上游 nameserver:

apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-dns
  namespace: kube-system
data:
  stubDomains: |
    {“acme.local”: [“1.2.3.4”]}
  upstreamNameservers: |
    [“8.8.8.8”, “8.8.4.4”]

如上面指定的那样,带有“.acme.local”后缀的 DNS 请求被转发到 1.2.3.4 处监听的 DNS。 “8.8.8.8”, “8.8.4.4”(这两个ip为Google Public DNS) 为上游查询提供服务。

ConfigMap 选项

kube-dns kube-system:kube-dns ConfigMap 的选项如下所示:

字段 格式 描述
stubDomains(可选) 使用 DNS 后缀 key 的 JSON map(例如 “acme.local”),以及 DNS IP 的 JSON 数组作为 value。 目标 nameserver 可能是一个 Kubernetes Service。例如,可以运行自己的 dnsmasq 副本,将 DNS 名字暴露到 ClusterDNS namespace 中。
upstreamNameservers(可选) DNS IP 的 JSON 数组。 注意:如果指定,则指定的值会替换掉被默认从节点的 /etc/resolv.conf 中获取到的 nameserver。限制:最多可以指定三个上游 nameserver。

注意,集群管理员不希望覆盖节点的上游 nameserver,所以他们不会指定可选的 upstreamNameservers 字段。

下表描述了如何将具有特定域名的查询映射到其目标DNS服务器:

域名 响应查询的服务器
kubernetes.default.svc.cluster.local kube-dns
foo.acme.local 自定义 DNS (1.2.3.4)
widget.com 上游 DNS (8.8.8.8 或 8.8.4.4)

对 Pod 的影响

Kubernetes 目前在 Pod 定义中支持两个 DNS 策略:Default 和 ClusterFirst,dnsPolicy 默认为 ClusterFirst。如果将 dnsPolicy 设置为 Default,域名解析配置则完全从 Pod 所在的节点(/etc/resolv.conf)继承而来。

k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题_第4张图片

如果包含自定义DNS,则逻辑图为

k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题_第5张图片

自定义的上游名称服务器和存根域不会影响那些将自己的 dnsPolicy 设置为 Default 或者 None 的 Pod。

如果 Pod 的 dnsPolicy 设置为 “ClusterFirst”,则其名称解析将按其他方式处理,具体取决于存根域和上游 DNS 服务器的配置。

未进行自定义配置:没有匹配上配置的集群域名后缀的任何请求,例如 “www.kubernetes.io”,将会被转发到继承自节点的上游 nameserver。

进行自定义配置:如果配置了存根域和上游 DNS 服务器(和在 前面例子 配置的一样),DNS 查询将根据下面的流程进行路由:

  • 查询首先被发送到 kube-dns 中的 DNS 缓存层。

  • 从缓存层,检查请求的后缀,并转发到合适的 DNS 上,基于如下的示例:

    • 具有集群后缀的名字(例如 “.cluster.local”):请求被发送到 kube-dns。
    • 具有存根域后缀的名字(例如 “.acme.local”):请求被发送到配置的自定义 DNS 解析器(例如:监听在 1.2.3.4)。
    • 不具有能匹配上后缀的名字(例如 “widget.com”):请求被转发到上游 DNS(例如:Google 公共 DNS 服务器,8.8.8.8 和 8.8.4.4)。

k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题_第6张图片

使用dnsmasq自定义DNS服务器,并添加自己的记录

上面的教程都是配置dns服务器的地址, 我们也可以自己来建一个dns服务器,并添加记录,然后将自定义的dns服务器添加为k8s的上游dns服务器.

dnsmasq的部署参考:https://blog.csdn.net/luanpeng825485697/article/details/84139310

dnsmasq的解析流程

dnsmasq先去解析hosts文件, 再去解析/etc/dnsmasq.d/下的*.conf文件,并且这些文件的优先级要高于dnsmasq.conf,我们自定义的resolv.dnsmasq.conf中的DNS也被称为上游DNS,这是最后去查询解析的;

如果不想用hosts文件做解析,我们可以在/etc/dnsmasq.conf中加入no-hosts这条语句,这样的话就直接查询上游DNS了,如果我们不想做上游查询,就是不想做正常的解析,我们可以加入no-reslov这条语句。

dnsmasq.conf文件中的配置含义参考: http://blog.51cto.com/longlei/2065967

dnsmasq的参数及常用设置说明

编辑 dnsmasq 的配置文件 /etc/dnsmasq.conf 。这个文件包含大量的选项注释。

(1)dnsmasq经常修改的比较重要参数说明

具体参数 参数说明
resolv-file 定义dnsmasq从哪里获取上游DNS服务器的地址, 默认从/etc/resolv.conf获取。
strict-order 表示严格按照resolv-file文件中的顺序从上到下进行DNS解析,直到第一个解析成功为止。
listen-address 定义dnsmasq监听的地址,默认是监控本机的所有网卡上。
address 启用泛域名解析,即自定义解析a记录,例如:address=/long.com/192.168.115.10 访问long.com时的所有域名都会被解析成192.168.115.10
bogus-nxdomain 对于任何被解析到此 IP 的域名,将响应 NXDOMAIN 使其解析失效,可以多次指定. 通常用于对于访问不存在的域名,禁止其跳转到运营商的广告站点
server 指定使用哪个DNS服务器进行解析,对于不同的网站可以使用不同的域名对应解析。例如:server=/google.com/8.8.8.8 #表示对于google的服务,使用谷歌的DNS解析。

(2)查看配置文件语法是否正确,可执行下列命令

[root@localhost ~]# dnsmasq --test
dnsmasq: syntax check OK.

(3)DNS 缓存设置

要在单台电脑上以守护进程方式启动dnsmasq做DNS缓存服务器,编辑/etc/dnsmasq.conf,添加监听地址:

listen-address=127.0.0.1

如果用此主机为局域网提供默认 DNS,请用为该主机绑定固定 IP 地址,设置:

listen-address=192.168.x.x

这种情况建议配置静态IP

多个ip地址设置:

listen-address=127.0.0.1,192.168.x.x

(4)三个以上域名服务器
Linux 处理 DNS 请求时有个限制,在 resolv.conf 中最多只能配置三个域名服务器(nameserver)。作为一种变通方法,可以在 resolv.conf 文件中只保留 localhost 作为域名服务器,然后为外部域名服务器另外创建 resolv-file 文件。

也就是/etc/resolv.conf内容为

nameserver 127.0.0.1

首先,为 dnsmasq 新建一个域名解析文件:

[root@localhost ~]# vim /etc/resolv.dnsmasq.conf
# Google's nameservers, for example
nameserver 8.8.8.8
nameserver 8.8.4.4

然后编辑 /etc/dnsmasq.conf 让 dnsmasq 使用新创建的域名解析文件:

[root@localhost ~]# vim  /etc/dnsmasq.conf
...
resolv-file=/etc/resolv.dnsmasq.conf

增加自己的dns解析记录

通过上面的理论基础我们知道了dns解析的流程.现在我们增加一条自己的记录.

dnsmasq支持读取/etc/hosts文件作为自己的DNS记录,如果/etc/hosts解析不方便的话,还可以指定–addn-hosts,指定某一文件作为hosts添加到dnsmasq缓存中。所以现在方案就简单了

创建一个configmap,其内容为待解析的域名记录;将configmap作为volume挂载到dnsmasq容器的/dns目录下,然后为dnsmasq增加参数–addn-hosts=/dns/key,宿主机主机名记录就可以加到dnsmasq中去了。

如果集群扩容,configmap更新了呢?我们知道configmap更新了以后,会更新挂载到容器中的文件;但遗憾的是,dnsmasq并不会管addn-hosts的文件的变化,新机器的主机名并不能加到kube-dns中。

办法也有,因为kube-dns是一个deployment,所以可以将其scaleout 1 -> 0 -> 1:

kubectl scale kube-dns --replicas=0 -n kube-system
kubectl scale kube-dns --replicas=1 -n kube-system

缺点就是集群内会暂时关闭DNS解析。

或者 我们也可以在/etc/dnsmasq.d/下的*.conf文件中增加一行自己想要的解析记录

address=/long.com/192.168.115.10

增加以后重启pod就可以了. 跟前面的方法其实是一样的.

使用CoreDNS进行服务发现

上面我们使用的是kube-dns进行的dns管理,当然还有很多其他的dns管理工具, 用的多的就是CoreDNS.

要使用CoreDN您的Kubernetes服务器必须是v1.9或更高版本。要检查版本,请输入kubectl version。

注意:在Kubernetes 1.11中,CoreDNS已经而配置为通用可用性(GA)并默认安装。

CoreDNS是一个通用的权威DNS服务器,可以作为集群DNS,符合dns规范。并且在高版本的k8s中CoreDNS作为默认的dns服务器

使用kubeadm升级现有集群

在Kubernetes 1.10及更高版本中,您还可以在使用kubeadm升级正在使用的群集时移至CoreDNS 。在这种情况下,kubeadm将基于kube-dnsConfigMap 生成CoreDNS配置(“Corefile”),保留联合,存根域和上游名称服务器的配置。

如果要从kube-dns转移到CoreDNS,请确保 在升级期间将CoreDNS功能门设置为true。例如,以下是v1.11.0升级的样子:

kubeadm upgrade apply v1.11.0 --feature-gates=CoreDNS=true

在1.11之前的版本中,Corefile将被升级期间创建的文件覆盖。 如果已对其进行自定义,则应保存现有的ConfigMap。在新的ConfigMap启动并运行后,您可以重新应用自定义。

如果您在Kubernetes 1.11及更高版本中运行CoreDNS,则在升级期间,将保留现有的Corefile。

CoreDNS ConfigMap选项

CoreDNS是一个模块化和可插拔的DNS服务器,每个插件都为CoreDNS添加了新功能。这可以通过维护Corefile来配置,Corefile是CoreDNS配置文件。集群管理员可以修改CoreDNS Corefile的ConfigMap以更改服务发现的工作方式。

在Kubernetes中,CoreDNS安装了以下默认的Corefile配置。

k8s中hostname, hosts文件, DNS和代理问题, service和pod的访问问题_第7张图片

官网参考:https://github.com/coredns/coredns/tree/master/plugin/kubernetes

Corefile配置包括以下CoreDNS 插件:

  • error:错误记录到stdout。
  • health:CoreDNS的运行状况报告为http:// localhost:8080 / health。
  • kubernetes:CoreDNS将根据Kubernetes服务和pod的IP回复DNS查询。
  • prometheus:CoreDNS的度量标准可以在http:// localhost:9153 / Prometheus格式的指标中找到。
  • proxy:任何不在Kubernetes集群域内的查询都将转发到预定义的解析器(/etc/resolv.conf)。
  • cache:这将启用前端缓存。
  • loop:检测简单的转发循环,如果找到循环则停止CoreDNS进程。
  • reload:允许自动重新加载已更改的Corefile。
  • loadbalance:这是一个循环DNS负载均衡器,通过在答案中随机化A,AAAA和MX记录的顺序。

kubernetes下包含更多的配置项

 kubernetes [ZONES...] {
        resyncperiod DURATION
        endpoint URL [URL...]
        tls CERT KEY CACERT
        kubeconfig KUBECONFIG CONTEXT
        namespaces NAMESPACE...
        labels EXPRESSION
        pods POD-MODE
        endpoint_pod_names
        upstream [ADDRESS...]
        ttl TTL
        noendpoints
        transfer to ADDRESS...
        fallthrough [ZONES...]
        ignore empty_service
    }

其中

  • resyncperiod指定Kubernetes数据API DURATION周期。

    • pods insecure返回一个A记录对应的ip,但并不会检查这个ip对应的Pod当前是否存在。这个选项主要用于兼容kube-dns。
    • verified:推荐的方式,返回A记录的同时会确保对应ip的pod存在。比insecure会消耗更多的内存。
    • disabled:默认, 如果您不使用pod记录,则可以使用该选项。
  • Upstream 用于解析指向外部主机的服务(外部服务)。

参考官网:https://github.com/coredns/coredns/tree/master/plugin/kubernetes

我们可以通过修改此configmap来修改默认行为。

使用CoreDNS配置Stub域和上游名称服务器

如果集群运营商的Consul域服务器位于10.150.0.1,并且所有Consul名称都具有后缀.consul.local。要在CoreDNS中配置它,集群管理员在CoreDNS ConfigMap中创建。

另外如果明确强制所有非群集DNS的查询在172.16.0.1要经过特定的名称服务器,proxy和upstream对域名服务器,而不是/etc/resolv.conf(好吧,我翻译错了)

To explicitly force all non-cluster DNS lookups to go through a specific nameserver at 172.16.0.1, point the proxy and upstream to the nameserver instead of /etc/resolv.conf

则设置成下面的配置

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           upstream 172.16.0.1
           fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        proxy . 172.16.0.1
        cache 30
        loop
        reload
        loadbalance
    }
    consul.local:53 {
        errors
        cache 30
        proxy . 10.150.0.1
    }

在Kubernetes 1.10及更高版本中,kubeadm支持从kube-dns ConfigMap自动转换CoreDNS ConfigMap。

又例如下面coredns配置文件:

1.访问cluster.local后缀的,去查10.254.0.2
2.访问out-of.kubernetes的如server.out-of.kubernetes去查192.168.x.x
3.访问互联网的,走resolve.conf的地址

    .:53 {
        errors      # show errors
        log stdout  # show query logs
        health
        kubernetes cluster.local 10.254.0.0/16
        proxy out-of.kubernetes 192.168.x.x
        proxy . /etc/resolv.conf

再例如

. {
    debug
    errors
    whoami
    log
    proxy . /etc/resolv.conf {
            except mydomain.com
        }
    file /file/local mydomain.com
}

debug errors whoami log file proxy都是coredns支持的插件,这里就直接使用。上面最重要的是proxy和file两个插件。

proxy插件中 . /etc/resolv.conf表示所有的查询请求都由/etc/resolv.conf中的nameserver来负责解析,但除了mydomain.com的请求。

mydomain.com的请求怎么处理呢?就靠下面的file /file/local。coredns会加载/file/local中的数据,并且使用这个文件的数据来解析所有和mydomain.com有关的请求。这里需要注意,为什么coredns知道mydomain.com有关的数据都在local文件中,是因为file /file/local mydomain.com最后的mydomain.com表示local文件绑定的就是mydomain.com这个域名。

在pod内部自定义 DNS延伸

为了让用户更容易控制 Pod 中的 DNS 设置,Kubernetes v1.9 引入了一项新的 Alpha 特性(在 v1.10 中处于 Beta 阶段)。该特性在 v1.10 中被默认启用,在 v1.9 中如果想要启用此功能,集群管理员需要在 apiserver 和 kubelet 上启用 CustomPodDNS 特性,例如:“–feature-gates=CustomPodDNS=true,…”。启用了该特性之后,用户可以将 Pod 的 dnsPolicy 字段设置为 “None”,并且可以在 Pod.Spec 中添加新的字段 dnsConfig。

其中 dnsConfig 用来自定义 DNS 参数,而 dnsPolicy 用来给 Pod 选取预设的 DNS。接下来就看看可以通过哪些手段自定义 DNS。

dnsConfig

dnsConfig 可以让操作者延伸到 Pod 内部关于 DNS 的配置,这边需要特别注意的是,我使用的字眼是 延伸 而不是 配置,这是因为通过下一节的 dnsPolicy,每个 Pod 都会有一组预设的 DNS 配置。通过 dnsConfig 我们可以继续往上叠加相关的 DNS 参数到 Pod 之中。

目前总共支持三个参数,分别是:

  • nameservers
  • searches
  • options

这三个参数对应的就是大家熟悉的 /etc/resolv.conf 里面的三个参数,下面解释一下

最主要是nameserver关键字,如果没指定nameserver就找不到DNS服务器,其它关键字是可选的。

  • nameserver表示解析域名时使用该地址指定的主机为域名服务器。其中域名服务器是按照文件中出现的顺序来查询的,且只有当第一个nameserver没有反应时才查询下面的nameserver。
  • domain   声明主机的域名。很多程序用到它,如邮件系统;当为没有域名的主机进行DNS查询时,也要用到。如果没有域名,主机名将被使用,删除所有在第一个点( .)前面的内容。
  • search   它的多个参数指明域名查询顺序。当要查询没有域名的主机,主机将在由search声明的域中分别查找。
  • domain和search不能共存;如果同时存在,后面出现的将会被使用。
  • sortlist  允许将得到域名结果进行特定的排序。它的参数为网络/掩码对,允许任意的排列顺序。
  • options 设置为 timeout:n attempts:n 其中timeout是指连接某个dnsserver有问题造成堵塞的超时值,单位是秒;attempts是指解析域名尝试的次数。(好像不是这个含义)

在 Kubernetes 里面,这三个参数都包含在 dnsConfig 配置项中,而 dnsConfig 包含在 PodSpec 配置项中,因为 Pod 内所有的容器都共享相同的 Network Namespace,所以网络方面的配置都会共享。

这边提供一个简单的 yaml 示例:

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-setting
  namespace: default
spec:
  containers:
  - image: hwchiu/netutils
    command:
      - sleep
      - "360000"
    imagePullPolicy: IfNotPresent
    name: ubuntu
  restartPolicy: Always
  dnsConfig:
    nameservers:
      - 1.2.3.4
    searches:
      - ns1.svc.cluster.local
      - my.dns.search.suffix
    options:
      - name: ndots
        value: "2"
      - name: edns0

通过上述 yaml 创建 Pod 之后,通过下面的命令可以观察到容器中 DNS 配置文件中会出现额外的配置。

$ kubectl exec ubuntu-setting cat /etc/resolv.conf

nameserver 10.254.0.2
nameserver 1.2.3.4
search default.svc.cluster.local svc.cluster.local cluster.local ns1.svc.cluster.local my.dns.search.suffix
options ndots:2 edns0

可以看到 nameserver 多了一个 1.2.3.4,而 search 则多了 ns1.svc.cluster.local my.dns.search.suffix 这两个自定义的值,最后 options 则增加了我们示例中指定的 ndots:2 edns0。

dnsConfig 非常简单直观,如果你需要自定义 DNS 参数,就可以通过这个字段来指定。

dnsPolicy

前面提过,dnsConfig 提供的是延伸 Pod 内预设的 DNS 配置,而 dnsPolicy 就是决定 Pod 内预设的 DNS 配置有哪些。

目前总共有四个类型可以选择:

  • None
  • Default
  • ClusterFirst
  • ClusterFirstHostNet

接下来针对这四个类型分别介绍。

None

None 表示会清除 Pod 预设的 DNS 配置,当 dnsPolicy 设置成这个值之后,Kubernetes 不会为 Pod 预先载入任何自身逻辑判断得到的 DNS 配置。因此若要将 dnsPolicy 的值设为 None,为了避免 Pod 里面没有配置任何 DNS,最好再添加 dnsConfig 来描述自定义的 DNS 参数。

Default

Default 表示 Pod 里面的 DNS 配置继承了宿主机上的 DNS 配置。简单来说,就是该 Pod 的 DNS 配置会跟宿主机完全一致。也就是和node上的dns配置是一样的

ClusterFirst

相对于上述的 Default,ClusterFirst 是完全相反的操作,它会预先把 kube-dns(或 CoreDNS)的信息当作预设参数写入到该 Pod 内的 DNS 配置。

ClusterFirst 是预设的行为,若没有在 Pod 內特別描述 PodPolicy, 则会将 dnsPolicy 预设为 ClusterFirst。

不过ClusterFirst 还有一个冲突,如果你的 Pod 设置了 HostNetwork=true,则 ClusterFirst 就会被强制转换成 Default。

ClusterFirstWithHostNet

ClusterFirstWithHostNet 用途非常简单,就是为了满足使用 HostNetwork 同时使用 k8s DNS 作为我 Pod 预设 DNS 的配置。

只要將 dnsPolicy 设置为 ClusterFirstWithHostNet, 就会一律返回 k8s DNS 的 clusterIP 这种形式。

hostNetwork就可以并行存在了

apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-hostnetwork-policy
  namespace: default
spec:
  containers:
  - image: hwchiu/netutils
    command:
      - sleep
      - "360000"
    imagePullPolicy: IfNotPresent
    name: ubuntu
  hostNetwork: true
  restartPolicy: Always
  dnsPolicy: ClusterFirstWithHostNet

关于如果使用

  hostNetwork: true
  restartPolicy: Always
  dnsPolicy: ClusterFirst

的错误这里解释一下设计上的原理以及流程:

  • 因为设置了 HostNetwork=true, 会让该 Pod 与该节点共用相同的网路空间(网卡/路由等功能)。
  • 而预设的 k8s DNS 是使用 ClusterIP 的 kubernetes serivce. 这种情况下,只有属于 Cluster 內的 Pod 可以获取该 ClusterIP。
  • 所以设置了 HostNetwork=true 的 Pod 就没有办法获取该 ClusterIP。
  • 于是预设就会将对应的 DNS 配置改回 Default 的形式,从节点继承其 DNS 配置信息。

coredns自定义dns记录

根据上面的知识,我们知道我们可以通过配置Corefile文件来实现

重新映射解析域名

例如重写规则映射添加foo.example.com到foo.default.svc.cluster.local:

.:53 {
    errors
    log
    health
    rewrite name foo.example.com foo.default.svc.cluster.local
    kubernetes cluster.local 10.0.0.0/24
    proxy . /etc/resolv.conf
    cache 30
}

通过rewrite实现, 这样在访问域名foo.example.com就是在访问域名foo.default.svc.cluster.local

一旦我们将它添加到ConfigMapvia kubectl edit或者kubectl apply,我们必须让CoreDNS知道它Corefile 已经改变了。您可以发送它SIGUSR1以告诉它重新加载优雅 - 也就是说,不会丢失服务:

$ kubectl exec -n kube-system coredns-980047985-g2748 -- kill -SIGUSR1 1

增加解析文件

我们可以增加自定义的域名解析文件
我们需要修改coredns.yaml我们用于在pod中创建其他文件的方法。要做到这一点,我们必须ConfigMap通过为区域文件添加file一行Corefile,并example.db为区域文件添加另一个键来编辑:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        log
        health
        rewrite name foo.example.com foo.default.svc.cluster.local
        kubernetes cluster.local 10.0.0.0/24
        file /etc/coredns/example.db example.org
        proxy . /etc/resolv.conf
        cache 30
    }
  example.db: |
    ; example.org test file
    example.org.            IN      SOA     sns.dns.icann.org. noc.dns.icann.org. 2015082541 7200 3600 1209600 3600
    example.org.            IN      NS      b.iana-servers.net.
    example.org.            IN      NS      a.iana-servers.net.
    example.org.            IN      A       127.0.0.1
    a.b.c.w.example.org.    IN      TXT     "Not a wildcard"
    cname.example.org.      IN      CNAME   www.example.net.

    service.example.org.    IN      SRV     8080 10 10 example.org.

我们还需要编辑模板规范的volumes部分Pod:

      volumes:
        - name: config-volume
          configMap:
            name: coredns
            items:
            - key: Corefile
              path: Corefile
            - key: example.db
              path: example.db

一旦我们使用了这个kubectl apply -f,就会构建一个新的CoreDNS pod,因为卷中有新文件。以后对文件的更改不需要新的pod,只需像我们之前那样优雅地重启。

让我们来看看:

$ kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
If you don't see a command prompt, try pressing enter.
/ # host foo
foo.default.svc.cluster.local has address 10.0.0.72
/ # host foo.example.com
foo.example.com has address 10.0.0.72
/ # host example.org
example.org has address 127.0.0.1
/ #

解析pod的ip

ingress代理

你可能感兴趣的:(架构,微服务架构)