feat(extra): add external-dns as standalone extra package (#1988)
## Summary Add external-dns as a standalone self-managed application in `packages/extra/external-dns/`, allowing tenants to deploy and configure their own DNS management directly from the dashboard. ## Motivation Tenants need the ability to manage their own DNS domains with their own provider. Following the [developers guide](https://github.com/cozystack/website/pull/413), this is implemented as an extra package (like `ingress` and `seaweedfs`) using the HelmRelease-based pattern, rather than embedding it in the tenant chart. This enables multi-tenant scenarios where: - Tenant A uses Cloudflare for `domain-a.com` - Tenant B uses AWS Route53 for `domain-b.com` - Each tenant deploys and manages external-dns independently from the dashboard ## Changes - **New package**: `packages/extra/external-dns/` — standalone HelmRelease-based application - **New PackageSource**: `packages/core/platform/sources/external-dns-application.yaml` — references `system/external-dns` and `extra/external-dns` components - **Cleaned tenant chart**: removed the previously embedded `externalDns` block from `packages/apps/tenant/` ## Features - Support for 9 DNS providers: cloudflare, aws, azure, google, digitalocean, linode, ovh, exoscale, godaddy - Per-provider credential configuration with full JSON schema validation - Domain filtering via `domainFilters` - Configurable sync policy (`sync` or `upsert-only`) - Namespaced operation (`namespaced: true`) for tenant isolation - Unique `txtOwnerId` per namespace to prevent DNS record conflicts - Resource sizing via presets or explicit CPU/memory ## Usage Example Deploy from the dashboard, or via values: ```yaml # Cloudflare provider: cloudflare domainFilters: - example.com cloudflare: apiToken: "your-cloudflare-api-token" ``` ```yaml # AWS Route53 provider: aws domainFilters: - example.org aws: accessKeyId: "AKIAXXXXXXXX" secretAccessKey: "your-secret-key" region: "us-east-1" ``` ## Test plan - [ ] `helm template external-dns packages/extra/external-dns/ --set provider=cloudflare --set cloudflare.apiToken=test` renders correctly - [ ] `helm template external-dns packages/extra/external-dns/` fails (provider required) - [ ] `helm template wrong-name packages/extra/external-dns/ --set provider=cloudflare` fails (release name check) - [ ] Deploy external-dns from tenant dashboard - [ ] Verify HelmRelease is created in tenant namespace with namespaced RBAC - [ ] Create an Ingress and verify DNS record is created - [ ] Verify no conflict with global external-dns instance 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an External DNS package for automatic DNS record management. * Support for 9 DNS providers: Cloudflare, AWS, Azure, Google, DigitalOcean, Linode, OVH, Exoscale, GoDaddy. * Helm-based deployment with namespaced/system variants and release configuration options. * Configurable synchronization policies, domain filtering, provider credentials, extra args, and resource presets. * **Documentation** * New README and schema-driven values documentation for installation and configuration. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
commit
5e773486e5
35 changed files with 2130 additions and 180 deletions
50
hack/e2e-apps/external-dns.bats
Normal file
50
hack/e2e-apps/external-dns.bats
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
teardown() {
|
||||
kubectl -n tenant-test delete externaldns.apps.cozystack.io --all --ignore-not-found 2>/dev/null || true
|
||||
}
|
||||
|
||||
@test "Create and Verify ExternalDNS with inmemory provider" {
|
||||
name='test'
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: ExternalDNS
|
||||
metadata:
|
||||
name: ${name}
|
||||
namespace: tenant-test
|
||||
spec:
|
||||
provider: inmemory
|
||||
domainFilters:
|
||||
- example.com
|
||||
EOF
|
||||
|
||||
sleep 5
|
||||
kubectl -n tenant-test wait hr ${name} --timeout=120s --for=condition=ready
|
||||
kubectl -n tenant-test wait hr ${name}-system --timeout=120s --for=condition=ready
|
||||
timeout 60 sh -ec "until kubectl -n tenant-test get deploy -l app.kubernetes.io/instance=${name}-system -o jsonpath='{.items[0].status.readyReplicas}' | grep -q '1'; do sleep 5; done"
|
||||
|
||||
kubectl -n tenant-test delete externaldns.apps.cozystack.io ${name}
|
||||
}
|
||||
|
||||
@test "Create and Verify ExternalDNS with custom annotationPrefix" {
|
||||
name='test-prefix'
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: apps.cozystack.io/v1alpha1
|
||||
kind: ExternalDNS
|
||||
metadata:
|
||||
name: ${name}
|
||||
namespace: tenant-test
|
||||
spec:
|
||||
provider: inmemory
|
||||
annotationPrefix: custom-dns/
|
||||
domainFilters:
|
||||
- example.org
|
||||
EOF
|
||||
|
||||
sleep 5
|
||||
kubectl -n tenant-test wait hr ${name} --timeout=120s --for=condition=ready
|
||||
kubectl -n tenant-test wait hr ${name}-system --timeout=120s --for=condition=ready
|
||||
timeout 60 sh -ec "until kubectl -n tenant-test get deploy -l app.kubernetes.io/instance=${name}-system -o jsonpath='{.items[0].status.readyReplicas}' | grep -q '1'; do sleep 5; done"
|
||||
|
||||
kubectl -n tenant-test delete externaldns.apps.cozystack.io ${name}
|
||||
}
|
||||
|
|
@ -46,6 +46,9 @@ spec:
|
|||
publishing:
|
||||
host: "example.org"
|
||||
apiServerEndpoint: "https://192.168.123.10:6443"
|
||||
bundles:
|
||||
enabledPackages:
|
||||
- cozystack.external-dns-application
|
||||
EOF
|
||||
|
||||
# Wait until HelmReleases appear & reconcile them
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue