---
title: ExternalDNSを使ってGKEからCloudFlareにIngressのDNSレコードを登録
tags: ["Kubernetes", "GKE", "CloudFlare"]
categories: ["Dev", "CaaS", "Kubernetes", "ExternalDNS"]
date: 2018-01-08T15:12:48Z
updated: 2018-01-08T15:12:48Z
---

### ExternalDNSについて

[ExternalDNS](https://github.com/kubernetes-incubator/external-dns)はKubernetesから外部のDNSサービスにService`type: LoadBalancer`やIngressのIPアドレスのDNSレコードを登録してくれます。

v0.4の段階では次のサービスに対応しています。

* [Google CloudDNS](https://cloud.google.com/dns/docs/)
* [AWS Route 53](https://aws.amazon.com/route53/)
* [AzureDNS](https://azure.microsoft.com/en-us/services/dns)
* [CloudFlare](https://www.cloudflare.com/de/dns)
* [DigitalOcean](https://www.digitalocean.com/products/networking)
* [DNSimple](https://dnsimple.com/)
* [Infoblox](https://www.infoblox.com/products/dns/)

このブログの証明書を見てもらえば分かりますが、私はCloudFlareを使ってSSL対応をしており、有償オプション($10/month)でDedicatedな証明書を使用しています。

<img width="300" src="https://user-images.githubusercontent.com/106908/34673767-cb2a65fa-f4c6-11e7-8fe7-7b610e5a7eda.png">

SANでマルチドメインを登録しまくっています。

<img width="300" src="https://user-images.githubusercontent.com/106908/34673814-eea9efb4-f4c6-11e7-8dbe-4cbae17f4a4b.png">

Kubernetesで`type: LoadBalancer`なサービスやIngressを作る時にAレコードを毎回CloudFlareに登録していて面倒だと思ってたので、このExternalDNSの仕組みはありがたいのです。
(自分でCloudFlareのAPIを叩く何かを作ろうと思っていました...)

### ExternalDNSのデプロイ

まずはExternalDNSのデプロイを使うために、`external-dns.yml`を作成します。

``` yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: external-dns
  namespace: kube-system
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: external-dns
    spec:
      containers:
      - name: external-dns
        image: registry.opensource.zalan.do/teapot/external-dns:v0.4.8
        args:
        - --source=service
        - --source=ingress
        - --domain-filter=ik.am # your domain managed by cloud flare
        - --provider=cloudflare
        - --cloudflare-proxied
        env:
        - name: CF_API_KEY
          valueFrom:
            secretKeyRef:
              name: cloudflare-secret
              key: cloudflare-api-key
        - name: CF_API_EMAIL
          valueFrom:
            secretKeyRef:
              name: cloudflare-secret
              key: cloudflare-api-email
```

`CF_API_KEY`と`CF_API_EMAIL`の内容は`cloudflare-secret.yml`に設定しておきます。

``` yaml
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-secret
  namespace: kube-system
type: Opaque
data:
  cloudflare-api-key: ********** # echo -n <CF_API_KEY> | base64
  cloudflare-api-email: ********** # echo -n <CF_API_EMAIL> | base64
```

これらをデプロイします。

```
kubectl apply -f cloudflare-secret.yml
kubectl apply -f external-dns.yml
```

これでExternalDNSのデプロイ完了です。

### 動作確認

動作確認として`nginx`をデプロイしてCloudFlareと連携できるか試します。次の`nginx.yml`を作成します。


``` yaml
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:
  type: NodePort
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
```

自分はCloudFlareの[Full SSLモード](https://support.cloudflare.com/hc/en-us/articles/200170416-What-do-the-SSL-options-mean-)を使っているので、Ingress側でもSSLの設定が必要です。Strictモードでなければ、Ingress側は自己証明書でOKです。

![image](https://user-images.githubusercontent.com/106908/34675514-36adab56-f4cd-11e7-9486-faacc8c8fad6.png)

```
kubectl create secret tls tls-secret -n default  --cert=public.crt  --key=private.key
# public.crtとprivate.keyは自己証明書でOK
```

> Flexibleモードを使えばGCP側でSSLの設定は不要になりますが、CloudFlare <-> GCP間の通信が平文になってしまい、イマイチです。

次にGCPでIngressのstatic ipを発行します。名前は`cloudflare-ingress`にします。

```
gcloud compute addresses create cloudflare-ingress --global
```

次にIngressの設定を書きます。次の`ingress.yml`を作成します。ホスト名はCloudFlare管理化のドメインにします。

``` yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: demo-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.global-static-ip-name: cloudflare-ingress
    ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
  - secretName: tls-secret
  rules:
  - host: nginx.ik.am
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80
```

これをデプロイします。


```
kubectl apply -f ingress.yml
```

しばらくすると、CloudFlare側にTXTレコードとAレコードが作成されます。AレコードにはIngressに設定したstatic ipが設定されます。

<img width="400" src="https://user-images.githubusercontent.com/106908/34673914-457dcb76-f4c7-11e7-81e6-cec04100e574.png">

Audit Logを見るとわかりやすいです。

<img width="400" src="https://user-images.githubusercontent.com/106908/34673823-f467bcb0-f4c6-11e7-9771-27b1fec66d2a.png">


しばらくするとGKE側のIngressのStatusがOKになり(遅い)、

![image](https://user-images.githubusercontent.com/106908/34675183-1ff577c8-f4cc-11e7-9b42-4a5af2007556.png)

[https://nginx.ik.am](https://nginx.ik.am)にアクセスできるようになります。

<img width="400" src="https://user-images.githubusercontent.com/106908/34674158-2e110a2e-f4c8-11e7-9d2c-c441f2d736dd.png">

---

Ingressを設定するだけでCloudFlareにAレコードが登録されることを確認できました。運用が少し楽になります。
Let's Encryptでも試してみたいところです。
