external-dnsをさくらのクラウドで使う

kubernetes-incubator/external-dnsって何?

KubernetesでServiceやIngressなどの作成/更新を検知してDNSレコードを動的に設定してくれるexternal-dnsというプロダクトがkubernetes-incubator配下にあります。

github.com

例えば以下のようなIngressを作成するとnginx.example.orgというホスト名に対応するAレコードを作成してくれます。

kind: Ingress
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: nginx.example.org
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80

external-dnsの特徴的な点として、データソース(ServiceやIngressなど)とレコード作成先(プロバイダーと呼ばれている)が分離されており、 それぞれを任意の組み合わせで利用することが可能という点があります。 これにより様々なプラットフォームを統一的な手段でサポートできるようになっています。

データソースとしてはService/Ingressだけでなく、istio-gateway独自のCRD(Custom Resource Definitions)などがあり、 レコードの作成先については以下のような様々なプラットフォームがサポートされています。

external-dns v0.5時点で対応しているプロバイダー

これがさくらのクラウドに対応していませんでしたので今回forkして対応してみました。

github.com

当記事ではさくらのクラウドでのexternal-dnsの使い方について紹介します。
(なお今の所はupstreamへのマージは考えてません。使いたいという方が増えたら考えます。)

external-dnsさくらのクラウドで使う

準備作業

まずはKubernetesクラスターの準備やさくらのクラウドDNSに管理対象のゾーンを登録しておく必要があります。

KubernetesクラスターについてはRancher2セットアップというスタートアップスクリプトが提供されていますのでそちらを利用して準備しておきます。

以下の記事などが参考になるかと思います。

febc-yamamoto.hatenablog.jp

qiita.com

また、さくらのクラウドへのDNSゾーン登録も必要です。
こちらは以下のスライドなどが参考になるかと思います。

www.slideshare.net

sacloud/external-dnsのデプロイ

準備が出来たらexternal-dnsをデプロイします。

manifestは以下のようになります。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","watch","list"]
- apiGroups: ["extensions"] 
  resources: ["ingresses"] 
  verbs: ["get","watch","list"]
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: default
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: external-dns
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: sacloud/external-dns:latest
        args:
        - --source=service 
        - --source=ingress
        - --domain-filter=example.com # (optional, but we highly recommended to set this) limit to only example.com domains; change to match the zone created above.
        - --provider=sakuracloud
        env:
        - name: SAKURACLOUD_ACCESS_TOKEN
          value: "YOUR_API_KEY"
        - name: SAKURACLOUD_ACCESS_TOKEN_SECRET
          value: "YOUR_API_SECRET"

上の方がRBACの設定、Deploymentのcontainersの部分がexternal-dnsのコンテナの定義となっています。

RBACを使わない場合については以下のドキュメントを参照してください
external-dns/sakuracloud.md at master · sacloud/external-dns · GitHub

external-dnsのコンテナ定義部分だけ抜粋

      containers:
      - name: external-dns
        image: sacloud/external-dns:latest
        args:
        - --source=service 
        - --source=ingress
        - --domain-filter=example.com # (optional, but we highly recommended to set this) limit to only example.com domains; change to match the zone created above.
        - --provider=sakuracloud
        env:
        - name: SAKURACLOUD_ACCESS_TOKEN
          value: "YOUR_API_KEY"
        - name: SAKURACLOUD_ACCESS_TOKEN_SECRET
          value: "YOUR_API_SECRET"

以下の部分は各自で任意の値を設定してください。

この例では以下のような指定を行なっています。

動作確認

動作確認のためnginxコンテナをデプロイし、Ingressで外部からアクセスできるようにします。

まずはPodとServiceをデプロイします。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

続いてIngressをデプロイします。
ここではFQDNとしてexternal-dns.example.comを指定しています。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-example
  namespace: default
spec:
  rules:
  - host: external-dns.example.com
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80

しばらく待つと対象のゾーンにAレコードとTXTレコードが追加されているのがコントロールパネルなどで確認できます。 後は指定したFQDNに対してアクセスするとNGINXのデフォルトページが表示されるはずです。

後片付け

Ingressを削除すると対応するDNSレコードも削除されるようになっています。
(この動作はexternal-dnsのオプション--policyにデフォルトでsyncが指定されているためです)

終わりに

external-dnsを利用することでKubernetes側の操作だけでDNSレコードの登録/変更/破棄が行えます。
頻繁にアプリケーションのデプロイ/DNSレコードの更新を行うけど、 さくらのクラウドのコントロールパネル/APIヘのアクセスは集中管理したい/触れる人を限定したい、といった場合などで便利だと思います。

ぜひご利用ください。

以上です。