通过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