Kubernetesのcluster使うDNSはClusterアドオンとして用意されています。今回は以下のアドオンを使ってserviceとkube-dnsのpodを作りpodで名前解決が出来るようにします。

以下に設定が用意されているので、これを使ってkube-dnsを動かしてみます。
https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns

apiserverの設定

kubernetesの認証とアクセス制御を動かしてみるで構築したKubernetesのClusterがインストールされている前提で記述します。

まず、apiserverの設定を追加します。
--advertise-addressはkebeletから接続させるためのipアドレスを設定します。kube-apiserver -hで確認すると--bind-addressを設定しているときは同じアドレスが--advertise-addressに設定されると記述されていますが0.0.0.0がアドバタイズするアドレスとして設定できないようで、kubeleteから接続出来るipアドレスを設定する必要があります。

podからはapiserverのclusterIP(10.254.0.1)にsslで通信できるように鍵を設定します。

$ cat /etc/kubernetes/apiserver
KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0 --bind-address=0.0.0.0 --advertise-address=192.168.33.21"
KUBE_API_PORT="--secure-port=6443 --insecure-port=8080"
# KUBELET_PORT="--kubelet-port=10250"
KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379"
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"
KUBE_API_ARGS="--tls-cert-file=/etc/kubernetes/ssl/apiserver.crt --tls-private-key-file=/etc/kubernetes/ssl/apiserver.key --service_account_key_file=/etc/kubernetes/ssl/apiserver.key --authorization-mode=ABAC --authorization-policy-file=/etc/kubernetes/policy/abac-policy.jsonl"

policyの設定

kube-dnsのnamespaceがkube-systemなのでnamespaceがdefaultのapiserverに接続するためのpolicyを追加する必要があります。

$ cat /etc/kubernetes/policy/abac-policy.jsonl
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"system:serviceaccount:default:default", "namespace": "*", "resource": "*", "apiGroup": "*"}}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user":"system:serviceaccount:kube-system:default", "namespace": "*", "resource": "*", "apiGroup": "*"}}

再起動

apiserverを再起動します。

$ systemctl restart kube-apiserver

$ ps aux | grep kube-apiserver | grep -v grep | sed "s/ --/\n--/g"
kube 22140 0.5 5.9 175356 111376 ? Ssl 13:26 0:56 /usr/bin/kube-apiserver
--logtostderr=true
--v=0
--etcd-servers=http://127.0.0.1:2379
--insecure-bind-address=0.0.0.0
--bind-address=0.0.0.0
--advertise-address=192.168.33.21
--secure-port=6443
--insecure-port=8080
--allow-privileged=false
--service-cluster-ip-range=10.254.0.0/16
--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota
--tls-cert-file=/etc/kubernetes/ssl/apiserver.crt
--tls-private-key-file=/etc/kubernetes/ssl/apiserver.key
--service_account_key_file=/etc/kubernetes/ssl/apiserver.key
--authorization-mode=ABAC
--authorization-policy-file=/etc/kubernetes/policy/abac-policy.jsonl

kubeletの設定

kubeletにapiserverと同じ鍵を設定して、dnsの設定も追加します。

$ cat /etc/kubernetes/kubelet
KUBELET_ADDRESS="--address=0.0.0.0"
# KUBELET_PORT="--port=10250"
KUBELET_HOSTNAME="--hostname-override=centos-minion-1"
KUBELET_API_SERVER="--api-servers=http://centos-master-1:8080"
KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"
KUBELET_ARGS="--tls-cert-file=/etc/kubernetes/ssl/apiserver.crt --tls-private-key-file=/etc/kubernetes/ssl/apiserver.key --cluster-dns=10.254.254.254 --cluster-domain=cluster.local"

鍵はapiserverで設定した同じものをコピペして設定します。--cluster-dnsはdnsに割り当てるclusteripを設定します。--cluster-domainはcluster内で使うドメインを指定します。デフォルトはcluster.localなのでとりあえずデフォルトを設定しておきます。

再起動

kubeletを再起動します。

$ systemctl restart kubelet.service

$ ps aux | grep kubelet | grep -v grep | sed "s/ --/\n--/g"
root 22472 1.4 3.4 761736 65684 ? Ssl 13:30 2:42 /usr/bin/kubelet
--logtostderr=true
--v=0
--api-servers=http://centos-master-1:8080
--address=0.0.0.0
--hostname-override=centos-minion-1
--allow-privileged=false
--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest
--tls-cert-file=/etc/kubernetes/ssl/apiserver.crt
--tls-private-key-file=/etc/kubernetes/ssl/apiserver.key
--cluster-dns=10.254.254.254
--cluster-domain=cluster.local

kube-dnsを作る

次のkubernetesのレポジトリのファイルを作ってpodとserviceを作ります。
https://github.com/kubernetes/kubernetes/tree/f7305e6f4375a34cb6e2f47b6e164527370e8871/cluster/addons/dns

まず、serviceから。dnsのipアドレスを設定してサービスを作成します。

$ wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-svc.yaml.base
$ mv kubedns-svc.yaml.base kubedns-svc.yaml
$ sed -i 's|__PILLAR__DNS__SERVER__|10.254.254.254|g' kubedns-svc.yaml
$ kubectl create -f kubedns-svc.yaml
service "kube-dns" created

次にkube-dnsを作ります。設定は使うドメインのみ設定しています。

$ wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-controller.yaml.base
$ mv kubedns-controller.yaml.base kubedns-controller.yaml
$ sed -i 's|__PILLAR__DNS__DOMAIN__|cluster.local|g' kubedns-controller.yaml
$ sed -i "/__PILLAR__FEDERATIONS__DOMAIN__MAP__/d" kubedns-controller.yaml
$ kubectl create -f kubedns-controller.yaml
deployment "kube-dns" created
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
kube-dns-3216771805-i4yzz 3/3 Running 0 1m

正しく起動できた場合は上記のように表示されます。podはkube-dns, sidecar, dnsmasqが作成されます。この3つのpodでdnsの機能を提供する様に設定されています。sidecarがLeader election、dnsmasqがinternal dnsとして動作するようです。

うまく起動しない場合はminionの/var/log/messagesにkubeletのログが出ているので確認できます。
以下の様なログが出ている場合はapiserverと通信ができてないのでapiserverの認証やadvertise-addressが設定されているか確認する必要があります。

Failed to list *v1.Service: Get https://10.254.0.1:443/api/v1/services?resourceVersion=0: dial tcp 10.254.0.1:443: getsockopt: connection refused
Failed to list *v1.Endpoints: Get https://10.254.0.1:443/api/v1/endpoints?resourceVersion=0: dial tcp 10.254.0.1:443: getsockopt: connection refused
Failed to list *v1.ConfigMap: Get https://10.254.0.1:443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dkube-dns&resourceVersion=0: dial tcp 10.254.0.1:443: getsockopt: connection refused

動作確認

以下の手順を参考にdnsが正しく動作しているか確認します。

https://kubernetes.io/docs/admin/dns/

以下の設定を作成してpodを作ります。

$ cat busybox.yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always

$ kubectl create -f busybox.yaml
pod "busybox" created

podの中からkubernetes.defaultをlookupするとアドレスが確認できます。

$ kubectl get pods busybox
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 21s
$ kubectl exec -ti busybox -- nslookup kubernetes.default
Server: 10.254.254.254
Address 1: 10.254.254.254 kube-dns.kube-system.svc.cluster.local

Name: kubernetes.default
Address 1: 10.254.0.1 kubernetes.default.svc.cluster.local

podに付けた名前とipアドレスで正引き・逆引きが出来ることが確認できます。

$ kubectl exec -ti busybox -- nslookup busybox
Server: 10.254.254.254
Address 1: 10.254.254.254 kube-dns.kube-system.svc.cluster.local

Name: busybox
Address 1: 172.30.62.3 busybox
$ kubectl exec -ti busybox -- nslookup 172.30.67.4
Server: 10.254.254.254
Address 1: 10.254.254.254 kube-dns.kube-system.svc.cluster.local

Name: 172.30.62.3
Address 1: 172.30.62.3 busybox

pod内の/etc/resolv.confを確認するとnameserverにkube-dnsのipアドレスが追加されていることが確認できます。domainではなくsearchに3つの名前が追加されていることが確認できます。

$ kubectl exec busybox cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.254.254.254
nameserver 10.0.2.3 // Vagrant
options ndots:5

最後に作成したリソースを記載しておきます。

$ kubectl get all --all-namespaces -o wide
NAMESPACE NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
default svc/kubernetes 10.254.0.1 <none> 443/TCP h <none>
kube-system svc/kube-dns 10.254.254.254 <none> 53/UDP,53/TCP h k8s-app=kube-dns

NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
default po/busybox 1/1 Running 2 h 172.30.62.3 centos-minion-1
kube-system po/kube-dns-3216771805-swlk 3/3 Running 0 h 172.30.62.2 centos-minion-1

おわり。

参考

  1. https://kubernetes.io/docs/admin/dns/
  2. https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns