feat(external-dns): Move to Enterprise + add Docs (#14426)

**Description**

Tested and documented, let's get this to the Enterprise train

⚒️ Fixes  # <!--(issue)-->

**⚙️ Type of change**

- [ ] ⚙️ Feature/App addition
- [ ] 🪛 Bugfix
- [ ] ⚠️ Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] 🔃 Refactor of current code

**🧪 How Has This Been Tested?**
<!--
Please describe the tests that you ran to verify your changes. Provide
instructions so we can reproduce. Please also list any relevant details
for your test configuration
-->

**📃 Notes:**
<!-- Please enter any other relevant information here -->

**✔️ Checklist:**

- [ ] ⚖️ My code follows the style guidelines of this project
- [ ] 👀 I have performed a self-review of my own code
- [ ] #️⃣ I have commented my code, particularly in hard-to-understand
areas
- [ ] 📄 I have made corresponding changes to the documentation
- [ ] ⚠️ My changes generate no new warnings
- [ ] 🧪 I have added tests to this description that prove my fix is
effective or that my feature works
- [ ] ⬆️ I increased versions for any altered app according to semantic
versioning

** App addition**

If this PR is an app addition please make sure you have done the
following.

- [ ] 🪞 I have opened a PR on
[truecharts/containers](https://github.com/truecharts/containers) adding
the container to TrueCharts mirror repo.
- [ ] 🖼️ I have added an icon in the Chart's root directory called
`icon.png`

---

_Please don't blindly check all the boxes. Read them and only check
those that apply.
Those checkboxes are there for the reviewer to see what is this all
about and
the status of this PR with a quick glance._

---------

Signed-off-by: Kjeld Schouten <kjeld@schouten-lebbing.nl>
Co-authored-by: Kjeld Schouten <kjeld@schouten-lebbing.nl>
This commit is contained in:
StevenMcElligott
2023-11-07 11:13:27 -05:00
committed by GitHub
parent f0901dd9e4
commit dcc72ba211
17 changed files with 727 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
# helm-docs templates
*.gotmpl
# docs folder
/docs
# icon
icon.png

View File

@@ -0,0 +1 @@
# Changelog

View File

@@ -0,0 +1,28 @@
apiVersion: v2
appVersion: "0.13.6"
dependencies:
- name: common
repository: https://library-charts.truecharts.org
version: 14.2.3
deprecated: false
description: ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers.
home: https://truecharts.org/charts/enterprise/external-dns
icon: https://truecharts.org/img/hotlink-ok/chart-icons/external-dns.png
keywords:
- external-dns
- k8s
- kubernetes
kubeVersion: ">=1.16.0-0"
maintainers:
- email: info@truecharts.org
name: TrueCharts
url: https://truecharts.org
name: external-dns
sources:
- https://github.com/truecharts/charts/tree/master/charts/enterprise/external-dns
- https://github.com/kubernetes-sigs/external-dns
type: application
version: 1.0.0
annotations:
truecharts.org/category: networking
truecharts.org/SCALE-support: "true"

View File

@@ -0,0 +1,27 @@
# README
## General Info
TrueCharts can be installed as both *normal* Helm Charts or as Apps on TrueNAS SCALE.
However only installations using the TrueNAS SCALE Apps system are supported.
For more information about this App, please check the docs on the TrueCharts [website](https://truecharts.org/charts/incubator/)
**This chart is not maintained by the upstream project and any issues with the chart should be raised [here](https://github.com/truecharts/charts/issues/new/choose)**
## Support
- Please check our [quick-start guides for TrueNAS SCALE](https://truecharts.org/manual/SCALE/guides/scale-intro).
- See the [Website](https://truecharts.org)
- Check our [Discord](https://discord.gg/tVsPTHWTtr)
- Open a [issue](https://github.com/truecharts/charts/issues/new/choose)
---
## Sponsor TrueCharts
TrueCharts can only exist due to the incredible effort of our staff.
Please consider making a [donation](https://truecharts.org/sponsor) or contributing back to the project any way you can!
*All Rights Reserved - The TrueCharts Project*

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -0,0 +1,80 @@
# External-DNS Setup Guide
ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers.
## What it does?
Inspired by Kubernetes DNS, Kubernetes' cluster-internal DNS server, ExternalDNS makes Kubernetes resources discoverable via public DNS servers. Like KubeDNS, it retrieves a list of resources (Services, Ingresses, etc.) from the Kubernetes API to determine a desired list of DNS records. Unlike KubeDNS, however, it's not a DNS server itself, but merely configures other DNS providers accordingly—e.g. AWS Route 53 or Google Cloud DNS.
### Prerequisites (required for Support on TrueCharts Discord)
- Traefik
- Clusterissuer / Cert-manager installed (vital if exposed externally)
Please follow the [Getting Started](https://truecharts.org/manual/SCALE/guides/getting-started) guide on the [Truecharts](https://truecharts.org) website.
## Installation instructions
This guide will cover 2 scenarios, `Cloudflare` and `Pi-Hole` / `Pihole`, for more external DNS record providers, see [External-DNS Docs](https://github.com/kubernetes-sigs/external-dns/tree/master/docs/tutorials).
### Cloudflare
These instructions taken from [external-dns cloudflare tutorial](https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/cloudflare.md)
#### Step 1:
Enter `CF_API_TOKEN` (preferred) or `CF_API_EMAIL`/`CF_API_KEY`
![Cloudflare API Token](img/Cloudflare-API-token.png)
#### Step 2:
Enter preferences for Logs and DNS updates (I suggest >5m to prevent log spam) and select `cloudflare` as provider and select sources. I find `ingress` and `service` covers everything. If you want to filter by multiple domains add your `Domain Filter Entry`
![Cloudflare App Config 1](img/Cloudflare-App-Config-1.png)
I recommend using `noop` for `Registry Type` and leaving the rest as default, can add DNS Zone filters as necessary as well (see upstream/cloudflare docs).
![Cloudflare App Config 2](img/Cloudflare-App-Config-2.png)
#### Step 3:
Verify it works, check the logs for updates to DNS records
```2023-11-07 09:36:07.165596-05:00time="2023-11-07T09:36:07-05:00" level=info msg="Instantiating new Kubernetes client"
2023-11-07 09:36:07.165633-05:00time="2023-11-07T09:36:07-05:00" level=info msg="Using inCluster-config based on serviceaccount-token"
2023-11-07 09:36:07.165850-05:00time="2023-11-07T09:36:07-05:00" level=info msg="Created Kubernetes client https://172.17.0.1:443"
2023-11-07 09:36:08.958946-05:00time="2023-11-07T09:36:08-05:00" level=info msg="Changing record." action=CREATE record=seafile.DOMAIN.com ttl=1 type=A zone=d959ce24eb85d78a7f527b6150446335
```
If this works, you'll see DNS entries inside Cloudflare's DNS page.
### PiHole
#### Step 1
Ignore Provider Credentials, and skip straight to `App Configuration` and select `pihole`, add domain filters as necessary
![PiHole App Config 1](img/PiHole-Config-1.png)
Change to `noop` for `Registry Type` and add `PiHole Server Address` (default is `http://pihole.ix-pihole.svc.cluster.local:9089`) and `PiHole Server Password`
![PiHole App Config 2](img/PiHole-Config-2.png)
#### Step 2
Verify logs from `External-DNS` to see if it connects and updates `PiHole`
```d:false IBMCloudConfigFile:/etc/kubernetes/ibmcloud.json TencentCloudConfigFile:/etc/kubernetes/tencent-cloud.json TencentCloudZoneType: PiholeServer:http://pihole.ix-pihole.svc.cluster.local:9089 PiholePassword:****** PiholeTLSInsecureSkipVerify:false PluralCluster: PluralProvider:}"
2023-11-07 10:29:07.801555-05:00time="2023-11-07T10:29:07-05:00" level=info msg="Instantiating new Kubernetes client"
2023-11-07 10:29:07.801568-05:00time="2023-11-07T10:29:07-05:00" level=info msg="Using inCluster-config based on serviceaccount-token"
2023-11-07 10:29:07.801861-05:00time="2023-11-07T10:29:07-05:00" level=info msg="Created Kubernetes client https://172.17.0.1:443"
2023-11-07 10:29:08.008741-05:00time="2023-11-07T10:29:08-05:00" level=info msg="add firezone.DOMAIN.com IN A -> 192.168.88.105"
2023-11-07 10:29:10.048171-05:00time="2023-11-07T10:29:10-05:00" level=info msg="add scrutiny.DOMAN.com IN A -> 192.168.88.105"
```
Check `PiHole` GUI for A records under `Local DNS`
![PiHole-GUI](img/PiHole-GUI.png)
Enjoy!

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

View File

@@ -0,0 +1,350 @@
# Include{groups}
portals:
open:
# Include{portalLink}
questions:
# Include{global}
# Include{workload}
# Include{workloadDeployment}
# Include{replicas1}
# Include{podSpec}
# Include{containerMain}
- variable: env
label: "Provider Specific Credentials - Main Config Below"
schema:
additional_attrs: true
type: dict
attrs:
- variable: CF_API_TOKEN
label: Cloudflare API Token (preferred)
description: Cloudflare API Token, optimal when using with Cloudflare
schema:
type: string
default: ""
- variable: CF_API_KEY
label: Cloudflare API Key
description: Cloudflare API Key if not using the preferred API Token
schema:
type: string
default: ""
- variable: CF_API_EMAIL
label: Cloudflare API Email
description: Cloudflare API email if not using the preferred API Token
schema:
type: string
default: ""
- variable: DO_TOKEN
label: Digitalocean API Key
description: Needed for read / write access on Digitalocean
schema:
type: string
default: ""
- variable: DNSSIMPLE_OAUTH
label: DNS Simple OAUTH Key
description:
schema:
type: string
default: ""
- variable: LINODE_TOKEN
label: Linode PI Key
description: Needed for read / write access on Linode
schema:
type: string
default: ""
- variable: OVH_APPLICATION_KEY
label: OVH Application Key
description: OVH Application Key
schema:
type: string
default: ""
- variable: OVH_APPLICATION_SECRET
label: OVH Application Secret
description: OVH Application Secret
schema:
type: string
default: ""
- variable: OVH_CONSUMER_KEY
label: OVH Consumer Key
description: Your OVH Consumer key after validated link
schema:
type: string
default: ""
- variable: SCW_ACCESS_KEY
label: Scaleway Access Key
description: Your Scaleway Access Key
schema:
type: string
default: ""
- variable: SCW_SECRET_KEY
label: Scaleway Secret Key
description: Your Scaleway Secret Key
schema:
type: string
default: ""
# Include{containerBasic}
# Include{containerAdvanced}
# Include{containerConfig}
- variable: externaldns
group: App Configuration
label: External-DNS Configuration
schema:
additional_attrs: true
type: dict
attrs:
- variable: logLevel
label: Log Verbosity Level
description: How description the logs are, from info to debug.
schema:
type: string
required: true
default: info
enum:
- value: info
description: info
- value: warning
description: warning
- value: error
description: error
- value: panic
description: panic
- value: debug
description: debug
- value: fatal
description: fatal
- variable: logFormat
label: Log Format
description: Output logs in either text or Json
schema:
type: string
default: text
enum:
- value: text
description: text
- value: json
description: json
- variable: interval
label: The interval for DNS updates.
description: How often the DNS will you update your DNS records
schema:
type: string
default: 5m
- variable: provider
label: Provider
description: Provider where the upstream DNS records will be created, eg Cloudflare, Digitalocean or things such as pihole. Some providers need additional args set when using them, please refer to upstream documentation for their usage.
schema:
type: string
required: true
default: cloudflare
enum:
- value: akamai
description: akamai
- value: alibabacloud
description: alibabacloud
- value: aws
description: aws
- value: aws-sd
description: aws-sd
- value: azure
description: azure
- value: azure-dns
description: azure-dns
- value: azure-private-dns
description: azure-private-dns
- value: bluecat
description: bluecat
- value: civo
description: civo
- value: cloudflare
description: cloudflare
- value: coredns
description: coredns
- value: designate
description: designate
- value: digitalocean
description: digitalocean
- value: dnsimple
description: dnsimple
- value: dyn
description: dyn
- value: exoscale
description: exoscale
- value: gandi
description: gandi
- value: godaddy
description: godaddy
- value: google
description: google
- value: ibmcloud
description: ibmcloud
- value: infoblox
description: infoblox
- value: inmemory
description: inmemory
- value: linode
description: linode
- value: ns1
description: ns1
- value: oci
description: oci
- value: pdns
description: pdns
- value: pihole
description: pihole
- value: plural
description: plural
- value: rcodezero
description: rcodezero
- value: rdns
description: rdns
- value: rfc2136
description: rfc2136
- value: safedns
description: safedns
- value: scaleway
description: scaleway
- value: skydns
description: skydns
- value: tencentcloud
description: tencentcloud
- value: transip
description: transip
- value: ultradns
description: ultradns
- value: vinyldns
description: vinyldns
- value: vultr
description: vultr
- variable: sources
label: "Sources"
schema:
type: list
default: ["ingress"]
items:
- variable: source
label: source
schema:
type: string
required: true
default: ingress
enum:
- value: ingress
description: ingress
- value: service
description: service
- variable: domainFilters
label: Domain Filters
description: Limit possible target zones by domain suffixes.
schema:
type: list
default: []
items:
- variable: domainFilterEntry
label: Domain Filter Entry
schema:
type: string
default: ""
required: true
- variable: zoneidFilters
label: Cloudflare DNS Zone Filter (optional)
description: Limit possible target zones by zone IDs. (Optional)
schema:
type: list
show_if: [["provider", "=", "cloudflare"]]
default: []
items:
- variable: zoneidFilterEntry
label: Zone ID Filter Entry
schema:
type: string
default: ""
required: true
- variable: registry
label: Registry Type
description: Available registry types are txt, noop
schema:
type: string
default: noop
enum:
- value: txt
description: text
- value: noop
description: noop
- variable: policy
label: DNS Synchronization Policy
description: How DNS records are synchronized between sources and providers
schema:
type: string
default: upsert-only
enum:
- value: upsert-only
description: upsert-only
- value: sync
description: sync
- variable: txtOwnerId
label: txt Owner Id
description: TXT registry identifier.
schema:
type: string
default: ""
- variable: txtPrefix
label: txtPrefix
description: Prefix to create a TXT record with a name following the pattern prefix.<CNAME record>
schema:
type: string
default: ""
- variable: txtSuffix
label: txtSuffix
description: TXT Suffix to attach
schema:
type: string
default: ""
- variable: piholeServer
label: Pi-Hole Server Address
description: Actual adresss/FQDN of your Pi-Hole install, such as pihole-web.pihole.svc.cluster.local,
schema:
type: string
show_if: [["provider", "=", "pihole"]]
default: ""
- variable: piholePassword
label: Pi-Hole Server Passowrd
description: Password for Pi-Hole
schema:
type: string
show_if: [["provider", "=", "pihole"]]
private: true
default: ""
# Include{podOptions}
# Include{serviceExpertRoot}
# Include{serviceExpert}
# Include{serviceList}
# Include{persistenceList}
# Include{ingressList}
# Include{securityContextRoot}
- variable: runAsUser
label: "runAsUser"
description: "The UserID of the user running the application"
schema:
type: int
default: 568
- variable: runAsGroup
label: "runAsGroup"
description: "The groupID of the user running the application"
schema:
type: int
default: 568
# Include{securityContextContainer}
# Include{securityContextAdvanced}
# Include{securityContextPod}
- variable: fsGroup
label: "fsGroup"
description: "The group that should own ALL storage."
schema:
type: int
default: 568
# Include{resources}
# Include{advanced}
# Include{addons}
# Include{codeserver}
# Include{netshoot}
# Include{vpn}
# Include{documentation}

View File

@@ -0,0 +1 @@
{{- include "tc.v1.common.lib.chart.notes" $ -}}

View File

@@ -0,0 +1,50 @@
{{- define "externaldns.args" -}}
args:
{{- with .Values.externaldns.provider }}
- --provider={{ . }}
{{- end -}}
{{- with .Values.externaldns.zoneidFilters }}
- --zone-id-filter={{ . }}
{{- end -}}
{{- with .Values.externaldns.cloudflareProxied }}
- --cloudflare-proxied={{ . }}
{{- end }}
- --log-level={{ .Values.externaldns.logLevel }}
- --log-format={{ .Values.externaldns.logFormat }}
- --interval={{ .Values.externaldns.interval }}
{{- if .Values.externaldns.triggerLoopOnEvent }}
- --events
{{- end -}}
{{- range .Values.externaldns.sources }}
- --source={{ . }}
{{- end -}}
{{- with .Values.externaldns.policy }}
- --policy={{ . }}
{{- end -}}
{{- with .Values.externaldns.registry }}
- --registry={{ . }}
{{- end -}}
{{- with .Values.externaldns.txtOwnerId }}
- --txt-owner-id={{ . }}
{{- end -}}
{{- with .Values.externaldns.txtPrefix }}
- --txt-prefix={{ . }}
{{- end -}}
{{- if and (eq .Values.externaldns.txtPrefix "") (ne .Values.externaldns.txtSuffix "") }}
- --txt-suffix={{ .Values.externaldns.txtSuffix }}
{{- end -}}
{{- if .Values.externaldns.namespaced }}
- --namespace={{ include "tc.v1.common.lib.metadata.namespace" (dict "caller" "External-DNS" "rootCtx" $ "objectData" .Values) }}
{{- end -}}
{{- with .Values.externaldns.domainFilter }}
{{- range . -}}
- --domain-filter={{ . }}
{{- end -}}
{{- end -}}
{{- with .Values.externaldns.piholeServer }}
- --pihole-server={{ . }}
{{- end -}}
{{- with .Values.externaldns.piholePassword }}
- --pihole-password={{ . }}
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,9 @@
{{/* Make sure all variables are set properly */}}
{{- include "tc.v1.common.loader.init" . }}
{{- $newArgs := (include "externaldns.args" . | fromYaml) }}
{{- $args := concat ((get .Values.workload.main.podSpec.containers.main "args") | default list) $newArgs.args }}
{{- $_ := set .Values.workload.main.podSpec.containers.main "args" $args -}}
{{/* Render the templates */}}
{{ include "tc.v1.common.loader.apply" . }}

View File

@@ -0,0 +1,151 @@
image:
repository: tccr.io/truecharts/external-dns
pullPolicy: IfNotPresent
tag: v0.13.6@sha256:78c942addf7fbc79c384e55bed9a886706c748d744cedf6214d4a50dd7b76d54
externaldns:
logLevel: "info"
logFormat: "text"
interval: "1m"
provider: "inmemory"
sources:
- "service"
- "ingress"
domainFilters: []
zoneidFilters: []
cloudflareProxied: ""
registry: "txt"
policy: ""
piholeServer: ""
piholePassword: ""
triggerLoopOnEvent: "false"
txtOwnerId: ""
txtPrefix: ""
txtSuffix: ""
service:
main:
ports:
main:
protocol: http
targetPort: 7979
port: 7979
workload:
main:
podSpec:
containers:
main:
probes:
liveness:
path: "/healthz"
readiness:
path: "/healthz"
startup:
path: "/healthz"
env:
CF_API_TOKEN: ""
CF_API_KEY: ""
CF_API_EMAIL: ""
DO_TOKEN: ""
DNSIMPLE_OAUTH: ""
LINODE_TOKEN: ""
OVH_APPLICATION_KEY: ""
OVH_APPLICATION_SECRET: ""
OVH_CONSUMER_KEY: ""
SCW_ACCESS_KEY: ""
SCW_SECRET_KEY: ""
# -- Whether Role Based Access Control objects like roles and rolebindings should be created
rbac:
main:
enabled: true
primary: true
clusterWide: true
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["list","watch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["services","endpoints"]
verbs: ["get","watch","list"]
- apiGroups: ["extensions","networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get","watch","list"]
- apiGroups: ["networking.istio.io"]
resources: ["gateways"]
verbs: ["get","watch","list"]
- apiGroups: ["networking.istio.io"]
resources: ["virtualservices"]
verbs: ["get","watch","list"]
- apiGroups: ["getambassador.io"]
resources: ["hosts","ingresses"]
verbs: ["get","watch","list"]
- apiGroups: ["projectcontour.io"]
resources: ["httpproxies"]
verbs: ["get","watch","list"]
- apiGroups: ["externaldns.k8s.io"]
resources: ["dnsendpoints"]
verbs: ["get","watch","list"]
- apiGroups: ["externaldns.k8s.io"]
resources: ["dnsendpoints/status"]
verbs: ["*"]
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["gateways"]
verbs: ["get","watch","list"]
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["httproutes"]
verbs: ["get","watch","list"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get","watch","list"]
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["grpcroutes"]
verbs: ["get","watch","list"]
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["tlsroutes"]
verbs: ["get","watch","list"]
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["tcproutes"]
verbs: ["get","watch","list"]
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["udproutes"]
verbs: ["get","watch","list"]
- apiGroups: ["gloo.solo.io","gateway.solo.io"]
resources: ["proxies","virtualservices"]
verbs: ["get","watch","list"]
- apiGroups: ["configuration.konghq.com"]
resources: ["tcpingresses"]
verbs: ["get","watch","list"]
- apiGroups: ["traefik.containo.us", "traefik.io"]
resources: ["ingressroutes", "ingressroutetcps", "ingressrouteudps"]
verbs: ["get","watch","list"]
- apiGroups: ["route.openshift.io"]
resources: ["routes"]
verbs: ["get","watch","list"]
- apiGroups: ["zalando.org"]
resources: ["routegroups"]
verbs: ["get","watch","list"]
- apiGroups: ["zalando.org"]
resources: ["routegroups/status"]
verbs: ["patch","update"]
- apiGroups: ["cis.f5.com"]
resources: ["virtualservers"]
verbs: ["get","watch","list"]
# -- The service account the pods will use to interact with the Kubernetes API
serviceAccount:
main:
enabled: true
primary: true
podOptions:
automountServiceAccountToken: true
portal:
open:
enabled: false