通过ExternalDNS集成外部DNS服务
ExternalDNS项目的目的是,将Kubernetes的Service/Ingress暴露的服务(的DNS记录)同步给外部的DNS Provider。
ExternalDNS的设计思想类似于KubeDNS,都是从多种K8S API资源中推断需要生成的DNS记录。不同之处是,ExternalDNS本身不提供DNS服务,它必须集成一个外部的DNS服务器,将DNS记录写进去。
大量场景下,使用ExternalDNS你可以基于K8S资源(主要是Ingress和LoadBalancer类型的Service)来动态的控制DNS记录,而不需要知晓DNS服务器的技术细节。这是因为ExternalDNS项目已经集成了多种知名DNS服务提供商。
本章我们尝试以CodeDNS(启用Etcd插件)作为DNS Provider,安装和配置ExternalDNS,并将K8S中的Ingress、Service的DNS记录写到此CoreDNS中。
1 2 3 4 5 6 |
helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update helm install bitnami/etcd --name kubefed-etcd --namespace kube-federation-system \ --set global.imageRegistry=docker.gmem.cc \ --set global.imagePullSecrets[0]=gmemregsecret \ --set auth.rbac.enabled=false --set clusterDomain=k8s.gmem.cc |
1 2 3 |
docker run --name etcd -h etcd --network local --ip 172.21.0.14 --dns 172.21.0.1 \ -e ALLOW_NONE_AUTHENTICATION=yes \ docker.gmem.cc/bitnami/etcd:3.4.9 |
CoreDNS的Etcd插件,实现了SkyDNS风格的服务发现服务。该插件仅仅支持一部分DNS记录类型,因此不适合作为通用的DNS Zone数据插件。此外此插件不去处理subdomain、delegation。存储在Etcd中的数据,以SkyDNS消息的格式编码。Etcd插件通过forward插件的扩展用法,来将请求转发给网络上的服务器。
要启用Etcd插件,你需要修改stable/coredns的Values:
1 2 3 4 5 6 7 8 9 10 11 12 |
servers: - zones: - name: proxy parameters: . /etc/resolv.conf - name: etcd # 此插件是权威的 DNS Zones parameters: k8s.gmem.cc configBlock: |- # 在Etcd中的存储路径 path /skydns # Etcd访问地址 endpoint http://172.21.0.14:2379 |
然后进行安装:
1 2 3 |
helm install coredns-1.10.1.tgz --name kubefed-coredns --namespace kube-federation-system \ --set image.repository=docker.gmem.cc/coredns/coredns \ --set isClusterService=false |
1 2 3 4 5 |
etcd k8s.gmem.cc { path /skydns endpoint http://172.21.0.14:2379 } forward . 114.114.114.114 |
在这里我们安装一个ExternalDNS,并且将CoreDNS作为它的Provider:
1 2 3 4 5 6 7 8 |
helm install bitnami/external-dns --name external-dns --namespace=kube-system \ --set global.imageRegistry=docker.gmem.cc \ --set global.imagePullSecrets[0]=gmemregsecret \ --set provider=coredns \ --set coredns.etcdEndpoints=http://172.21.0.14:2379 \ --set sources="{service,ingress,istio-gateway,crd}" \ --set publishInternalServices=true \ --set crd.create=true --set policy=sync --set logLevel=debug |
为了支持将Ingress Controller的外部IP地址设置给Ingress对象的Status中的IP地址,我们需要较新版本的nginx-ingress:
1 2 3 4 5 6 7 8 9 10 11 |
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm install ingress-nginx/ingress-nginx --name ingress-nginx --namespace kube-system --set controller.image.repository=docker.gmem.cc/kubernetes-ingress-controller/nginx-ingress-controller \ # 将Ingress Controller的Service的IP地址报告为Ingress的Status的IP地址 --set controller.publishService.enabled=true \ # 使用的默认SSL证书 --set controller.extraArgs."default-ssl-certificate"="kube-system/gmemk8scert" \ # 配合MetalLB使用,让Ingress Controller的Service获得外部IP --set controller.service.type=LoadBalancer \ --set controller.admissionWebhooks.patch.image.repository=docker.gmem.cc/jettech/kube-webhook-certgen \ --set imagePullSecrets[0].name=gmemregsecret |
在K8S集群中创建一个Ingress,并等待其ADDRESS(status.loadBalancer.ingress.ip[0])被填充:
1 2 3 |
kubectl -n devops get ingress grafana # NAME HOSTS ADDRESS PORTS AGE # grafana grafana.k8s.gmem.cc 10.0.11.10 80, 443 534d |
这时,ExternalDNS的日志中会出现DNS记录同步的相关信息:
time="2020-06-01T02:46:34Z" level=debug msg="Endpoints generated from ingress: devops/grafana: [grafana.k8s.gmem.cc 0 IN A 10.0.11.10 [] grafana.k8s.gmem.cc 0 IN A 10.0.11.10 []]"
CoreDNS的后端Etcd中则会出现条目:
1 2 3 |
etcdctl --endpoints http://172.21.0.14:2379 get /skydns/cc/gmem/k8s/grafana --prefix # /skydns/cc/gmem/k8s/grafana/0e5a5d35 # {"host":"10.0.11.10","text":"\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/devops/grafana\"","targetstrip":1} |
使用nslookup,针对CoreDNS进行DNS查询测试,可以发现解析能够成功。
选项 | 说明 |
--master="" | K8S API Server地址 |
--kubeconfig="" | 使用的Kubeconfig |
--request-timeout=30s | K8S API Server访问超时 |
--source=source .. | 从哪些K8S资源中查找端点:service, ingress, node, fake, connector, istio-gateway, cloudfoundry, contour-ingressroute, crd, empty, skipper-routegroup |
--namespace="" | 从哪些命名空间查找K8S资源,默认所有命名空间 |
--annotation-filter="" | 基于注解过滤被external-dns管理的source列表,默认所有source |
--fqdn-template="" |
对于不提供hostname的源,使用该参数提供的模板生成DNS名。可以指定逗号分隔的列表 和fake source联用时则指定hostname后缀 |
--combine-fqdn-annotation | combine fqdn-template和注解,而非覆盖 |
--ignore-hostname-annotation | 提供了fqdn-template的情况下,生成DNS名称时忽略hostname注解 |
--publish-internal-services | 发布ClusterIP类型Service的地址 |
--publish-host-ip | 发布无头服务的host-ip |
--always-publish-not-ready-addresses | 总是发布无头服务的尚未就绪的地址 |
--crd-source-apiversion | CRD源的API版本,默认externaldns.k8s.io/v1alpha1 |
--crd-source-kind="DNSEndpoint" | CRD源的API类型 |
--service-type-filter | 关注的Service类型,默认all,可选ClusterIP, NodePort, LoadBalancer, ExternalName |
--provider=provider | 使用的DNS Provider,可选aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, ovh, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns |
--domain-filter= ... | 限制处理的目标DNS Zone,使用domain后缀形式,该参数可以指定多次 |
--exclude-domains= ... | 排除DNS子域 |
--zone-id-filter= ... | 使用Zone ID来过滤目标Zone |
--policy=sync | 和DNS Provider进行数据同步的方式,默认sync,可选upsert-only, create-only |
--registry=txt | 跟踪DNS记录所有权的registry实现方式,默认txt,可选noop, aws-sd |
--txt-owner-id="default" | 使用txt registry时,用于识别当前ExternalDNS的ID |
--txt-prefix="" | 使用txt registry时,给每个所有权记录前缀的字符串 |
--txt-cache-interval=0s | txt缓存同步时间 |
--interval=1m0s | 两次连续的,到DNS Provider的同步的间隔 |
--once | 在第一次同步后,退出同步循环 |
--dry-run | 打印DNS记录变更,不调用DNS Provider |
--events | 当source变更时间发生时,也(在定期同步的基础上)触发同步 |
--log-format=text | 日志格式,可选text, json |
--metrics-address=":7979" | 指标和健康检查暴露地址 |
--log-level=info | 日志级别 panic, debug, info, warning, error, fatal |
Leave a Reply