Kubernetes技术分析之DNS

jopen 9年前

Docker的流行激活了一直不温不火的PaaS,随着而来的是各类Micro-PaaS的出现,Kubernetes是其中最具代表性的一员,它是 Google多年大规模容器管理技术的开源版本。本系列文章将逐一分析Kubernetes, 本文主要讲解如何开启DNS支持,以及其原理和使用方式。

1.开启DNS

Kubernetes支持2种服务发现方式,环境变量和DNS,其中环境变量是默认支持的,但是环境变量方式存在限制:Pod必须在Service之后创建,DNS则没有这个限制。

DNS是一种Cluster Add-on, 它随Kubernetes部署,但是需要配置启动:

- cluster turn-up

如果使用cluster turn-up,需要配置cluster/gce/config-default.sh
ENABLE_CLUSTER_DNS=true  DNS_SERVER_IP="10.0.0.10"  DNS_DOMAIN="cluster.local"  DNS_REPLICAS=1

- 手动方式

首先启动DNS server ReplicationController和Service,
配置文件模板:https://github.com/GoogleCloud ... s/dns

skydns-rc.yaml:
apiVersion: v1  kind: ReplicationController  metadata:  name: kube-dns-v6  namespace: kube-system  labels:  k8s-app: kube-dns  version: v6  kubernetes.io/cluster-service: "true"  spec:  replicas: 1  selector:  k8s-app: kube-dns  version: v6  template:  metadata:    labels:      k8s-app: kube-dns      version: v6      kubernetes.io/cluster-service: "true"  spec:    containers:    - name: etcd      image: gcr.io/google_containers/etcd:2.0.9      resources:        limits:          cpu: 100m          memory: 50Mi      command:      - /usr/local/bin/etcd      - -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    - name: kube2sky      image: gcr.io/google_containers/kube2sky:1.11      resources:        limits:          cpu: 100m          memory: 50Mi      args:      # command = "/kube2sky"      - --kube_master_url=http://192.168.3.146:8080 #change to your master url      - -domain=cluster.local    - name: skydns      image: gcr.io/google_containers/skydns:2015-03-11-001      resources:        limits:          cpu: 100m          memory: 50Mi      args:      # command = "/skydns"      - -machines=http://localhost:4001      - -addr=0.0.0.0:53      - -domain=cluster.local.      ports:      - containerPort: 53        name: dns        protocol: UDP      - containerPort: 53        name: dns-tcp        protocol: TCP    dnsPolicy: Default  # Don't use cluster DNS.

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: 10.254.210.250  ports:  - name: dns  port: 53  protocol: UDP  - name: dns-tcp  port: 53  protocol: TCP

创建后可以查看:
$ kubectl --namespace="kube-system" get pods  NAME                READY     STATUS    RESTARTS   AGE  kube-dns-v6-5y317   3/3       Running   0          2d    $ kubectl --namespace="kube-system" get services  NAME       LABELS               SELECTOR             IP(S)            PORT(S)  kube-dns   k8s-app=kube-dns...  k8s-app=kube-dns     10.254.210.250   53/UDP,53/TCP

DNS Server启动完成后,还需要配置kubelet:
--cluster_dns=10.254.210.250  #DNS service ip  --cluster_domain=cluster.local #default local domain

部署好的话可以验证下,现有以下services:
$ kubectl get services  NAME            LABELS                 SELECTOR            IP(S)            PORT(S)  frontend        name=frontend          name=frontend       10.254.159.131   80/TCP  redis-master    name=redis-master      name=redis-master   10.254.169.230   6379/TCP  redis-slave     name=redis-slave       name=redis-slave    10.254.70.184    6379/TCP

选择一个pod,进行DNS验证:
$ kubectl exec busybox -- nslookup frontend          Server:    10.254.210.250  Address 1: 10.254.210.250    Name:      frontend  Address 1: 10.254.159.131    $ kubectl exec busybox -- nslookup redis-master  Server:    10.254.210.250  Address 1: 10.254.210.250    Name:      redis-master  Address 1: 10.254.169.230    $ kubectl exec busybox -- nslookup redis-slave  Server:    10.254.210.250  Address 1: 10.254.210.250    Name:      redis-slave  Address 1: 10.254.70.184

可以看到查询处理的ip和Service ip一致,说明DNS工作正常。

2.DNS说明

DNS Server包含3部分:
- skyDNS: 提供DNS解析服务
- etcd:用于skyDNS的存储
- kube2sky:连接Kubernetes和skyDNS

实际上kube2sky会监听Kubernetes,当有新的Service创建时,就生成相应记录到skyDNS,一个Service包括2条记录:
<service_name>.<namespace_name>.<domain>  <service_name>.<namespace_name>.svc.<domain>

然后kubelet会在容器启动的时候配置根据/etc/resolv.conf:
$ kubectl exec busybox cat /etc/resolv.conf   nameserver 10.254.210.250  nameserver 218.85.157.99  search default.svc.cluster.local svc.cluster.local cluster.local  options ndots:5

可以看到配置了DNS Service IP作为域名服务器,然后设置了default.svc.cluster.local svc.cluster.local cluster.local作为默认域名。

以redis-master service为例:
$ kubectl exec busybox -- nslookup redis-master  Server:    10.254.210.250  Address 1: 10.254.210.250    Name:      redis-master  Address 1: 10.254.169.230    $ kubectl exec busybox -- nslookup redis-master.default.cluster.local  Server:    10.254.210.250  Address 1: 10.254.210.250    Name:      redis-master.default.cluster.local  Address 1: 10.254.169.230    $ kubectl exec busybox -- nslookup redis-master.default.svc.cluster.local  Server:    10.254.210.250  Address 1: 10.254.210.250    Name:      redis-master.default.svc.cluster.local  Address 1: 10.254.169.230

对于Headless services,域名则对于所有Endpoints:
$ kubectl describe service frontend-headless  Name:           frontend-headless  Namespace:      default  Labels:         name=frontend-headless  Selector:               name=frontend  Type:           ClusterIP  IP:                None  Port:                  <unnamed> 80/TCP  Endpoints:        10.1.14.19:80,10.1.79.47:80,10.1.79.48:80  Session Affinity:     None  No events.    $ kubectl exec busybox -- nslookup frontend-headless  Server:    10.254.210.250  Address 1: 10.254.210.250    Name:      frontend-headless  Address 1: 10.1.14.19  Address 2: 10.1.79.47  Address 3: 10.1.79.48

参考


作者简介

吴龙辉,现任网宿科技高级运营工程师,致力于云计算PaaS的研究和实践,活跃于CloudFoundry、Docker、Kubernetes等开源社区,贡献代码和撰写技术文档。