external-dns/docs/contributing/crd-source.md
Yury Tsarev 95624432b7 Update CRD source doc with RBAC, fix CRD manifest
* Add RBAC piece of documentation

* Remove `status:` to avoid validation failure

Otherwise it fails with
```
$ kubectl apply -f crd-manifest.yaml
error: error validating "crd-manifest.yaml": error validating data: ValidationError(CustomResourceDefinition.status): missing required field "storedVersions" in io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1beta1.CustomResourceDefinitionStatus;
```
2019-12-28 15:51:09 +01:00

5.1 KiB

CRD Source

CRD source provides a generic mechanism to manage DNS records in your favourite DNS provider supported by external-dns.

Details

CRD source watches for a user specified CRD to extract Endpoints from its Spec. So users need to create such a CRD and register it to the kubernetes cluster and then create new object(s) of the CRD specifying the Endpoints.

Registering CRD

Here is typical example of CRD API type which provides Endpoints to CRD source:

type TTL int64
type Targets []string
type ProviderSpecificProperty struct {
	Name  string
	Value string
}
type ProviderSpecific []ProviderSpecificProperty

type Endpoint struct {
	// The hostname of the DNS record
	DNSName string `json:"dnsName,omitempty"`
	// The targets the DNS record points to
	Targets Targets `json:"targets,omitempty"`
	// RecordType type of record, e.g. CNAME, A, SRV, TXT etc
	RecordType string `json:"recordType,omitempty"`
	// TTL for the record
	RecordTTL TTL `json:"recordTTL,omitempty"`
	// Labels stores labels defined for the Endpoint
	// +optional
	Labels Labels `json:"labels,omitempty"`
	// ProviderSpecific stores provider specific config
	// +optional
	ProviderSpecific ProviderSpecific `json:"providerSpecific,omitempty"`
}

type DNSEndpointSpec struct {
	Endpoints []*Endpoint `json:"endpoints,omitempty"`
}

type DNSEndpointStatus struct {
	// The generation observed by the external-dns controller.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// DNSEndpoint is the CRD wrapper for Endpoint
// +k8s:openapi-gen=true
// +kubebuilder:resource:path=dnsendpoints
// +kubebuilder:subresource:status
type DNSEndpoint struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   DNSEndpointSpec   `json:"spec,omitempty"`
	Status DNSEndpointStatus `json:"status,omitempty"`
}

Refer to kubebuilder to create and register the CRD.

Usage

One can use CRD source by specifying --source flag with crd and specifying the ApiVersion and Kind of the CRD with --crd-source-apiversion and crd-source-kind respectively. for e.g:

$ build/external-dns --source crd --crd-source-apiversion externaldns.k8s.io/v1alpha1  --crd-source-kind DNSEndpoint --provider inmemory --once --dry-run

Creating DNS Records

Create the objects of CRD type by filling in the fields of CRD and DNS record would be created accordingly.

Example

Here is an example CRD manifest generated by kubebuilder. Apply this to register the CRD

$ kubectl apply --validate=false -f docs/contributing/crd-source/crd-manifest.yaml
customresourcedefinition.apiextensions.k8s.io "dnsendpoints.externaldns.k8s.io" created

Then you can create the dns-endpoint yaml similar to dnsendpoint-example

$ kubectl apply -f docs/contributing/crd-source/dnsendpoint-example.yaml
dnsendpoint.externaldns.k8s.io "examplednsrecord" created

Run external-dns in dry-mode to see whether external-dns picks up the DNS record from CRD.

$ build/external-dns --source crd --crd-source-apiversion externaldns.k8s.io/v1alpha1  --crd-source-kind DNSEndpoint --provider inmemory --once --dry-run
INFO[0000] config: {Master: KubeConfig: Sources:[crd] Namespace: AnnotationFilter: FQDNTemplate: CombineFQDNAndAnnotation:false Compatibility: PublishInternal:false PublishHostIP:false ConnectorSourceServer:localhost:8080 Provider:inmemory GoogleProject: DomainFilter:[] ZoneIDFilter:[] AWSZoneType: AWSAssumeRole: AWSMaxChangeCount:4000 AWSEvaluateTargetHealth:true AzureConfigFile:/etc/kubernetes/azure.json AzureResourceGroup: CloudflareProxied:false InfobloxGridHost: InfobloxWapiPort:443 InfobloxWapiUsername:admin InfobloxWapiPassword: InfobloxWapiVersion:2.3.1 InfobloxSSLVerify:true DynCustomerName: DynUsername: DynPassword: DynMinTTLSeconds:0 OCIConfigFile:/etc/kubernetes/oci.yaml InMemoryZones:[] PDNSServer:http://localhost:8081 PDNSAPIKey: PDNSTLSEnabled:false TLSCA: TLSClientCert: TLSClientCertKey: Policy:sync Registry:txt TXTOwnerID:default TXTPrefix: Interval:1m0s Once:true DryRun:true LogFormat:text MetricsAddress::7979 LogLevel:info TXTCacheInterval:0s ExoscaleEndpoint:https://api.exoscale.ch/dns ExoscaleAPIKey: ExoscaleAPISecret: CRDSourceAPIVersion:externaldns.k8s.io/v1alpha1 CRDSourceKind:DNSEndpoint}
INFO[0000] running in dry-run mode. No changes to DNS records will be made.
INFO[0000] Connected to cluster at https://192.168.99.100:8443
INFO[0000] CREATE: foo.bar.com 180 IN A 192.168.99.216
INFO[0000] CREATE: foo.bar.com 0 IN TXT "heritage=external-dns,external-dns/owner=default"

RBAC configuration

If you use RBAC, extend the external-dns ClusterRole with:

- apiGroups: ["externaldns.k8s.io"]
  resources: ["dnsendpoints"]
  verbs: ["get","watch","list"]
- apiGroups: ["externaldns.k8s.io"]
  resources: ["dnsendpoints/status"]
  verbs: ["*"]