coredns on k3os

# はじめに

今回は k3os 上に DNS サーバの coredns を構築してみました。
k8s 内部で利用される文献は多かったのですが、IaaS やオンプレなど外部から使う用の DNS の文献は少なかったので。
※k3os ではなく、各種 k8s でも下記の手順で構築できる、、、はず。

# 環境・構築順序

相も変わらず今回もクライアント環境です

ホストOS：Windows 10 Pro
VirtualBox：6.0.8
※ネットワークはブリッジアダプターで作成しました
k3os：v0.2.0

※coredns については詳しく触れません、本家ドキュメントを参考に
※coredns は etcd + PersistentVolume で永続化もできますが、今回は簡易的なConfigmapを使ってます

構築順序は

1. k3os 構築
2. nginx-ingress のデプロイ
3. coredns のデプロイ

です。

### 完成図

![coredns01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/abb7a135-c91e-8b8d-b888-8fb7fde871d7.jpeg)

※ns：namespace、ds：daemonset、cm：configmap、svc：service、deploy：deployment

# 1. k3os 構築

自分の記事で申し訳ないのですが、以下の記事を参考に。

[Rancher on k3os](https://qiita.com/t_ume/items/2fde5ebeee404b8c281c)
※os-config でディスクインストールまでを参考に

[k3os REAME 読んでみた](https://qiita.com/t_ume/items/d605c79a7e4dbf2d50db)
※Configuration を参考に今回はIPを固定化してます

# 2. nginx-ingress のデプロイ

下記、本家リンクを参考に進めていきます。
[Installing the Ingress Controller](https://github.com/nginxinc/kubernetes-ingress/blob/master/docs/installation.md)

１．namespace と serviceaccount を作成します

```bash:ns-and-sa.yaml
yaml : https://github.com/nginxinc/kubernetes-ingress/blob/master/deployments/common/ns-and-sa.yaml

$ kubectl apply -f ns-and-sa.yaml

$ kubectl describe ns nginx-ingress
Name:         nginx-ingress
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","kind":"Namespace","metadata":{"annotations":{},"name":"nginx-ingress"}}
Status:       Active
No resource quota.
No resource limits.

$ kubectl describe sa nginx-ingress -n nginx-ingress
Name:                nginx-ingress
Namespace:           nginx-ingress
Labels:              <none>
Annotations:         kubectl.kubernetes.io/last-applied-configuration:
                       {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"nginx-ingress","namespace":"nginx-ingress"}}
Image pull secrets:  <none>
Mountable secrets:   nginx-ingress-token-xxxxx
Tokens:              nginx-ingress-token-xxxxx
Events:              <none>
```
２．デフォルト TLS 用に secret を登録します

```bash:default-server-secret.yaml
yaml : https://github.com/nginxinc/kubernetes-ingress/blob/master/deployments/common/default-server-secret.yaml

$ kubectl apply -f default-server-secret.yaml

$ kubectl describe secret default-server-secret -n nginx-ingress
Name:         default-server-secret
Namespace:    nginx-ingress
Labels:       <none>
Annotations:
Type:         Opaque

Data
====
tls.crt:  1013 bytes
tls.key:  1679 bytes
```

３．nginx の設定ファイルとして configmap を作成します
　　※最初は空で作成します

```bash:nginx-config.yaml
yaml : https://github.com/nginxinc/kubernetes-ingress/blob/master/deployments/common/nginx-config.yaml

$ kubectl apply -f nginx-config.yaml

$ kubectl describe cm nginx-config -n nginx-ingress
Name:         nginx-config
Namespace:    nginx-ingress
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","data":null,"kind":"ConfigMap","metadata":{"annotations":{},"name":"nginx-config","namespace":"nginx-ingress"}}

Data
====
```

４．「１．」で作成したserviceaccount に rbac の設定を行います

```bash:rbac.yaml
yaml : https://github.com/nginxinc/kubernetes-ingress/blob/master/deployments/rbac/rbac.yaml

$ kubectl apply -f rbac.yaml
```

５．nginx-ingress コンテナをデプロイします
　　※今回は公開ポートを 53 で指定したいため、Deployment ではなく DaemonSets でデプロイします
　　※[こちら](https://github.com/nginxinc/kubernetes-ingress/blob/master/deployments/daemon-set/nginx-ingress.yaml)を参考に yaml を修正しています

```yaml:nginx-ingress.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ingress
  namespace: nginx-ingress
spec:
  selector:
    matchLabels:
      app: nginx-ingress
  template:
    metadata:
      labels:
        app: nginx-ingress
     #annotations:
       #prometheus.io/scrape: "true"
       #prometheus.io/port: "9113"
    spec:
      serviceAccountName: nginx-ingress
      containers:
      - image: nginx/nginx-ingress:edge
        imagePullPolicy: Always
        name: nginx-ingress
        ports:
        - name: dns-tcp
          containerPort: 53
          hostPort: 53
          protocol: TCP
        - name: dns-udp
          containerPort: 53
          hostPort: 53
          protocol: UDP
       #- name: prometheus
         #containerPort: 9113
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        args:
          - -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
          - -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
         #- -v=3 # Enables extensive logging. Useful for troubleshooting.
         #- -report-ingress-status
         #- -external-service=nginx-ingress
         #- -enable-leader-election
         #- -enable-prometheus-metrics
         #- -enable-custom-resources
```
```bash:nginx-ingress.yaml
$ kubectl apply -f nginx-ingress.yaml

$ kubectl get all -n nginx-ingress
NAME                      READY   STATUS    RESTARTS   AGE
pod/nginx-ingress-4xmht   1/1     Running   0          22m

NAME                           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/nginx-ingress   1         1         1       1            1           <none>          22m
```
nginx-ingress のデプロイはここまでで完了です。

# 3. coredns のデプロイ

最後に coredns をデプロイし、名前解決できるところまで確認します。

下記、本家リンクを参考に進めていきます。
[Support for TCP/UDP Load Balancing](https://github.com/nginxinc/kubernetes-ingress/tree/master/examples/tcp-udp)

１．coredns のデプロイ
※今回は default namespace に構築します

```yaml:dns.yaml
yaml : https://github.com/nginxinc/kubernetes-ingress/blob/master/examples/tcp-udp/dns.yaml
※上部 configmap の行のみ以下で修正

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
data:
  Corefile: |
    .:53 {
      forward . 8.8.8.8:53
      log
    }

    invalid {
      hosts /etc/hosts invalid {
        192.168.xx.xx www.rancher.invalid
      }
      errors
      log
    }

※Corefile の中身は適宜変更してください、最低限「.:53」のセクションさえあれば名前解決はします
※invalid ドメインはテスト用の静的DNSとして登録してあります
```

```bash:dns.yaml
$ kubectl apply -f dns.yaml

$ kubectl get all -n default
NAME                           READY   STATUS    RESTARTS   AGE
pod/coredns-6b479dfb7f-lksjg   1/1     Running   0          17m
pod/coredns-6b479dfb7f-nf7sr   1/1     Running   0          17m

NAME                       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
service/coredns            ClusterIP   10.43.116.169   <none>        53/UDP,53/TCP   17m
service/coredns-headless   ClusterIP   None            <none>        53/UDP,53/TCP   17m
service/kubernetes         ClusterIP   10.43.0.1       <none>        443/TCP         42m

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns   2/2     2            2           17m

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/coredns-6b479dfb7f   2         2         2       17m
```

２．nginx-ingress の nginx 設定を修正します

```yaml:nginx-config.yaml
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
  namespace: nginx-ingress
data:
    stream-snippets: |
      upstream coredns-udp {
          server coredns.default.svc.cluster.local:53;
      }
      server {
          listen 53 udp;
          proxy_pass coredns-udp;
          proxy_responses 1;
      }
      upstream coredns-tcp {
          server coredns.default.svc.cluster.local:53;
      }
      server {
          listen 53;
          proxy_pass coredns-tcp;
      }
```
※k3s 内で coredns.default.svc.cluster.local が解決できない場合は、coredns の yaml 内で作成した service の ClusterIP を指定することで動作します

```bash:nginx-config.yaml
$ kubectl apply -f nginx-config.yaml

$ kubectl describe cm nginx-config -n nginx-ingress
Name:         nginx-config
Namespace:    nginx-ingress
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
・・・
Data
====
stream-snippets:
・・・

Events:
  Type    Reason   Age                From                      Message
  ----    ------   ----               ----                      -------
  Normal  Updated  46s (x4 over 26m)  nginx-ingress-controller  Configuration from nginx-ingress/nginx-config was updated
```

３．名前解決できるか dnstool コンテナを立ち上げて確認します。

```console:dnstool
$ kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
If you don't see a command prompt, try pressing enter.

# dig で確認
# dig @<dns サーバ IP ※今回はホストの IP> <検索対象 FQDN>
dnstools# dig @192.168.xx.xx kubernetes.io
・・・
;; ANSWER SECTION:
kubernetes.io.          30      IN      A       45.54.44.102
・・・

# Corefile で指定した静的DNSをひいてみる
dnstools# dig @192.168.xx.xx www.rancher.invalid
・・・
;; ANSWER SECTION:
www.rancher.invalid.    3600    IN      A       192.168.xx.xx
・・・
```

# おわりに
無事に名前解決まで確認できたでしょうか。
http/https の公開は ingress でできるのですが、他 TCP/UDP の公開時には今回のnginx-ingressも便利かと思います。