feat: add external-dns for managing public DNS records (#288)
This commit is contained in:
1 parent
c62dcbe8da
commit
6cbfd7cb9c
8 files changed
+86
-24
No files matched your search
@@ -22,6 +22,7 @@ Feel free to read up on any of these technologies before you get started to be m
|
|||||||
- [cert-manager](https://cert-manager.io/) - SSL certificates - with Cloudflare DNS challenge
|
- [cert-manager](https://cert-manager.io/) - SSL certificates - with Cloudflare DNS challenge
|
||||||
- [calico](https://www.tigera.io/project-calico/) - CNI (container network interface)
|
- [calico](https://www.tigera.io/project-calico/) - CNI (container network interface)
|
||||||
- [echo-server](https://github.com/Ealenn/Echo-Server) - REST Server Tests (Echo-Server) API (useful for debugging HTTP issues)
|
- [echo-server](https://github.com/Ealenn/Echo-Server) - REST Server Tests (Echo-Server) API (useful for debugging HTTP issues)
|
||||||
|
- [external-dns](https://github.com/kubernetes-sigs/external-dns) - Automatically configure external DNS servers for Kubernetes Ingresses and Services
|
||||||
- [flux](https://toolkit.fluxcd.io/) - GitOps tool for deploying manifests from the `cluster` directory
|
- [flux](https://toolkit.fluxcd.io/) - GitOps tool for deploying manifests from the `cluster` directory
|
||||||
- [hajimari](https://github.com/toboshii/hajimari) - start page with ingress discovery
|
- [hajimari](https://github.com/toboshii/hajimari) - start page with ingress discovery
|
||||||
- [k8s_gateway](https://github.com/ori-edge/k8s_gateway) - DNS resolver for all types of external Kubernetes resources
|
- [k8s_gateway](https://github.com/ori-edge/k8s_gateway) - DNS resolver for all types of external Kubernetes resources
|
||||||
@@ -309,19 +310,23 @@ kubectl --kubeconfig=./provision/kubeconfig get pods -n flux-system
|
|||||||
|
|
||||||
🎉 **Congratulations** if all goes smooth you'll have a Kubernetes cluster managed by Flux, your Git repository is driving the state of your cluster.
|
🎉 **Congratulations** if all goes smooth you'll have a Kubernetes cluster managed by Flux, your Git repository is driving the state of your cluster.
|
||||||
|
|
||||||
Now it's time to pause and go get some coffee ☕
|
Now it's time to pause and go get some coffee ☕ because next is describing how DNS is handled. 🧠
|
||||||
|
|
||||||
## 📣 Post installation
|
## 📣 Post installation
|
||||||
|
|
||||||
### 🌐 DNS
|
### 🌐 DNS
|
||||||
|
|
||||||
|
📍 The `external-dns` application created in the `networking` namespace will handle creating public DNS records. `echo-server` is the only public domain exposed on your Cloudflare domain. In order to make additional applications public you must set an ingress annotation like in the `HelmRelease` for `echo-server`. You do not need to use Terraform to create additional DNS records unless you a record outside the purposes of your Kubernetes cluster.
|
||||||
|
|
||||||
`k8s_gateway` is deployed on the IP choosen for `${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}`. Inorder to test DNS you can point your clients DNS to the `${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}` IP address and load `https://hajimari.${BOOTSTRAP_CLOUDFLARE_DOMAIN}` in your browser.
|
`k8s_gateway` is deployed on the IP choosen for `${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}`. Inorder to test DNS you can point your clients DNS to the `${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}` IP address and load `https://hajimari.${BOOTSTRAP_CLOUDFLARE_DOMAIN}` in your browser.
|
||||||
|
|
||||||
You can also try debugging with the command `dig`, e.g. `dig @${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR} hajimari.${BOOTSTRAP_CLOUDFLARE_DOMAIN}` and you should get a valid answer containing your `${BOOTSTRAP_METALLB_TRAEFIK_ADDR}` IP address.
|
You can also try debugging with the command `dig`, e.g. `dig @${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR} hajimari.${BOOTSTRAP_CLOUDFLARE_DOMAIN}` and you should get a valid answer containing your `${BOOTSTRAP_METALLB_TRAEFIK_ADDR}` IP address.
|
||||||
|
|
||||||
If your router (or Pi-Hole, Adguard Home or whatever) supports conditional DNS forwarding (also know as split-horizon DNS) you may have DNS requests for `${SECRET_DOMAIN}` only point to the `${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}` IP address. This will ensure only DNS requests for `${SECRET_DOMAIN}` will get routed to your `k8s_gateway` service.
|
If your router (or Pi-Hole, Adguard Home or whatever) supports conditional DNS forwarding (also know as split-horizon DNS) you may have DNS requests for `${SECRET_DOMAIN}` only point to the `${BOOTSTRAP_METALLB_K8S_GATEWAY_ADDR}` IP address. This will ensure only DNS requests for `${SECRET_DOMAIN}` will get routed to your `k8s_gateway` service.
|
||||||
|
|
||||||
To access services from the outside world port forwarded `80` and `443` in your router to the `${BOOTSTRAP_METALLB_TRAEFIK_ADDR}` IP, in a few moments head over to your browser and you _should_ be able to access `https://hajimari.${BOOTSTRAP_CLOUDFLARE_DOMAIN}` from a device outside your LAN.
|
To access services from the outside world port forwarded `80` and `443` in your router to the `${BOOTSTRAP_METALLB_TRAEFIK_ADDR}` IP, in a few moments head over to your browser and you _should_ be able to access `https://echo-server.${BOOTSTRAP_CLOUDFLARE_DOMAIN}` from a device outside your LAN.
|
||||||
|
|
||||||
|
Now if nothing is working, that is expected. This is DNS after all!
|
||||||
|
|
||||||
### 👉 Troubleshooting
|
### 👉 Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ spec:
|
|||||||
enabled: true
|
enabled: true
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: "letsencrypt-production"
|
cert-manager.io/cluster-issuer: "letsencrypt-production"
|
||||||
|
external-dns.alpha.kubernetes.io/target: "ipv4.${SECRET_DOMAIN}"
|
||||||
|
external-dns/is-public: "true"
|
||||||
hajimari.io/enable: "true"
|
hajimari.io/enable: "true"
|
||||||
hajimari.io/icon: "video-input-antenna"
|
hajimari.io/icon: "video-input-antenna"
|
||||||
traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
|
traefik.ingress.kubernetes.io/router.entrypoints: "websecure"
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
name: external-dns
|
||||||
|
namespace: networking
|
||||||
|
spec:
|
||||||
|
interval: 5m
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: external-dns
|
||||||
|
version: 1.8.0
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: external-dns-charts
|
||||||
|
namespace: flux-system
|
||||||
|
interval: 5m
|
||||||
|
install:
|
||||||
|
createNamespace: true
|
||||||
|
values:
|
||||||
|
interval: 5m
|
||||||
|
logLevel: debug
|
||||||
|
provider: cloudflare
|
||||||
|
env:
|
||||||
|
- name: CF_API_EMAIL
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: external-dns-cloud-credentials
|
||||||
|
key: email
|
||||||
|
- name: CF_API_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: external-dns-cloud-credentials
|
||||||
|
key: api-key
|
||||||
|
extraArgs:
|
||||||
|
- --cloudflare-proxied
|
||||||
|
- --annotation-filter=external-dns/is-public in (true)
|
||||||
|
policy: sync
|
||||||
|
sources:
|
||||||
|
- ingress
|
||||||
|
txtPrefix: "k8s."
|
||||||
|
txtOwnerId: "default"
|
||||||
|
domainFilters:
|
||||||
|
- "${SECRET_DOMAIN}"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: 100Mi
|
||||||
|
cpu: 25m
|
||||||
|
limits:
|
||||||
|
memory: 250Mi
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- helm-release.yaml
|
||||||
|
- secret.sops.yaml
|
||||||
@@ -3,5 +3,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1
|
|||||||
kind: Kustomization
|
kind: Kustomization
|
||||||
resources:
|
resources:
|
||||||
- cloudflare-ddns
|
- cloudflare-ddns
|
||||||
|
- external-dns
|
||||||
- k8s-gateway
|
- k8s-gateway
|
||||||
- traefik
|
- traefik
|
||||||
+11
-4
@@ -36,32 +36,39 @@ main() {
|
|||||||
verify_cloudflare
|
verify_cloudflare
|
||||||
success
|
success
|
||||||
else
|
else
|
||||||
# sops configuration file
|
# generate sops configuration file
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/.sops.yaml"
|
> "${PROJECT_DIR}/.sops.yaml"
|
||||||
# cluster
|
# generate cluster settings
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/cluster/cluster-settings.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/cluster/cluster-settings.yaml" \
|
||||||
> "${PROJECT_DIR}/cluster/base/cluster-settings.yaml"
|
> "${PROJECT_DIR}/cluster/base/cluster-settings.yaml"
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/cluster/gotk-sync.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/cluster/gotk-sync.yaml" \
|
||||||
> "${PROJECT_DIR}/cluster/base/flux-system/gotk-sync.yaml"
|
> "${PROJECT_DIR}/cluster/base/flux-system/gotk-sync.yaml"
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/cluster/kube-vip-daemonset.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/cluster/kube-vip-daemonset.yaml" \
|
||||||
> "${PROJECT_DIR}/cluster/core/kube-system/kube-vip/daemon-set.yaml"
|
> "${PROJECT_DIR}/cluster/core/kube-system/kube-vip/daemon-set.yaml"
|
||||||
|
# generate cluster secrets
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/cluster/cluster-secrets.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/cluster/cluster-secrets.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/cluster/base/cluster-secrets.sops.yaml"
|
> "${PROJECT_DIR}/cluster/base/cluster-secrets.sops.yaml"
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/cluster/cert-manager-secret.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/cluster/cert-manager-secret.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/cluster/core/cert-manager/secret.sops.yaml"
|
> "${PROJECT_DIR}/cluster/core/cert-manager/secret.sops.yaml"
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/cluster/cloudflare-ddns-secret.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/cluster/cloudflare-ddns-secret.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/cluster/apps/networking/cloudflare-ddns/secret.sops.yaml"
|
> "${PROJECT_DIR}/cluster/apps/networking/cloudflare-ddns/secret.sops.yaml"
|
||||||
|
envsubst < "${PROJECT_DIR}/tmpl/cluster/external-dns-secret.sops.yaml" \
|
||||||
|
> "${PROJECT_DIR}/cluster/apps/networking/external-dns/secret.sops.yaml"
|
||||||
|
# encrypt cluster secrets
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/cluster/base/cluster-secrets.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/cluster/base/cluster-secrets.sops.yaml"
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/cluster/core/cert-manager/secret.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/cluster/core/cert-manager/secret.sops.yaml"
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/cluster/apps/networking/cloudflare-ddns/secret.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/cluster/apps/networking/cloudflare-ddns/secret.sops.yaml"
|
||||||
# terraform
|
sops --encrypt --in-place "${PROJECT_DIR}/cluster/apps/networking/external-dns/secret.sops.yaml"
|
||||||
|
# generate terraform secrets
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/terraform/secret.sops.yaml" \
|
envsubst < "${PROJECT_DIR}/tmpl/terraform/secret.sops.yaml" \
|
||||||
> "${PROJECT_DIR}/provision/terraform/cloudflare/secret.sops.yaml"
|
> "${PROJECT_DIR}/provision/terraform/cloudflare/secret.sops.yaml"
|
||||||
|
# encrypt terraform secrets
|
||||||
sops --encrypt --in-place "${PROJECT_DIR}/provision/terraform/cloudflare/secret.sops.yaml"
|
sops --encrypt --in-place "${PROJECT_DIR}/provision/terraform/cloudflare/secret.sops.yaml"
|
||||||
# ansible
|
# generate ansible settings
|
||||||
envsubst < "${PROJECT_DIR}/tmpl/ansible/kube-vip.yml" \
|
envsubst < "${PROJECT_DIR}/tmpl/ansible/kube-vip.yml" \
|
||||||
> "${PROJECT_DIR}/provision/ansible/inventory/group_vars/kubernetes/kube-vip.yml"
|
> "${PROJECT_DIR}/provision/ansible/inventory/group_vars/kubernetes/kube-vip.yml"
|
||||||
|
# generate ansible hosts file and secrets
|
||||||
generate_ansible_hosts
|
generate_ansible_hosts
|
||||||
generate_ansible_host_secrets
|
generate_ansible_host_secrets
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -99,21 +99,3 @@ resource "cloudflare_record" "root" {
|
|||||||
type = "CNAME"
|
type = "CNAME"
|
||||||
ttl = 1
|
ttl = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "cloudflare_record" "hajimari" {
|
|
||||||
name = "hajimari"
|
|
||||||
zone_id = lookup(data.cloudflare_zones.domain.zones[0], "id")
|
|
||||||
value = "ipv4.${data.sops_file.cloudflare_secrets.data["cloudflare_domain"]}"
|
|
||||||
proxied = true
|
|
||||||
type = "CNAME"
|
|
||||||
ttl = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "cloudflare_record" "echo_server" {
|
|
||||||
name = "echo-server"
|
|
||||||
zone_id = lookup(data.cloudflare_zones.domain.zones[0], "id")
|
|
||||||
value = "ipv4.${data.sops_file.cloudflare_secrets.data["cloudflare_domain"]}"
|
|
||||||
proxied = true
|
|
||||||
type = "CNAME"
|
|
||||||
ttl = 1
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# yamllint disable
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: external-dns-cloud-credentials
|
||||||
|
namespace: networking
|
||||||
|
stringData:
|
||||||
|
email: ${BOOTSTRAP_CLOUDFLARE_EMAIL}
|
||||||
|
api-key: ${BOOTSTRAP_CLOUDFLARE_APIKEY}
|
||||||
Reference in new issue
Block a user