#初めに
「kubernetes the hard way を PC でやってみる」の14回目、「CoreDNS」についてです。 (目次)
今回は CoreDNS です。
DNS は Control plane のコンポーネントですが、
kubernetes the hard way では POD としてワーカーノード上にデプロイします。
この回もハマりました、が、基本的には前回のネットワークの問題がほとんどだったので、
ネットワークさえ問題なければ順当に終わると思います。
やることは以下の通りです。 今回は Control plane ノードの1台で実施します
- CoreDNS のデプロイ
- 検証
CoreDNS のデプロイ
kubernetes のドキュメントや kubernetes the hard way では、 NW 周りや CoreDNS では
外部にある yaml ファイルを apply するだけ、という構成になっています。
確かにそれだけでできるのはすごいことではありますが、
やっているほうはなんとなくできた、という感じになってしまいます。
ここでは、一旦 デプロイしたうえで、 yaml の中身も少し見ておきたいと思います。
(私のわかる範囲で…)
Core DNS のデプロイは kubernetes the hard way と同じです。
まず、ダウンロードしておきます。
# curl -o coredns.yaml https://storage.googleapis.com/kubernetes-the-hard-way/coredns.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3715 100 3715 0 0 5415 0 --:--:-- --:--:-- --:--:-- 5415
次にそれを apply します。(もちろん、kubernetes the hard way 通り、いきなりapply してもよいです)
# kubectl apply -f coredns.yaml
serviceaccount/coredns created
clusterrole.rbac.authorization.k8s.io/system:coredns created
clusterrolebinding.rbac.authorization.k8s.io/system:coredns created
configmap/coredns created
deployment.apps/coredns created
service/kube-dns created
サービスアカウント、ClusterRole、ClusterRoleBinding、 ConfigMap、Deployment、 Service が作成されているのが見て取れます。
kube-system の namespace に coredns の POD が2つできて、 それぞれ 1/1 Running となっていれば OK です。
# kubectl get pods --namespace kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
coredns-68567cdb47-8s42p 1/1 Running 0 46s 10.200.0.2 k8sworker2 <none> <none>
coredns-68567cdb47-wnh6c 1/1 Running 0 46s 10.200.0.2 k8sworker0 <none> <none>
#検証
yaml ファイルの中身を見る前に、先に検証を済ませておきます。
busybox の Pod を作成しておきます。
※さてここで注意事項ですが、下記の例では、さらっと --image=busybox:1.28
としています。
これが実は非常に重要で、 busybox の 1.28.4 より新しいバージョンでは CoreDNS の名前解決にエラーが出る ようです。
私も最近なぜか CoreDNS がつれなくなった、、、と嘆いていましたが、 --image=busybox
としていたため
最新版の busybox になっていました。。。
Issue が出ているようです。そしてまだ解消されていないようです。。。
# kubectl run --generator=run-pod/v1 busybox --image=busybox:1.28 --command -- sleep 3600
pod/busybox created
# kubectl get pods -l run=busybox -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox 1/1 Running 0 18s 10.200.2.87 k8sworker2 <none> <none>
次に、 jsonpath で POD 名を取得します。
( kubernetes the hard way に沿って変数に入れていますが、別に POD 名をコピペしてもよいです)
# PODNAME=$( kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}" )
# echo $PODNAME
busybox
該当の POD で nslookup kubernetes を実行します。
kubernetes は API Server の Service 名でしたね。
# kubectl exec -it ${PODNAME} -- nslookup kubernetes
Server: 10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local
確かに、 service を確認しても 10.32.0.1 になっています。
# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.32.0.1 <none> 443/TCP 93d <none>
ついでに kubernetes サービスの endpoint も観ておきましょう。 6443 は API Server のポートですね。
# kubectl get endpoints kubernetes
NAME ENDPOINTS AGE
kubernetes 192.168.199.200:6443,192.168.199.201:6443,192.168.199.202:6443 94d
CoreDNS 補足
CoreDNS yaml ファイル補足
CoreDNS の yaml ファイルの補足です。 補足が不要であれば飛ばしてください。
いずれも すべて kube-system ネームスペースに作成されています。
■まずサービスアカウントです
CoreDNS 用のユーザーアカウントのようなものです。
こんな簡単でいいんですね。
apiVersion: v1
kind: ServiceAccount
metadata:
name: coredns
namespace: kube-system
■ClusterRole
endpoints, services, pods, namespaces に対しては、 list, watch
nodes については get できるようになっているロールです。 ClusterRole なので Cluster 全体に対して有効です。
ただ、それで何をしているのかはわかりませんね。。。
そこをサラサラ説明できるようになりたいものです。。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
rules:
- apiGroups:
- ""
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
■ClusterRoleBinding
前述の system:coredns という ClusterRole と最初に作成した coredns という名前の ServiceAccount を
roleRef:
と subjects:
のフィールドで関連付けています。
これで、 coredns サービスアカウントで、 node の get などができる、という話になります。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:coredns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:coredns
subjects:
- kind: ServiceAccount
name: coredns
namespace: kube-system
■ConfigMap
さて見慣れない記述ですが、どうもこれが CoreDNS の設定ファイルのようです。
kubernetes の下記のドキュメントあたりに説明が記載されています。
Customizing DNS Service、Debugging DNS Resolution
また、Corefile については、Corefile Explained に記載されています。
root ゾーン (.) の 53 番ポートで、{}の中が読み込まれている CoreDNS のプラグインです。
kubernetes プラグイン も読み込まれていますね。
ここで、 cluster.local ゾーンについては 同じネームスペースに実際に Pod がいるかいないかにかかわらず
A レコードとIP を返す設定 (insecure) になっているようです。
また、prometheus プラグインも入っており、CoreDNS のメトリックスを Prometheus に連携できるようですね。
プラグインの種類については Plugins に詳しく記載されています。
さて、もう一つのポイントが cluster.local
だと思います。
kubernetes 上で service を定義すると、 <service_name>.<namespace>.svc.cluster.local
という名前が定義されます。
これは、kubernetes で決められている模様です。
詳しくは、「ServiceとPodに対するDNS」「Kubernetes DNS-Based Service Discovery」をご覧ください。
ただ、それがどうやって Pod の resolv.conf に入ってくるのかは「PodのDNSポリシー」が参考になります。
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
cache 30
loop
reload
loadbalance
}
■Deployment
ようやくなじみのある Deployment ですね。 長いです。
以下のような設定が入っていますね。
-
replicas:
が 2 -
image:
に coredns/coredns:1.6.2 -
args
に-conf
,/etc/coredns/Corefile
を指定 -
/etc/coredns
に ReadOnly でconfig-volume
ボリューム(ConfigMap)をマウント - Readyness Probe, Liveness Probe を利用
- Port は 53/TCP, 53/UDP とメトリック用に 9153/TCP を公開
なお、 2020/08/10 時点では、 CoreDNS は 1.7.0 が最新のようです。 (2020/06/15 リリース)
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/name: "CoreDNS"
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
spec:
priorityClassName: system-cluster-critical
serviceAccountName: coredns
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
nodeSelector:
beta.kubernetes.io/os: linux
containers:
- name: coredns
image: coredns/coredns:1.6.2
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 170Mi
requests:
cpu: 100m
memory: 70Mi
args: [ "-conf", "/etc/coredns/Corefile" ]
volumeMounts:
- name: config-volume
mountPath: /etc/coredns
readOnly: true
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
- containerPort: 9153
name: metrics
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
add:
- NET_BIND_SERVICE
drop:
- all
readOnlyRootFilesystem: true
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /ready
port: 8181
scheme: HTTP
dnsPolicy: Default
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
■Service
サービスです。 一番のポイントは clusterIP: 10.32.0.10
と固定で IP がふられているところですね。
このIP は重要で、 kubelet の設定の中にも登場します。(/var/lib/kubelet/kubelet-config.yaml
)
※kubernetes のドキュメントでは、 --cluster-dns=10.32.0.10 のように渡す形で記載がありますが、
kubernetes the hard way では kubelet-config.yaml に記載されています。
このIP については、重要な割には kubernetes the hard way では説明がありません。。。 気にならないんですかね。。
IP 以外に、当然ですが Port も同様に 53/TCP, 53/UDP, 9153/TCP を公開しています。
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
annotations:
prometheus.io/port: "9153"
prometheus.io/scrape: "true"
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "CoreDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.32.0.10
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
- name: metrics
port: 9153
protocol: TCP
以上が CoreDNS の yaml ファイルの内容になります。
全てが理解できているわけではありませんが、概要を理解するだけでも違うと思います。
##resolv.conf 補足
名前解決の際、以下のようになっていたと思います。
# k exec -it busybox-686db6799-2bp82 -- nslookup kubernetes
Server: 10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local
ここで、 kubernetes の名前解決をすると、 kubernetes.default.svc.cluster.local と返ってきています。
<サービス名>.<ネームスペース名>.svc.cluster.local なのですが、
勝手に default.svc.cluster.local がつく理由は Pod の resolv.conf にあります。
/etc # cat resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.32.0.10
options ndots:5
ここに、 search ドメインとして、 default.svc.cluster.local svc.cluster.local cluster.local
が
入っているため、 kubernetes.default.svc.cluster.local が検索されます。
また、 ndots:5 ですが、 これは "." の数が 5個以下の場合、先に search ドメインを付けたものを検索する、という設定です。
これがあると、(場合により)名前解決が非効率になりパフォーマンスが落ちることがあるようです。
詳細は 「Kubernetes pods /etc/resolv.conf ndots:5 option and why it may negatively affect your application performances」をご覧ください。
今回はここまでとして、次回は Smoke Test の部分を実施します。
← 13.Pod Network
↑ 目次
→ 15.Smoke Test