K8s系列之:DNS服务搭建指南

K8s系列之:DNS服务搭建指南

  • 一、skydns配置文件说明
  • 二、修改每台Node上的kubelet启动参数
  • 三、创建skydns RC和Service
  • 四、通过DNS查找Service
  • 五、DNS服务的工作原理解析

作为服务发现机制的基本功能,在集群内需要能够通过服务名对服务进行访问,就需要一个集群范围的DNS服务来完成服务名到ClusterIP的解析。

K8s提供的虚拟DNS服务名为skydns,由4个组件组成。

  • etcd:DNS存储
  • kube2sky:将K8s Master中的Service(服务注册到etcd)。
  • skyDNS:提供DNS域名解析服务
  • healthz:提供对skydns服务的健康检查功能。

K8s系列之:DNS服务搭建指南_第1张图片

一、skydns配置文件说明

skydns服务由一个RC和一个Service的定义组成,分别由配置文件skydns-rc.yaml和skydns-svc.yaml定义。

skydns的RC配置文件skydns-rc.yaml的内容如下,包含了4个容器的定义:
skydns-rc.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: kube-dns-v11
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    version: v11
    kubernetes.io/cluster-service: "true"
spec:
  replicas: 1
  selector:
    k8s-app: kube-dns
    version: v11
  template:
    metadata:
      labels:
        k8s-app: kube-dns
        version: v11
        kubernetes.io/cluster-service: "true"
      spec:
        containers:
        - name: etcd
          image: gcr.io/google_containers/etcd-amd64:2.2.1
          resources:
            limits:
              cpu: 100m
              memory: 50Mi
            requests:
              cpu: 100m
              memory: 50Mi
            command:
            - /usr/local/bin/etcd
            - -data-dir
            - /tmp/data
            - -listen-client-urls
            - http://127.0.0.1:2379,http://127.0.0.1:4001
            - -advertise-client-urls
            - http://127.0.0.1:2379,http://127.0.0.1:4001
            - -initial-cluster-token
            - skydns-etcd
            volumeMounts:
            - name: etcd-storage
              mountPath: /tmp/data
            - name: kube2sky
              image: gcr.io/google_containers/kube2sky-amd64:1.15
              resources:
                limits:
                  cpu: 100m
                  #kube2sky watches all pods
                  memory: 50Mi
                requests:
                  cpu: 100m
                  memory: 50Mi
              livenessProbe:
                httpGet:
                  path: /healthz
                  port: 8080
                  schema: HTTP
                initialDelaySeconds: 60
                timeoutSeconds: 5
                successThreshold: 5
                successThreshold: 1
                failureThreshold: 5
              readinessProbe:
                httpGet:
                  path: /readiness
                  port: 8081
                  schema: HTTP
                initialDelaySeconds: 30
                timeoutSeconds: 5
              args:
              - --kube-master-url=http://192.168.18.3:8080
              - --domain=cluster.local
              - name: skydns
                image: gcr.io/google_containers/skydns:2015-10-13-8c72f8c
                resources:
                  limits:
                    cpu: 100m
                    memory: 50Mi
                  requests:
                    cpu: 100m
                    memory: 50Mi
                  args:
                  - -machines=http://127.0.0.1:4001
                  - -addr=0.0.0.0:53
                  - -ns-rotate=false
                  - -domain=cluster.local
                  ports:
                  - containerPort: 53
                    name: dns
                    protocol: UDP
                  - containerPort: 53
                    name: dns-tcp
                    protocol: TCP
                - name:
                  image: gcr.io/google_containers/exechealthz:1.0
                  resources:
                    limits:
                      cpu: 10m
                      memory: 20Mi
                    requests:
                      cpu: 10m
                      memory: 20Mi
                    args:
                    - -cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 >/dev/null
                    - -port=8080
                    ports:
                    - containerPort: 8080
                      protocol: TCP
                  volumes:
                  - name: etcd-storage
                    emptyDir: {}
                  dnsPolicy: Default

需要修改的几个配置参数如下:

  • kube2sky容器需要访问K8s Master,需要配置Master所在物理主机的IP地址和端口号,本例中设置参数–kube_master_url的值为http://192.168.18.3:8080

  • kube2sky容器和skydns容器的启动参数–domain,设置kubernetes集群中Service所属的域名,本例中为cluster.local。启动后,kube2sky会通过API Server监控集群中全部Service的定义,生成相应的记录并保存到etcd中。kube2sky为每个Service生成以下两条记录。

  • ..

  • ..svc.

  • skydns的启动参数-addr=0.0.0.0:53表示使用本机TCP和UDP的53端口提供服务。

skydns-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: "KubeDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 169.169.0.100
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP

注意:skydns服务使用的clusterIP需要指定一个固定的IP地址,每个Node的kubelet进程都将使用这个IP地址,不能通过Kubernetes自动分配。

这个IP地址需要在kube-apiserver启动参数–service-cluster-ip-range指定的IP地址范围内。
在创建skydns容器之前,先修改每个Node上kubelet的启动参数。

二、修改每台Node上的kubelet启动参数

修改每台Node上kubelet的启动参数,加上以下两个参数:

  • –cluster_dns=169.169.0.100:为DNS服务的ClusterIP地址
  • –cluster_domain=cluster.local:为DNS服务中设置的域名。

重启kubelet服务

三、创建skydns RC和Service

通过kubectl create完成skydns的RC和Service的创建:

kubectl create -f skydns-rc.yaml
kubectl create -f skydns-svc.yaml

查看RC、Pod和Service,确保容器成功启动:

kubectl get rc --namespace=kube-system
kubectl get pods --namespace=kube-system
kubectl get services --namespace=kube-system

为redis-master应用创建一个Service
redis-master-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: redis-master
  labels:
    name: redis-master
spec:
  ports:
  - port: 6379
    targetPort: 6379
  selector:
    name: redis-master

查看创建好的redis-master service:

kubectl get services
NAME       CLUSTER-IP         EXTERNAL-IP     PORT(S)   AGE
redis-master    169.169.8.10    <none>        6379/TCP   1h

系统为redis-master服务分配了一个虚拟IP地址:169.169.8.10。

至此在K8s集群内虚拟DNS服务就搭建好了。在需要访问redis-master的应用中,仅需要配置上redis-master Service的名称和服务的端口号,就能够访问到redis-master应用了。

redis-slave镜像的启动脚本/run.sh的内容为:

if [[ ${GET_HOSTS_FROM:-dns} == "env" ]]; then
  redis-server --slaveof ${REDIS_MASTER_SERVICE_HOST} 6379
else
  redis-server --slaveof redis-master 6379
fi

在使用DNS模式的情况下,redis-slave配置的Master地址为:redis-master:6379。通过服务名进行配置,能够极大地简化客户端应用对后端服务变化的感知,包括服务虚拟IP地址的变化、服务后端Pod的变化等,对应用程序的微服务架构实现提供了强有力的支撑。

四、通过DNS查找Service

接下来使用一个带有nslookup工具的Pod来验证DNS服务是否能够正常工作。

busybox.yaml

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - name: busybox
    image: gcr.io/google_containers/busybox
    command:
      - sleep
      - "3600" 

运行kubectl create -f busybox.yaml完成创建。

在该容器成功启动后,通过kubectl exec nslookup进行测试。

kubectl exec busybox -- nslookup redis-master
Server:        169.169.0.100
Address 1:     169.169.0.100

Name:          redis-master
Address 1:     169.169.8.10

可以看到,通过DNS服务器169.169.0.100成功找到了名为"redis-master"服务的IP地址:169.169.8.10.

如果某个Service属于不同的命名空间,在进行Service查找时,需要带上namespace的名字。下面以查找kube-dns服务为例:

kubectl exec busybox -- nslookup kube-dns.kube-system
Server: 169.169.0.100
Address 1: 169.169.0.100

Name:    kube-dns.kube-system
Address 1: 169.169.0.100

仅使用kube-dns来进行查找,将会失败:
nslookup: can’t resolve ‘kube-dns’

五、DNS服务的工作原理解析

(1)kube2sky容器应用通过调用K8s Master的API获得集群中所有Service的信息,并持续监控新Service的生成,然后写入etcd中。

查看etcd中存储的Service信息:

kubectl exec kube-dns-v8-5tpm2 -c etcd --namespace=kube-system etcdctl ls /skydns/local/cluster

/skydns/local/cluster/default
/skydns/local/cluster/svc
/skydns/local/cluster/kube-system

查看redis-master服务对应的键值:

kubectl exec kube-dns-v8-5tpm2 -c etcd --namespace=kube-system etcdctl get /skydns/local/cluster/default/redis-master

{"host":"169.169.8.10","priority":10,"weight":10,"ttl":30,"targetstrip":0}

可以看到,redis-master服务对应的完整域名为redis-master.default.cluster.local,并且IP地址为169.169.8.10。

(2)根据kubelet启动参数的设置(–cluster_dns),kubelet会在每个新创建的Pod中设置DNS域名解析配置文件/etc/resolv.conf文件,在其中增加了一条namespace配置和一条search配置:

nameserver            169.169.0.100
search default.svc.cluster.local          svc.cluster.local          cluster.local     localdomain

通过名字服务器169.169.0.100访问的实际上就是skydns在53端口上提供的DNS解析服务。

(3)最后,应用程序就能够像访问网站域名一样,仅仅通过服务的名字就能访问到服务了。

以redis-slave为例,假设启动了redis-slave Pod,登陆redis-slave容器进行查看,可以看到其通过DNS域名服务找到了redis-master的IP地址169.169.8.10,并成功进行了连接。

你可能感兴趣的:(日常分享专栏,kubernetes,K8s系列,DNS服务搭建指南)