如何为裸机配置 kubespray DNS

问题描述

我对 kubernetes 比较陌生,我的大学课程有一个项目,要在裸机上构建 kubernetes 集群。

为此,我设置了一个 PoC 环境,在 6 台机器(其中 3 台是一个节点上的 KVM 机器)中,所有管理都由 MAAS 完成,即 DHCP,而 DNS 由那台机器管理。我有一个委托给 MAAS DNS 服务器 k8s.example.com 的 DNS 区域,所有机器都在其中。整个网络在自己的 VLAN 10.0.10.0/24 中,从 DHCP 保留 metallb IPRange。 这是一张说明简单集群的图片:

k8s overview

软件方面,所有主机都使用 ubuntu 20.04,我使用 kubespray 部署所有内容,即 kubernetes、metallb 和 nginx-ingress-controller。我对应的 kubespray 值是:

dashboard_enabled: false
ingress_nginx_enabled: true
ingress_nginx_host_network: true

kube_proxy_strict_arp: true

metallb_enabled: true
metallb_speaker_enabled: true
metallb_ip_range:
  - "10.0.10.100-10.0.10.120"

kubeconfig_localhost: true

我的问题是,我无法将 DNS 从集群中移出到 Internet 进行工作。 我有一个通配符 A Record set for *.k8s.example.com 到 nginx-Ingress 外部 ip,这对于每个 pod 都可以从外部访问。 问题是,集群内的每个容器都无法再访问 Internet。每个请求都通过入口路由。意思是,如果我尝试到达 www.google.net,它会尝试到达 www.google.net.k8s.example.com,这是有道理的。删除通配符 A 记录后,只有每个 .com 域都可以毫无问题地访问(例如 www.google.com),它工作正常。集群内的所有 Pod 相互访问都没有问题。

我看到有几种配置可能性,在那里进行调整是有意义的,但在 2 周后,我真的更喜欢基于最佳实践并正确完成的解决方案。

我真的很想能够使用通配符 A 记录,但我担心这可能是不可能的。

我希望我提供了所需的所有信息,以使您能够充分了解我的问题。

编辑: 我使用了标准的 kubespray DNS 配置,因为我被告知它就足够了:

DNS configuration.
# Kubernetes cluster name,also will be used as DNS domain
cluster_name: cluster.local
# Subdomains of DNS domain to be resolved via /etc/resolv.conf for hostnet pods
ndots: 2
# Can be coredns,coredns_dual,manual or none
dns_mode: coredns
# Set manual server if using a custom cluster DNS server
# manual_dns_server: 10.x.x.x
# Enable nodelocal dns cache
enable_nodelocaldns: true
nodelocaldns_ip: 169.254.25.10
nodelocaldns_health_port: 9254
# nodelocaldns_external_zones:
# - zones:
#   - example.com
#   - example.io:1053
#   nameservers:
#   - 1.1.1.1
#   - 2.2.2.2
#   cache: 5
# - zones:
#   - https://mycompany.local:4453
#   nameservers:
#   - 192.168.0.53
#   cache: 0
# Enable k8s_external plugin for CoreDNS
enable_coredns_k8s_external: false
coredns_k8s_external_zone: k8s_external.local
# Enable endpoint_pod_names option for kubernetes plugin
enable_coredns_k8s_endpoint_pod_names: false

# Can be docker_dns,host_resolvconf or none
resolvconf_mode: docker_dns
# Deploy netchecker app to verify DNS resolve as an HTTP service
deploy_netchecker: false
# Ip address of the kubernetes skydns service
skydns_server: "{{ kube_service_addresses|ipaddr('net')|ipaddr(3)|ipaddr('address') }}"
skydns_server_secondary: "{{ kube_service_addresses|ipaddr('net')|ipaddr(4)|ipaddr('address') }}"
dns_domain: "{{ cluster_name }}"

我注意到的是,pods 的 etc resolv.conf 看起来像这样:

/ $ cat /etc/resolv.conf 
nameserver 169.254.25.10
search flux-system.svc.cluster.local svc.cluster.local cluster.local k8s.example.com maas
options ndots:5

例如在由 MAAS 管理的节点上,它是:

# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs must not access this file directly,but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 127.0.0.53
options edns0 trust-ad
search k8s.example.com maas

解决方法

正如评论中所讨论的,问题在于您的 Kubernetes 节点上的 resolv.conf,以及您使用的通配符记录与该 resolv.conf search 条目中的名称之一匹配的事实。

您可以从节点或 Pod 中调用的任何名称将首先被搜索为 ${input}.${search-entry},而 ${input} 仅在与您的 search 的连接没有返回时才会被查询已经有一些记录了。在域搜索列表中包含通配符记录将导致任何名称解析为该记录。

承认在这种情况下,k8s.example.com 记录是由 MAAS 推送的,并且我们无法真正持久地删除它,下一个最佳解决方案是使用另一个名称服务于您的 Ingress - 子域,或者不相关的东西。通常,更改 DHCP 服务器中的选项就足够了 - 或者可以说更好:不要使用 DHCP 托管 Kubernetes 节点。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...