feat: добавить аддон technitium-dns — HA DNS Primary+Secondary с kube-vip LB и zone sync
- Helm chart: Primary и Secondary Deployment, kube-vip LoadBalancer сервисы (UDP+TCP :53), ClusterIP для Web UI, PVC (ReadWriteOnce), Secret, Ingress - CronJob sync (*/5 мин): Python sync.py опрашивает Technitium REST API, создаёт Secondary зоны на secondary и вызывает forceSyncZone для каждой зоны - ExternalDNS (disabled по умолчанию): RFC 2136 DDNS для автоматических DNS-записей из Ingress - Ansible role: validate, namespace, Helm deploy, cleanup secrets, summary с Keenetic-инструкцией - Интеграция: Makefile, playbooks/addons.yml, group_vars/all/addons.yml, vault.yml.example - README с архитектурой, Keenetic-конфигурацией и troubleshooting
This commit is contained in:
6
Makefile
6
Makefile
@@ -58,7 +58,7 @@ DOCKER_RUN := docker run --rm -it \
|
|||||||
addon-harbor addon-gitea addon-owncloud addon-nextcloud \
|
addon-harbor addon-gitea addon-owncloud addon-nextcloud \
|
||||||
addon-csi-s3 addon-csi-ceph addon-csi-glusterfs addon-vaultwarden \
|
addon-csi-s3 addon-csi-ceph addon-csi-glusterfs addon-vaultwarden \
|
||||||
addon-smtp-relay addon-vault addon-external-secrets \
|
addon-smtp-relay addon-vault addon-external-secrets \
|
||||||
addon-jenkins addon-netbird addon-mediaserver addon-hysteria2-server addon-splitgw addon-ingress-proxypass addon-ingress-add-domains addon-yandex-dns-controller \
|
addon-jenkins addon-netbird addon-mediaserver addon-hysteria2-server addon-splitgw addon-ingress-proxypass addon-ingress-add-domains addon-yandex-dns-controller addon-technitium-dns \
|
||||||
add-node remove-node \
|
add-node remove-node \
|
||||||
add-etcd-node remove-etcd-node \
|
add-etcd-node remove-etcd-node \
|
||||||
etcd-backup etcd-restore etcd-list-snapshots \
|
etcd-backup etcd-restore etcd-list-snapshots \
|
||||||
@@ -432,6 +432,10 @@ addon-yandex-dns-controller: _check_env _check_image ## Yandex 360 DNS controlle
|
|||||||
@printf "$(CYAN)Устанавливаю Yandex 360 DNS Controller...$(NC)\n"
|
@printf "$(CYAN)Устанавливаю Yandex 360 DNS Controller...$(NC)\n"
|
||||||
$(DOCKER_RUN) addon yandex-dns-controller $(ARGS)
|
$(DOCKER_RUN) addon yandex-dns-controller $(ARGS)
|
||||||
|
|
||||||
|
addon-technitium-dns: _check_env _check_image ## Technitium DNS HA — Primary+Secondary, kube-vip LB, zone sync
|
||||||
|
@printf "$(CYAN)Устанавливаю Technitium DNS HA...$(NC)\n"
|
||||||
|
$(DOCKER_RUN) addon technitium-dns $(ARGS)
|
||||||
|
|
||||||
# Generic цель — любой аддон из addons/<name>/playbook.yml
|
# Generic цель — любой аддон из addons/<name>/playbook.yml
|
||||||
addon-%: _check_env _check_image
|
addon-%: _check_env _check_image
|
||||||
@if [ ! -f "addons/$*/playbook.yml" ]; then \
|
@if [ ! -f "addons/$*/playbook.yml" ]; then \
|
||||||
|
|||||||
173
addons/technitium-dns/README.md
Normal file
173
addons/technitium-dns/README.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
# technitium-dns
|
||||||
|
|
||||||
|
Highly-available internal DNS based on [Technitium DNS Server](https://technitium.com/dns/).
|
||||||
|
|
||||||
|
Deploys Primary + optional Secondary instance, each behind a **kube-vip** `LoadBalancer` service with a static IP. A `CronJob` syncs all Primary zones to Secondary automatically every 5 minutes via the Technitium REST API.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Clients (Keenetic / DHCP)
|
||||||
|
│
|
||||||
|
├─ DNS 192.168.1.53 → technitium-dns-primary (Deployment, RWO PVC)
|
||||||
|
└─ DNS 192.168.1.54 → technitium-dns-secondary (Deployment, RWO PVC)
|
||||||
|
|
||||||
|
CronJob sync (*/5 min): primary REST API → list zones → create missing Secondary zones on secondary → forceSync
|
||||||
|
|
||||||
|
Web UI (Ingress):
|
||||||
|
http://dns.home.local → primary :5380
|
||||||
|
http://dns-secondary.home.local → secondary :5380
|
||||||
|
|
||||||
|
ExternalDNS (optional, disabled by default):
|
||||||
|
Watches Ingress/Service → RFC 2136 DDNS → primary → AXFR → secondary
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
### 1. Set vault password
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/all/vault.yml (encrypted with ansible-vault)
|
||||||
|
technitium_dns_admin_password: "your-strong-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Enable and configure
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/all/addons.yml
|
||||||
|
addon_technitium_dns: true
|
||||||
|
|
||||||
|
technitium_dns_primary_ip: "192.168.1.53" # kube-vip managed IP
|
||||||
|
technitium_dns_secondary_ip: "192.168.1.54"
|
||||||
|
technitium_dns_domain: "home.local"
|
||||||
|
technitium_dns_primary_host: "dns.home.local"
|
||||||
|
technitium_dns_secondary_host: "dns-secondary.home.local"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make addon-technitium-dns
|
||||||
|
# or:
|
||||||
|
ansible-playbook playbooks/addons.yml --tags technitium-dns
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Create the internal zone (first time only)
|
||||||
|
|
||||||
|
Open `http://dns.home.local/` → login as `admin` → **Zones → Add Zone → Primary** → enter `home.local`.
|
||||||
|
|
||||||
|
Then add `A` records for your services under `home.local`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Keenetic router — DNS configuration
|
||||||
|
|
||||||
|
In Keenetic web interface: **Internet → DNS servers**
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
|-------|-------|
|
||||||
|
| Primary DNS | `192.168.1.53` |
|
||||||
|
| Secondary DNS | `192.168.1.54` |
|
||||||
|
|
||||||
|
Or via Keenetic CLI:
|
||||||
|
```
|
||||||
|
ip name-server 192.168.1.53
|
||||||
|
ip name-server 192.168.1.54
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Zone sync (Primary → Secondary)
|
||||||
|
|
||||||
|
The `technitium-dns-sync` `CronJob` runs every 5 minutes. It:
|
||||||
|
|
||||||
|
1. Logs in to both instances with the shared admin password.
|
||||||
|
2. Lists all `Primary` and `Forwarder` zones on primary.
|
||||||
|
3. Creates missing zones on secondary as `Secondary` type pointing to `primary.ip`.
|
||||||
|
4. Calls `forceSyncZone` for every zone.
|
||||||
|
|
||||||
|
Manual trigger:
|
||||||
|
```bash
|
||||||
|
kubectl create job --from=cronjob/technitium-dns-sync sync-manual-1 \
|
||||||
|
-n technitium-dns
|
||||||
|
kubectl -n technitium-dns logs -l app.kubernetes.io/component=sync -f
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ExternalDNS (optional)
|
||||||
|
|
||||||
|
Automatically creates DNS records on primary from `Ingress` and `Service` resources via **RFC 2136 DDNS**. Secondary picks up changes via the sync CronJob.
|
||||||
|
|
||||||
|
### Enable
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/all/addons.yml
|
||||||
|
technitium_dns_externaldns_enabled: true
|
||||||
|
technitium_dns_externaldns_domain_filter:
|
||||||
|
- "home.local"
|
||||||
|
technitium_dns_externaldns_policy: "upsert-only" # or "sync" to also delete
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enable DDNS on zones in Technitium
|
||||||
|
|
||||||
|
For each zone that ExternalDNS should write to:
|
||||||
|
|
||||||
|
1. Open Web UI → Zones → `home.local` → **Zone Settings**
|
||||||
|
2. **Dynamic Updates** → set to `Allow` (or `Allow Signed` for TSIG)
|
||||||
|
3. Save.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Variables reference
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| `technitium_dns_primary_ip` | `192.168.1.53` | kube-vip LB IP for primary |
|
||||||
|
| `technitium_dns_secondary_enabled` | `true` | Deploy secondary instance |
|
||||||
|
| `technitium_dns_secondary_ip` | `192.168.1.54` | kube-vip LB IP for secondary |
|
||||||
|
| `technitium_dns_primary_node` | `""` | Pin primary to node hostname |
|
||||||
|
| `technitium_dns_secondary_node` | `""` | Pin secondary to node hostname |
|
||||||
|
| `technitium_dns_domain` | `home.local` | Local DNS domain |
|
||||||
|
| `technitium_dns_forwarders` | `[1.1.1.1, 8.8.8.8]` | Upstream resolvers |
|
||||||
|
| `technitium_dns_recursion` | `AllowOnlyForPrivateNetworks` | Recursion mode |
|
||||||
|
| `technitium_dns_admin_password` | — | **In vault.yml** — admin password |
|
||||||
|
| `technitium_dns_storage_class` | `""` | StorageClass (empty = cluster default) |
|
||||||
|
| `technitium_dns_storage_size` | `1Gi` | PVC size per instance |
|
||||||
|
| `technitium_dns_ingress_enabled` | `true` | Expose Web UI via Ingress |
|
||||||
|
| `technitium_dns_primary_host` | `dns.home.local` | Primary Web UI hostname |
|
||||||
|
| `technitium_dns_secondary_host` | `dns-secondary.home.local` | Secondary Web UI hostname |
|
||||||
|
| `technitium_dns_sync_enabled` | `true` | Enable zone sync CronJob |
|
||||||
|
| `technitium_dns_sync_schedule` | `*/5 * * * *` | Sync frequency |
|
||||||
|
| `technitium_dns_externaldns_enabled` | `false` | Deploy ExternalDNS |
|
||||||
|
| `technitium_dns_externaldns_policy` | `upsert-only` | ExternalDNS sync policy |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**DNS not resolving after deploy**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check pods are Running
|
||||||
|
kubectl -n technitium-dns get pods
|
||||||
|
|
||||||
|
# Test DNS resolution from a pod
|
||||||
|
kubectl run dnstest --rm -it --image=busybox -- nslookup kubernetes.default 192.168.1.53
|
||||||
|
```
|
||||||
|
|
||||||
|
**Sync job failing**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n technitium-dns logs -l app.kubernetes.io/component=sync --tail=100
|
||||||
|
```
|
||||||
|
|
||||||
|
Common cause: secondary is not yet ready when the first sync runs. The job will retry on the next schedule.
|
||||||
|
|
||||||
|
**Secondary shows stale records**
|
||||||
|
|
||||||
|
Force a manual sync (see above). If secondary zone type is wrong, delete the zone on secondary and let sync recreate it.
|
||||||
|
|
||||||
|
**kube-vip IP not assigned**
|
||||||
|
|
||||||
|
Ensure the IP is in the kube-vip address pool (check `kube-vip` ConfigMap or CiliumLoadBalancerIPPool) and not already in use.
|
||||||
7
addons/technitium-dns/playbook.yml
Normal file
7
addons/technitium-dns/playbook.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- name: Install Technitium DNS HA
|
||||||
|
hosts: k3s_master[0]
|
||||||
|
gather_facts: false
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
- role: "{{ playbook_dir }}/role"
|
||||||
15
addons/technitium-dns/role/chart/Chart.yaml
Normal file
15
addons/technitium-dns/role/chart/Chart.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: technitium-dns
|
||||||
|
description: |
|
||||||
|
HA DNS сервер на базе Technitium DNS Server для K3s homelab.
|
||||||
|
Primary + Secondary инстансы с автоматической синхронизацией зон.
|
||||||
|
Интеграция с kube-vip (LoadBalancer), ingress-nginx (Web UI) и ExternalDNS (RFC 2136).
|
||||||
|
type: application
|
||||||
|
version: 1.0.0
|
||||||
|
appVersion: "13"
|
||||||
|
keywords:
|
||||||
|
- dns
|
||||||
|
- technitium
|
||||||
|
- ha
|
||||||
|
- homelab
|
||||||
|
home: https://git.antropoff.ru/DevOpsTools/K3S
|
||||||
150
addons/technitium-dns/role/chart/files/sync.py
Normal file
150
addons/technitium-dns/role/chart/files/sync.py
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Technitium DNS zone sync: ensures secondary has all Primary/Forwarder zones
|
||||||
|
from primary as Secondary zones pointing back to primary's LoadBalancer IP.
|
||||||
|
|
||||||
|
Required env vars:
|
||||||
|
PRIMARY_URL http://technitium-dns-primary-web.technitium-dns:5380
|
||||||
|
SECONDARY_URL http://technitium-dns-secondary-web.technitium-dns:5380
|
||||||
|
ADMIN_PASSWORD shared admin password
|
||||||
|
PRIMARY_LB_IP LB IP of primary (for AXFR source in secondary zones)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format="%(asctime)s %(levelname)s %(message)s",
|
||||||
|
datefmt="%H:%M:%S",
|
||||||
|
)
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
PRIMARY_URL = os.environ["PRIMARY_URL"].rstrip("/")
|
||||||
|
SECONDARY_URL = os.environ["SECONDARY_URL"].rstrip("/")
|
||||||
|
ADMIN_PASSWORD = os.environ["ADMIN_PASSWORD"]
|
||||||
|
PRIMARY_LB_IP = os.environ["PRIMARY_LB_IP"]
|
||||||
|
|
||||||
|
SESSION_PRIMARY = requests.Session()
|
||||||
|
SESSION_SECONDARY = requests.Session()
|
||||||
|
|
||||||
|
# Zone types that should be replicated to secondary
|
||||||
|
SYNC_TYPES = {"Primary", "Forwarder"}
|
||||||
|
|
||||||
|
|
||||||
|
def login(session: requests.Session, base_url: str, password: str) -> str:
|
||||||
|
r = session.get(
|
||||||
|
f"{base_url}/api/user/login",
|
||||||
|
params={"user": "admin", "pass": password, "includeInfo": "false"},
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
body = r.json()
|
||||||
|
if body.get("status") != "ok":
|
||||||
|
raise RuntimeError(f"Login failed at {base_url}: {body}")
|
||||||
|
token = body["response"]["token"]
|
||||||
|
log.info("Logged in to %s", base_url)
|
||||||
|
return token
|
||||||
|
|
||||||
|
|
||||||
|
def list_zones(session: requests.Session, base_url: str, token: str) -> list[dict]:
|
||||||
|
r = session.get(
|
||||||
|
f"{base_url}/api/zones/list",
|
||||||
|
params={"token": token},
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
body = r.json()
|
||||||
|
if body.get("status") != "ok":
|
||||||
|
raise RuntimeError(f"list_zones failed: {body}")
|
||||||
|
return body["response"]["zones"]
|
||||||
|
|
||||||
|
|
||||||
|
def create_secondary_zone(
|
||||||
|
session: requests.Session, base_url: str, token: str, zone: str, primary_ip: str
|
||||||
|
) -> None:
|
||||||
|
r = session.post(
|
||||||
|
f"{base_url}/api/zones/create",
|
||||||
|
params={
|
||||||
|
"token": token,
|
||||||
|
"zone": zone,
|
||||||
|
"type": "Secondary",
|
||||||
|
"primaryNameServerAddresses": primary_ip,
|
||||||
|
},
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
body = r.json()
|
||||||
|
if body.get("status") != "ok":
|
||||||
|
raise RuntimeError(f"create zone {zone!r} failed: {body}")
|
||||||
|
log.info("Created secondary zone: %s (primary=%s)", zone, primary_ip)
|
||||||
|
|
||||||
|
|
||||||
|
def force_sync(
|
||||||
|
session: requests.Session, base_url: str, token: str, zone: str
|
||||||
|
) -> None:
|
||||||
|
r = session.post(
|
||||||
|
f"{base_url}/api/zones/forceSyncZone",
|
||||||
|
params={"token": token, "zone": zone},
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
body = r.json()
|
||||||
|
if body.get("status") != "ok":
|
||||||
|
log.warning("forceSyncZone %s returned non-ok: %s", zone, body)
|
||||||
|
else:
|
||||||
|
log.info("Forced sync: %s", zone)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
tok_primary = login(SESSION_PRIMARY, PRIMARY_URL, ADMIN_PASSWORD)
|
||||||
|
tok_secondary = login(SESSION_SECONDARY, SECONDARY_URL, ADMIN_PASSWORD)
|
||||||
|
|
||||||
|
primary_zones = list_zones(SESSION_PRIMARY, PRIMARY_URL, tok_primary)
|
||||||
|
secondary_zones = list_zones(SESSION_SECONDARY, SECONDARY_URL, tok_secondary)
|
||||||
|
|
||||||
|
secondary_names = {z["name"] for z in secondary_zones}
|
||||||
|
|
||||||
|
stats = {"created": 0, "synced": 0, "skipped": 0, "errors": 0}
|
||||||
|
|
||||||
|
for zone in primary_zones:
|
||||||
|
name = zone["name"]
|
||||||
|
ztype = zone.get("type", "")
|
||||||
|
|
||||||
|
if ztype not in SYNC_TYPES:
|
||||||
|
stats["skipped"] += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if name not in secondary_names:
|
||||||
|
try:
|
||||||
|
create_secondary_zone(
|
||||||
|
SESSION_SECONDARY, SECONDARY_URL, tok_secondary, name, PRIMARY_LB_IP
|
||||||
|
)
|
||||||
|
stats["created"] += 1
|
||||||
|
# Re-fetch token after zone creation is not needed; force sync right away
|
||||||
|
force_sync(SESSION_SECONDARY, SECONDARY_URL, tok_secondary, name)
|
||||||
|
stats["synced"] += 1
|
||||||
|
except Exception as exc:
|
||||||
|
log.error("Failed to create/sync zone %s: %s", name, exc)
|
||||||
|
stats["errors"] += 1
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
force_sync(SESSION_SECONDARY, SECONDARY_URL, tok_secondary, name)
|
||||||
|
stats["synced"] += 1
|
||||||
|
except Exception as exc:
|
||||||
|
log.error("Failed to force-sync zone %s: %s", name, exc)
|
||||||
|
stats["errors"] += 1
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
"Done — created=%d synced=%d skipped=%d errors=%d",
|
||||||
|
stats["created"], stats["synced"], stats["skipped"], stats["errors"],
|
||||||
|
)
|
||||||
|
|
||||||
|
if stats["errors"] > 0:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
38
addons/technitium-dns/role/chart/templates/NOTES.txt
Normal file
38
addons/technitium-dns/role/chart/templates/NOTES.txt
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
╔══════════════════════════════════════════════════════════════╗
|
||||||
|
║ Technitium DNS HA — Deployed ║
|
||||||
|
╚══════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
Primary DNS:
|
||||||
|
LoadBalancer IP : {{ .Values.primary.ip }}
|
||||||
|
Web UI : http://{{ .Values.ingress.primary.host }}/
|
||||||
|
API : http://{{ .Values.primary.ip }}:5380/
|
||||||
|
|
||||||
|
{{- if .Values.secondary.enabled }}
|
||||||
|
Secondary DNS:
|
||||||
|
LoadBalancer IP : {{ .Values.secondary.ip }}
|
||||||
|
Web UI : http://{{ .Values.ingress.secondary.host }}/
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Configure Keenetic router (or DHCP server) to use:
|
||||||
|
Primary DNS : {{ .Values.primary.ip }}
|
||||||
|
{{- if .Values.secondary.enabled }}
|
||||||
|
Secondary DNS : {{ .Values.secondary.ip }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
First-time setup (create your internal zone):
|
||||||
|
kubectl -n {{ .Release.Namespace }} exec -it deploy/{{ include "technitium-dns.name" . }}-primary -- \
|
||||||
|
curl -s "http://localhost:5380/api/zones/create?token=\$TOKEN&zone={{ .Values.dns.domain }}&type=Primary"
|
||||||
|
|
||||||
|
Zone sync CronJob (primary → secondary):
|
||||||
|
{{- if and .Values.sync.enabled .Values.secondary.enabled }}
|
||||||
|
kubectl -n {{ .Release.Namespace }} create job --from=cronjob/{{ include "technitium-dns.name" . }}-sync sync-manual-1
|
||||||
|
kubectl -n {{ .Release.Namespace }} logs -l app.kubernetes.io/component=sync --tail=50
|
||||||
|
{{- else }}
|
||||||
|
(disabled — set sync.enabled=true and secondary.enabled=true to enable)
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Logs:
|
||||||
|
kubectl -n {{ .Release.Namespace }} logs -l app.kubernetes.io/component=primary -f
|
||||||
|
{{- if .Values.secondary.enabled }}
|
||||||
|
kubectl -n {{ .Release.Namespace }} logs -l app.kubernetes.io/component=secondary -f
|
||||||
|
{{- end }}
|
||||||
18
addons/technitium-dns/role/chart/templates/_helpers.tpl
Normal file
18
addons/technitium-dns/role/chart/templates/_helpers.tpl
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{{- define "technitium-dns.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "technitium-dns.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "technitium-dns.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "technitium-dns.chart" . }}
|
||||||
|
{{ include "technitium-dns.selectorLabels" . }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "technitium-dns.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "technitium-dns.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{{- if and .Values.sync.enabled .Values.secondary.enabled }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-sync
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
data:
|
||||||
|
sync.py: |
|
||||||
|
{{ .Files.Get "files/sync.py" | indent 4 }}
|
||||||
|
{{- end }}
|
||||||
53
addons/technitium-dns/role/chart/templates/cronjob-sync.yaml
Normal file
53
addons/technitium-dns/role/chart/templates/cronjob-sync.yaml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{{- if and .Values.sync.enabled .Values.secondary.enabled }}
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-sync
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
schedule: {{ .Values.sync.schedule | quote }}
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 3
|
||||||
|
failedJobsHistoryLimit: 3
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
backoffLimit: 2
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 12 }}
|
||||||
|
app.kubernetes.io/component: sync
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: sync
|
||||||
|
image: {{ .Values.sync.image }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
command:
|
||||||
|
- python3
|
||||||
|
- /scripts/sync.py
|
||||||
|
env:
|
||||||
|
- name: PRIMARY_URL
|
||||||
|
value: "http://{{ include "technitium-dns.name" . }}-primary-web.{{ .Release.Namespace }}:5380"
|
||||||
|
- name: SECONDARY_URL
|
||||||
|
value: "http://{{ include "technitium-dns.name" . }}-secondary-web.{{ .Release.Namespace }}:5380"
|
||||||
|
- name: PRIMARY_LB_IP
|
||||||
|
value: {{ .Values.primary.ip | quote }}
|
||||||
|
- name: ADMIN_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secret
|
||||||
|
key: adminPassword
|
||||||
|
volumeMounts:
|
||||||
|
- name: scripts
|
||||||
|
mountPath: /scripts
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.sync.resources | nindent 16 }}
|
||||||
|
volumes:
|
||||||
|
- name: scripts
|
||||||
|
configMap:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-sync
|
||||||
|
defaultMode: 0755
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-primary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
# Recreate is required for ReadWriteOnce PVCs — ensures old pod is fully
|
||||||
|
# terminated before new pod mounts the volume.
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
spec:
|
||||||
|
{{- if .Values.primary.nodeName }}
|
||||||
|
# Hard pin to specific node
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: {{ .Values.primary.nodeName | quote }}
|
||||||
|
{{- else }}
|
||||||
|
# Soft anti-affinity: prefer different node than secondary
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 100
|
||||||
|
podAffinityTerm:
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 20 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: dns
|
||||||
|
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: dns-udp
|
||||||
|
containerPort: 53
|
||||||
|
protocol: UDP
|
||||||
|
- name: dns-tcp
|
||||||
|
containerPort: 53
|
||||||
|
protocol: TCP
|
||||||
|
- name: web-ui
|
||||||
|
containerPort: 5380
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
# Set admin password on first boot (stored in config after that)
|
||||||
|
- name: DNS_SERVER_ADMIN_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secret
|
||||||
|
key: adminPassword
|
||||||
|
- name: DNS_SERVER_DOMAIN
|
||||||
|
value: {{ printf "dns1.%s" .Values.dns.domain | quote }}
|
||||||
|
# Upstream forwarders for queries outside managed zones
|
||||||
|
- name: DNS_SERVER_FORWARDERS
|
||||||
|
value: {{ .Values.dns.forwarders | join "," | quote }}
|
||||||
|
- name: DNS_SERVER_RECURSION
|
||||||
|
value: {{ .Values.dns.recursion | quote }}
|
||||||
|
- name: DNS_SERVER_LOCAL_END_POINTS
|
||||||
|
value: "0.0.0.0:53"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /etc/dns
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 5380
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 5380
|
||||||
|
initialDelaySeconds: 45
|
||||||
|
periodSeconds: 20
|
||||||
|
failureThreshold: 3
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "technitium-dns.name" . }}-primary
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
{{- if .Values.secondary.enabled }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secondary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
spec:
|
||||||
|
{{- if .Values.secondary.nodeName }}
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: {{ .Values.secondary.nodeName | quote }}
|
||||||
|
{{- else }}
|
||||||
|
# Soft anti-affinity: prefer different node than primary
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 100
|
||||||
|
podAffinityTerm:
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 20 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: dns
|
||||||
|
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: dns-udp
|
||||||
|
containerPort: 53
|
||||||
|
protocol: UDP
|
||||||
|
- name: dns-tcp
|
||||||
|
containerPort: 53
|
||||||
|
protocol: TCP
|
||||||
|
- name: web-ui
|
||||||
|
containerPort: 5380
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: DNS_SERVER_ADMIN_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secret
|
||||||
|
key: adminPassword
|
||||||
|
- name: DNS_SERVER_DOMAIN
|
||||||
|
value: {{ printf "dns2.%s" .Values.dns.domain | quote }}
|
||||||
|
- name: DNS_SERVER_FORWARDERS
|
||||||
|
value: {{ .Values.dns.forwarders | join "," | quote }}
|
||||||
|
- name: DNS_SERVER_RECURSION
|
||||||
|
value: {{ .Values.dns.recursion | quote }}
|
||||||
|
- name: DNS_SERVER_LOCAL_END_POINTS
|
||||||
|
value: "0.0.0.0:53"
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /etc/dns
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 5380
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 5380
|
||||||
|
initialDelaySeconds: 45
|
||||||
|
periodSeconds: 20
|
||||||
|
failureThreshold: 3
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "technitium-dns.name" . }}-secondary
|
||||||
|
{{- end }}
|
||||||
83
addons/technitium-dns/role/chart/templates/externaldns.yaml
Normal file
83
addons/technitium-dns/role/chart/templates/externaldns.yaml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{{- if .Values.externalDns.enabled }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-external-dns
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-external-dns
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["services", "endpoints", "pods", "nodes"]
|
||||||
|
verbs: ["get", "watch", "list"]
|
||||||
|
- apiGroups: ["extensions", "networking.k8s.io"]
|
||||||
|
resources: ["ingresses"]
|
||||||
|
verbs: ["get", "watch", "list"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-external-dns
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: {{ include "technitium-dns.name" . }}-external-dns
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: {{ include "technitium-dns.name" . }}-external-dns
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-external-dns
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: external-dns
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: external-dns
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: external-dns
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ include "technitium-dns.name" . }}-external-dns
|
||||||
|
containers:
|
||||||
|
- name: external-dns
|
||||||
|
image: {{ .Values.externalDns.image }}
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
args:
|
||||||
|
- --source=ingress
|
||||||
|
- --source=service
|
||||||
|
- --provider=rfc2136
|
||||||
|
- --rfc2136-host={{ .Values.primary.ip }}
|
||||||
|
- --rfc2136-port=53
|
||||||
|
- --rfc2136-zone={{ .Values.dns.domain }}
|
||||||
|
- --rfc2136-insecure
|
||||||
|
- --txt-owner-id={{ .Values.externalDns.txtOwnerId }}
|
||||||
|
- --policy={{ .Values.externalDns.policy }}
|
||||||
|
- --log-level=info
|
||||||
|
{{- range .Values.externalDns.domainFilter }}
|
||||||
|
- --domain-filter={{ . }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.externalDns.resources | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
64
addons/technitium-dns/role/chart/templates/ingress.yaml
Normal file
64
addons/technitium-dns/role/chart/templates/ingress.yaml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
---
|
||||||
|
# Ingress for primary Web UI
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-primary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: {{ .Values.ingress.ingressClass | quote }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls.enabled }}
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- {{ .Values.ingress.primary.host | quote }}
|
||||||
|
secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-primary-tls" (include "technitium-dns.name" .)) | quote }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.ingress.primary.host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-primary-web
|
||||||
|
port:
|
||||||
|
number: 5380
|
||||||
|
{{- if .Values.secondary.enabled }}
|
||||||
|
---
|
||||||
|
# Ingress for secondary Web UI
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secondary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: {{ .Values.ingress.ingressClass | quote }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.tls.enabled }}
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- {{ .Values.ingress.secondary.host | quote }}
|
||||||
|
secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-secondary-tls" (include "technitium-dns.name" .)) | quote }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.ingress.secondary.host | quote }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secondary-web
|
||||||
|
port:
|
||||||
|
number: 5380
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
40
addons/technitium-dns/role/chart/templates/pvc.yaml
Normal file
40
addons/technitium-dns/role/chart/templates/pvc.yaml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
# PVC for primary instance
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-primary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.storage.accessMode }}
|
||||||
|
{{- if .Values.storage.storageClassName }}
|
||||||
|
storageClassName: {{ .Values.storage.storageClassName | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.storage.size }}
|
||||||
|
{{- if .Values.secondary.enabled }}
|
||||||
|
---
|
||||||
|
# PVC for secondary instance
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secondary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- {{ .Values.storage.accessMode }}
|
||||||
|
{{- if .Values.storage.storageClassName }}
|
||||||
|
storageClassName: {{ .Values.storage.storageClassName | quote }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.storage.size }}
|
||||||
|
{{- end }}
|
||||||
10
addons/technitium-dns/role/chart/templates/secret.yaml
Normal file
10
addons/technitium-dns/role/chart/templates/secret.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secret
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
adminPassword: {{ .Values.secret.adminPassword | b64enc | quote }}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
# DNS LoadBalancer service — kube-vip assigns the static IP.
|
||||||
|
# Exposes UDP/53 + TCP/53 (requires K3s 1.26+ for MixedProtocol, which is the default).
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-primary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
annotations:
|
||||||
|
kube-vip.io/loadbalancerIPs: {{ .Values.primary.ip | quote }}
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
# Local preserves client source IP and avoids extra hop through kube-proxy
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
selector:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
ports:
|
||||||
|
- name: dns-udp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: UDP
|
||||||
|
- name: dns-tcp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
# ClusterIP service for Web UI — used as Ingress backend
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-primary-web
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: primary
|
||||||
|
ports:
|
||||||
|
- name: web-ui
|
||||||
|
port: 5380
|
||||||
|
targetPort: 5380
|
||||||
|
protocol: TCP
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{{- if .Values.secondary.enabled }}
|
||||||
|
---
|
||||||
|
# DNS LoadBalancer service for secondary
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secondary
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
annotations:
|
||||||
|
kube-vip.io/loadbalancerIPs: {{ .Values.secondary.ip | quote }}
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
selector:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
ports:
|
||||||
|
- name: dns-udp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: UDP
|
||||||
|
- name: dns-tcp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
# ClusterIP service for secondary Web UI
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "technitium-dns.name" . }}-secondary-web
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "technitium-dns.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "technitium-dns.selectorLabels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: secondary
|
||||||
|
ports:
|
||||||
|
- name: web-ui
|
||||||
|
port: 5380
|
||||||
|
targetPort: 5380
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
97
addons/technitium-dns/role/chart/values.yaml
Normal file
97
addons/technitium-dns/role/chart/values.yaml
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# Technitium DNS HA — default values
|
||||||
|
# Override via group_vars/all/addons.yml → technitium_dns_* variables
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: technitium/dns-server
|
||||||
|
tag: "13"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# ── Primary instance ──────────────────────────────────────────────────────────
|
||||||
|
primary:
|
||||||
|
# Static IP for kube-vip LoadBalancer (DNS port 53)
|
||||||
|
ip: "192.168.1.53"
|
||||||
|
# Pin to specific K8s node hostname (empty = use soft podAntiAffinity)
|
||||||
|
nodeName: ""
|
||||||
|
|
||||||
|
# ── Secondary instance ────────────────────────────────────────────────────────
|
||||||
|
secondary:
|
||||||
|
enabled: true
|
||||||
|
ip: "192.168.1.54"
|
||||||
|
nodeName: ""
|
||||||
|
|
||||||
|
# ── DNS server config ─────────────────────────────────────────────────────────
|
||||||
|
dns:
|
||||||
|
# Domain served locally (e.g. home.local)
|
||||||
|
domain: "home.local"
|
||||||
|
# Upstream forwarders for unknown queries
|
||||||
|
forwarders:
|
||||||
|
- "1.1.1.1"
|
||||||
|
- "8.8.8.8"
|
||||||
|
# AllowOnlyForPrivateNetworks | Allow | Deny
|
||||||
|
recursion: "AllowOnlyForPrivateNetworks"
|
||||||
|
|
||||||
|
# ── Admin credentials ─────────────────────────────────────────────────────────
|
||||||
|
secret:
|
||||||
|
adminPassword: "" # filled from Ansible vault (technitium_dns_admin_password)
|
||||||
|
|
||||||
|
# ── Persistent storage ────────────────────────────────────────────────────────
|
||||||
|
storage:
|
||||||
|
# StorageClass: empty = cluster default. "nfs-master01" recommended if NFS is set up.
|
||||||
|
storageClassName: ""
|
||||||
|
size: "1Gi"
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
|
||||||
|
# ── Web UI via ingress-nginx ──────────────────────────────────────────────────
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClass: nginx
|
||||||
|
primary:
|
||||||
|
host: "dns.home.local"
|
||||||
|
secondary:
|
||||||
|
host: "dns-secondary.home.local"
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
secretName: ""
|
||||||
|
|
||||||
|
# ── Resource limits ───────────────────────────────────────────────────────────
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# ── Zone sync CronJob (primary → secondary via AXFR) ─────────────────────────
|
||||||
|
# Ensures secondary has all zones from primary as Secondary (AXFR) zones.
|
||||||
|
sync:
|
||||||
|
enabled: true
|
||||||
|
schedule: "*/5 * * * *"
|
||||||
|
image: "python:3.11-slim"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
# ── ExternalDNS via RFC 2136 DDNS (optional) ─────────────────────────────────
|
||||||
|
# Watches Ingress resources and creates DNS records on primary automatically.
|
||||||
|
# Requires DDNS enabled on Technitium zones: Zone Settings → Dynamic Updates.
|
||||||
|
externalDns:
|
||||||
|
enabled: false
|
||||||
|
image: "registry.k8s.io/external-dns/external-dns:v0.14.2"
|
||||||
|
# DNS zones to manage
|
||||||
|
domainFilter:
|
||||||
|
- "home.local"
|
||||||
|
# sync = manage records (add+delete), upsert-only = only add
|
||||||
|
policy: "upsert-only"
|
||||||
|
txtOwnerId: "k3s-home"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
51
addons/technitium-dns/role/defaults/main.yml
Normal file
51
addons/technitium-dns/role/defaults/main.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
# ── Namespace ─────────────────────────────────────────────────────────────────
|
||||||
|
technitium_dns_namespace: technitium-dns
|
||||||
|
technitium_dns_release_name: technitium-dns
|
||||||
|
|
||||||
|
# ── Primary DNS LoadBalancer IP (kube-vip) ────────────────────────────────────
|
||||||
|
technitium_dns_primary_ip: "192.168.1.53"
|
||||||
|
technitium_dns_primary_node: "" # pin to hostname, empty = soft anti-affinity
|
||||||
|
|
||||||
|
# ── Secondary DNS (optional HA) ───────────────────────────────────────────────
|
||||||
|
technitium_dns_secondary_enabled: true
|
||||||
|
technitium_dns_secondary_ip: "192.168.1.54"
|
||||||
|
technitium_dns_secondary_node: ""
|
||||||
|
|
||||||
|
# ── DNS domain served locally ─────────────────────────────────────────────────
|
||||||
|
technitium_dns_domain: "home.local"
|
||||||
|
|
||||||
|
# ── Upstream forwarders ───────────────────────────────────────────────────────
|
||||||
|
technitium_dns_forwarders:
|
||||||
|
- "1.1.1.1"
|
||||||
|
- "8.8.8.8"
|
||||||
|
|
||||||
|
# ── Recursion policy ──────────────────────────────────────────────────────────
|
||||||
|
# AllowOnlyForPrivateNetworks | Allow | Deny
|
||||||
|
technitium_dns_recursion: "AllowOnlyForPrivateNetworks"
|
||||||
|
|
||||||
|
# ── Admin password — set in vault.yml: technitium_dns_admin_password ──────────
|
||||||
|
# technitium_dns_admin_password: ""
|
||||||
|
|
||||||
|
# ── Storage ───────────────────────────────────────────────────────────────────
|
||||||
|
technitium_dns_storage_class: "" # empty = cluster default
|
||||||
|
technitium_dns_storage_size: "1Gi"
|
||||||
|
|
||||||
|
# ── Web UI via Ingress ────────────────────────────────────────────────────────
|
||||||
|
technitium_dns_ingress_enabled: true
|
||||||
|
technitium_dns_ingress_class: nginx
|
||||||
|
technitium_dns_primary_host: "dns.home.local"
|
||||||
|
technitium_dns_secondary_host: "dns-secondary.home.local"
|
||||||
|
technitium_dns_ingress_tls_enabled: false
|
||||||
|
technitium_dns_ingress_tls_secret: ""
|
||||||
|
|
||||||
|
# ── Zone sync CronJob (primary → secondary) ───────────────────────────────────
|
||||||
|
technitium_dns_sync_enabled: true
|
||||||
|
technitium_dns_sync_schedule: "*/5 * * * *"
|
||||||
|
|
||||||
|
# ── ExternalDNS via RFC 2136 DDNS (optional) ─────────────────────────────────
|
||||||
|
technitium_dns_externaldns_enabled: false
|
||||||
|
technitium_dns_externaldns_domain_filter:
|
||||||
|
- "home.local"
|
||||||
|
technitium_dns_externaldns_policy: "upsert-only"
|
||||||
|
technitium_dns_externaldns_txt_owner_id: "k3s-home"
|
||||||
147
addons/technitium-dns/role/tasks/main.yml
Normal file
147
addons/technitium-dns/role/tasks/main.yml
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
---
|
||||||
|
# ── Validate inputs ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Validate technitium_dns_admin_password is set
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- technitium_dns_admin_password is defined
|
||||||
|
- technitium_dns_admin_password | length >= 8
|
||||||
|
fail_msg: >
|
||||||
|
technitium_dns_admin_password must be set in vault.yml (minimum 8 characters).
|
||||||
|
|
||||||
|
- name: Validate primary IP is set
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- technitium_dns_primary_ip | length > 0
|
||||||
|
fail_msg: >
|
||||||
|
technitium_dns_primary_ip must be set to a kube-vip-managed static IP.
|
||||||
|
|
||||||
|
# ── Create namespace ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Create technitium-dns namespace
|
||||||
|
ansible.builtin.command: >
|
||||||
|
k3s kubectl create namespace {{ technitium_dns_namespace }}
|
||||||
|
--dry-run=client -o yaml | k3s kubectl apply -f -
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
# ── Copy Helm chart to master ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Ensure chart temp directory is clean
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/technitium-dns-chart
|
||||||
|
state: absent
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Create chart temp directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/technitium-dns-chart
|
||||||
|
state: directory
|
||||||
|
mode: "0755"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Copy Helm chart to master
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ role_path }}/chart/"
|
||||||
|
dest: /tmp/technitium-dns-chart/
|
||||||
|
mode: preserve
|
||||||
|
become: true
|
||||||
|
|
||||||
|
# ── Template Helm values ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Template Helm values
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: values.yaml.j2
|
||||||
|
dest: /tmp/technitium-dns-values.yaml
|
||||||
|
mode: "0600"
|
||||||
|
become: true
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
# ── Lint chart ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Lint Helm chart
|
||||||
|
ansible.builtin.command: >
|
||||||
|
helm lint /tmp/technitium-dns-chart
|
||||||
|
--values /tmp/technitium-dns-values.yaml
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
register: _helm_lint
|
||||||
|
failed_when: _helm_lint.rc != 0
|
||||||
|
|
||||||
|
# ── Deploy chart ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Deploy technitium-dns via Helm
|
||||||
|
ansible.builtin.command: >
|
||||||
|
helm upgrade --install {{ technitium_dns_release_name }}
|
||||||
|
/tmp/technitium-dns-chart
|
||||||
|
--namespace {{ technitium_dns_namespace }}
|
||||||
|
--values /tmp/technitium-dns-values.yaml
|
||||||
|
--atomic
|
||||||
|
--wait
|
||||||
|
--timeout 180s
|
||||||
|
become: true
|
||||||
|
register: _helm_result
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
# ── Cleanup temp values file (contains password) ──────────────────────────────
|
||||||
|
|
||||||
|
- name: Remove temp values file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/technitium-dns-values.yaml
|
||||||
|
state: absent
|
||||||
|
become: true
|
||||||
|
|
||||||
|
# ── Wait for primary to be ready ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Wait for primary pod to be Running
|
||||||
|
ansible.builtin.command: >
|
||||||
|
k3s kubectl -n {{ technitium_dns_namespace }} rollout status
|
||||||
|
deployment/technitium-dns-primary --timeout=120s
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
# ── Get deployment status ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Get pod status
|
||||||
|
ansible.builtin.command: >
|
||||||
|
k3s kubectl -n {{ technitium_dns_namespace }} get pods,svc -o wide
|
||||||
|
become: true
|
||||||
|
changed_when: false
|
||||||
|
register: _pod_status
|
||||||
|
|
||||||
|
# ── Summary ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: "=== technitium-dns Ready ==="
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg:
|
||||||
|
- "╔══════════════════════════════════════════════════════════════╗"
|
||||||
|
- "║ Technitium DNS HA — Deployed ║"
|
||||||
|
- "╚══════════════════════════════════════════════════════════════╝"
|
||||||
|
- ""
|
||||||
|
- " Namespace : {{ technitium_dns_namespace }}"
|
||||||
|
- " Primary IP : {{ technitium_dns_primary_ip }} (DNS UDP/TCP :53)"
|
||||||
|
- " Primary UI : http://{{ technitium_dns_primary_host }}/"
|
||||||
|
- "{% if technitium_dns_secondary_enabled %}"
|
||||||
|
- " Secondary IP : {{ technitium_dns_secondary_ip }} (DNS UDP/TCP :53)"
|
||||||
|
- " Secondary UI : http://{{ technitium_dns_secondary_host }}/"
|
||||||
|
- "{% endif %}"
|
||||||
|
- ""
|
||||||
|
- " Keenetic router DNS settings:"
|
||||||
|
- " Primary DNS : {{ technitium_dns_primary_ip }}"
|
||||||
|
- "{% if technitium_dns_secondary_enabled %}"
|
||||||
|
- " Secondary DNS : {{ technitium_dns_secondary_ip }}"
|
||||||
|
- "{% endif %}"
|
||||||
|
- ""
|
||||||
|
- " Pods:"
|
||||||
|
- "{{ _pod_status.stdout_lines | to_yaml }}"
|
||||||
|
- ""
|
||||||
|
- " Create a local zone (first time only):"
|
||||||
|
- " Open http://{{ technitium_dns_primary_host }}/"
|
||||||
|
- " Login: admin / <vault password>"
|
||||||
|
- " Zones → Add Zone → Primary → {{ technitium_dns_domain }}"
|
||||||
|
- ""
|
||||||
|
- " Manual zone sync trigger:"
|
||||||
|
- "{% if technitium_dns_sync_enabled and technitium_dns_secondary_enabled %}"
|
||||||
|
- " kubectl create job --from=cronjob/technitium-dns-sync sync-manual-1 \\"
|
||||||
|
- " -n {{ technitium_dns_namespace }}"
|
||||||
|
- "{% endif %}"
|
||||||
47
addons/technitium-dns/role/templates/values.yaml.j2
Normal file
47
addons/technitium-dns/role/templates/values.yaml.j2
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Generated by Ansible — do not edit manually.
|
||||||
|
# Configure via: group_vars/all/addons.yml → technitium_dns_* variables.
|
||||||
|
# Admin password from vault.yml → technitium_dns_admin_password
|
||||||
|
|
||||||
|
primary:
|
||||||
|
ip: {{ technitium_dns_primary_ip | quote }}
|
||||||
|
nodeName: {{ technitium_dns_primary_node | quote }}
|
||||||
|
|
||||||
|
secondary:
|
||||||
|
enabled: {{ technitium_dns_secondary_enabled | string | lower }}
|
||||||
|
ip: {{ technitium_dns_secondary_ip | quote }}
|
||||||
|
nodeName: {{ technitium_dns_secondary_node | quote }}
|
||||||
|
|
||||||
|
dns:
|
||||||
|
domain: {{ technitium_dns_domain | quote }}
|
||||||
|
forwarders:
|
||||||
|
{{ technitium_dns_forwarders | to_yaml | indent(4, True) }}
|
||||||
|
recursion: {{ technitium_dns_recursion | quote }}
|
||||||
|
|
||||||
|
secret:
|
||||||
|
adminPassword: {{ technitium_dns_admin_password | quote }}
|
||||||
|
|
||||||
|
storage:
|
||||||
|
storageClassName: {{ technitium_dns_storage_class | quote }}
|
||||||
|
size: {{ technitium_dns_storage_size | quote }}
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: {{ technitium_dns_ingress_enabled | string | lower }}
|
||||||
|
ingressClass: {{ technitium_dns_ingress_class | quote }}
|
||||||
|
primary:
|
||||||
|
host: {{ technitium_dns_primary_host | quote }}
|
||||||
|
secondary:
|
||||||
|
host: {{ technitium_dns_secondary_host | quote }}
|
||||||
|
tls:
|
||||||
|
enabled: {{ technitium_dns_ingress_tls_enabled | string | lower }}
|
||||||
|
secretName: {{ technitium_dns_ingress_tls_secret | quote }}
|
||||||
|
|
||||||
|
sync:
|
||||||
|
enabled: {{ technitium_dns_sync_enabled | string | lower }}
|
||||||
|
schedule: {{ technitium_dns_sync_schedule | quote }}
|
||||||
|
|
||||||
|
externalDns:
|
||||||
|
enabled: {{ technitium_dns_externaldns_enabled | string | lower }}
|
||||||
|
domainFilter:
|
||||||
|
{{ technitium_dns_externaldns_domain_filter | to_yaml | indent(4, True) }}
|
||||||
|
policy: {{ technitium_dns_externaldns_policy | quote }}
|
||||||
|
txtOwnerId: {{ technitium_dns_externaldns_txt_owner_id | quote }}
|
||||||
@@ -9,8 +9,8 @@ addon_nfs_server: false # NFS сервер
|
|||||||
addon_csi_nfs: false # CSI NFS Driver + StorageClass
|
addon_csi_nfs: false # CSI NFS Driver + StorageClass
|
||||||
addon_ingress_nginx: true # ingress-nginx (Ingress controller)
|
addon_ingress_nginx: true # ingress-nginx (Ingress controller)
|
||||||
addon_cert_manager: false # cert-manager (TLS через Let's Encrypt)
|
addon_cert_manager: false # cert-manager (TLS через Let's Encrypt)
|
||||||
addon_metrics_server: true # metrics-server (kubectl top nodes/pods)
|
addon_metrics_server: false # metrics-server (kubectl top nodes/pods)
|
||||||
addon_prometheus_stack: true # Prometheus + Grafana + Alertmanager
|
addon_prometheus_stack: false # Prometheus + Grafana + Alertmanager
|
||||||
addon_istio: false # Istio service mesh + Kiali UI
|
addon_istio: false # Istio service mesh + Kiali UI
|
||||||
addon_argocd: false # ArgoCD (GitOps)
|
addon_argocd: false # ArgoCD (GitOps)
|
||||||
addon_longhorn: false # Longhorn (distributed block storage)
|
addon_longhorn: false # Longhorn (distributed block storage)
|
||||||
@@ -44,6 +44,7 @@ addon_splitgw: false # Split Gateway — прозрачный пр
|
|||||||
addon_ingress_proxypass: false # External Services Ingress Proxy — проксировать внешние сервисы через ingress-nginx
|
addon_ingress_proxypass: false # External Services Ingress Proxy — проксировать внешние сервисы через ingress-nginx
|
||||||
addon_ingress_add_domains: false # Ingress-only — добавить домены к существующим сервисам кластера
|
addon_ingress_add_domains: false # Ingress-only — добавить домены к существующим сервисам кластера
|
||||||
addon_yandex_dns_controller: false # Yandex 360 DNS controller — управление DNS через ConfigMap (safe mode)
|
addon_yandex_dns_controller: false # Yandex 360 DNS controller — управление DNS через ConfigMap (safe mode)
|
||||||
|
addon_technitium_dns: false # Technitium DNS HA — Primary+Secondary с kube-vip LB, зональный sync
|
||||||
|
|
||||||
# ─── NFS Server ───────────────────────────────────────────────────────────────
|
# ─── NFS Server ───────────────────────────────────────────────────────────────
|
||||||
nfs_exports:
|
nfs_exports:
|
||||||
@@ -358,6 +359,28 @@ minio_api_ingress_host: "s3.example.com"
|
|||||||
# netbird_exit_node_enabled: false
|
# netbird_exit_node_enabled: false
|
||||||
# После установки — настрой маршруты в Management UI
|
# После установки — настрой маршруты в Management UI
|
||||||
|
|
||||||
|
# ─── Technitium DNS HA ───────────────────────────────────────────────────────
|
||||||
|
# Self-hosted Primary+Secondary DNS с kube-vip LoadBalancer IP и авто-синхронизацией зон.
|
||||||
|
# Пароль задаётся в vault.yml: technitium_dns_admin_password
|
||||||
|
# technitium_dns_primary_ip: "192.168.1.53" # статический IP для primary DNS (kube-vip)
|
||||||
|
# technitium_dns_secondary_enabled: true
|
||||||
|
# technitium_dns_secondary_ip: "192.168.1.54" # статический IP для secondary DNS (kube-vip)
|
||||||
|
# technitium_dns_primary_node: "" # pinned hostname (пусто = soft anti-affinity)
|
||||||
|
# technitium_dns_secondary_node: ""
|
||||||
|
# technitium_dns_domain: "home.local" # локальная DNS-зона
|
||||||
|
# technitium_dns_forwarders: ["1.1.1.1", "8.8.8.8"]
|
||||||
|
# technitium_dns_recursion: "AllowOnlyForPrivateNetworks" # Allow | Deny | AllowOnlyForPrivateNetworks
|
||||||
|
# technitium_dns_primary_host: "dns.home.local" # Web UI через ingress
|
||||||
|
# technitium_dns_secondary_host: "dns-secondary.home.local"
|
||||||
|
# technitium_dns_ingress_enabled: true
|
||||||
|
# technitium_dns_ingress_tls_enabled: false
|
||||||
|
# technitium_dns_sync_schedule: "*/5 * * * *" # как часто синхронизировать зоны primary→secondary
|
||||||
|
# ExternalDNS (автоматические DNS-записи из Ingress/Service):
|
||||||
|
# technitium_dns_externaldns_enabled: false
|
||||||
|
# technitium_dns_externaldns_domain_filter: ["home.local"]
|
||||||
|
# technitium_dns_externaldns_policy: "upsert-only" # sync | upsert-only
|
||||||
|
# technitium_dns_externaldns_txt_owner_id: "k3s-home"
|
||||||
|
|
||||||
# ─── etcd backup ──────────────────────────────────────────────────────────────
|
# ─── etcd backup ──────────────────────────────────────────────────────────────
|
||||||
etcd_backup_dir: "{{ k3s_data_dir }}/server/db/snapshots"
|
etcd_backup_dir: "{{ k3s_data_dir }}/server/db/snapshots"
|
||||||
etcd_backup_retention: 5 # сколько снимков хранить
|
etcd_backup_retention: 5 # сколько снимков хранить
|
||||||
|
|||||||
@@ -132,3 +132,6 @@ vault_transmission_password: "changeme-transmission"
|
|||||||
yandex_dns:
|
yandex_dns:
|
||||||
org_id: "3312086"
|
org_id: "3312086"
|
||||||
token: "y0_ЗАМЕНИ_НА_OAUTH_ТОКЕН"
|
token: "y0_ЗАМЕНИ_НА_OAUTH_ТОКЕН"
|
||||||
|
|
||||||
|
# ── Technitium DNS HA ─────────────────────────────────────────────────────────
|
||||||
|
technitium_dns_admin_password: "ЗАМЕНИ_НА_ПАРОЛЬ" # минимум 8 символов
|
||||||
|
|||||||
@@ -319,3 +319,11 @@
|
|||||||
when: addon_yandex_dns_controller | default(false) | bool
|
when: addon_yandex_dns_controller | default(false) | bool
|
||||||
roles:
|
roles:
|
||||||
- role: "{{ playbook_dir }}/../addons/yandex-dns-controller/role"
|
- role: "{{ playbook_dir }}/../addons/yandex-dns-controller/role"
|
||||||
|
|
||||||
|
- name: Install Technitium DNS HA
|
||||||
|
hosts: k3s_master[0]
|
||||||
|
gather_facts: false
|
||||||
|
become: true
|
||||||
|
when: addon_technitium_dns | default(false) | bool
|
||||||
|
roles:
|
||||||
|
- role: "{{ playbook_dir }}/../addons/technitium-dns/role"
|
||||||
|
|||||||
Reference in New Issue
Block a user