diff --git a/.github/workflows/lint-test-chart.yaml b/.github/workflows/lint-test-chart.yaml new file mode 100644 index 0000000000..7a06a393c1 --- /dev/null +++ b/.github/workflows/lint-test-chart.yaml @@ -0,0 +1,48 @@ +name: Lint and Test Chart + +on: + pull_request: + paths: + - "charts/external-dns/**" + +jobs: + lint-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Helm + uses: azure/setup-helm@v1 + with: + version: v3.6.3 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.7 + + - name: Set up chart-testing + uses: helm/chart-testing-action@v2.1.0 + + - name: Run chart-testing (list-changed) + id: list-changed + run: | + changed=$(ct list-changed) + if [[ -n "$changed" ]]; then + echo "::set-output name=changed::true" + fi + + - name: Run chart-testing (lint) + run: ct lint + + - name: Create Kind cluster + uses: helm/kind-action@v1.2.0 + with: + wait: 120s + if: steps.list-changed.outputs.changed == 'true' + + - name: Run chart-testing (install) + run: ct install diff --git a/.github/workflows/release-chart.yaml b/.github/workflows/release-chart.yaml new file mode 100644 index 0000000000..b72995986e --- /dev/null +++ b/.github/workflows/release-chart.yaml @@ -0,0 +1,33 @@ +name: Release Chart + +on: + push: + branches: + - master + paths: + - "charts/external-dns/**" + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Install Helm + uses: azure/setup-helm@v1 + with: + version: v3.6.3 + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.2.1 + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + CR_RELEASE_NAME_TEMPLATE: "external-dns-helm-chart-{{ .Version }}" diff --git a/.gitignore b/.gitignore index db4b5e4c89..80a6ea1585 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,7 @@ vendor/ profile.cov # github codespaces -.venv/ \ No newline at end of file +.venv/ + +# Helm charts +!/charts/external-dns/ diff --git a/charts/external-dns/.helmignore b/charts/external-dns/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/external-dns/.helmignore @@ -0,0 +1,23 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/external-dns/Chart.yaml b/charts/external-dns/Chart.yaml new file mode 100644 index 0000000000..60fb086adb --- /dev/null +++ b/charts/external-dns/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: external-dns +description: ExternalDNS synchronizes exposed Kubernetes Services and Ingresses with DNS providers. +type: application +version: 1.2.0 +appVersion: 0.9.0 +keywords: + - kubernetes + - external-dns + - dns +home: https://github.com/kubernetes-sigs/external-dns/ +icon: https://github.com/kubernetes-sigs/external-dns/raw/master/img/external-dns.png +sources: + - https://github.com/kubernetes-sigs/external-dns/ +maintainers: + - name: stevehipwell + email: steve.hipwell@gmail.com +annotations: + artifacthub.io/changes: | + - kind: added + description: Initial official release. diff --git a/charts/external-dns/README.md b/charts/external-dns/README.md new file mode 100644 index 0000000000..e6b82ba5b7 --- /dev/null +++ b/charts/external-dns/README.md @@ -0,0 +1,66 @@ +# ExternalDNS + +[ExternalDNS](https://github.com/kubernetes-sigs/external-dns/) synchronizes exposed Kubernetes Services and Ingresses with DNS providers. + +## Installing the Chart + +Before you can install the chart you will need to add the `external-dns` repo to [Helm](https://helm.sh/). + +```shell +helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/ +``` + +After you've installed the repo you can install the chart. + +```shell +helm upgrade --install external-dns/external-dns +``` + +## Configuration + +The following table lists the configurable parameters of the _ExternalDNS_ chart and their default values. + +| Parameter | Description | Default | +| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | +| `image.repository` | Image repository. | `k8s.gcr.io/external-dns/external-dns` | +| `image.tag` | Image tag, will override the default tag derived from the chart app version. | `""` | +| `image.pullPolicy` | Image pull policy. | `IfNotPresent` | +| `imagePullSecrets` | Image pull secrets. | `[]` | +| `nameOverride` | Override the `name` of the chart. | `""` | +| `fullnameOverride` | Override the `fullname` of the chart. | `""` | +| `serviceAccount.create` | If `true`, create a new `serviceaccount`. | `true` | +| `serviceAccount.annotations` | Annotations to add to the service account. | `{}` | +| `serviceAccount.name` | Service account to be used. If not set and `serviceAccount.create` is `true`, a name is generated using the full name template. | `""` | +| `rbac.create` | If `true`, create the RBAC resources. | `true` | +| `podLabels` | Labels to add to the pod. | `{}` | +| `podAnnotations` | Annotations to add to the pod. | `{}` | +| `podSecurityContext` | Security context for the pod, this supports the full [PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#podsecuritycontext-v1-core) API. | _see values.yaml_ | +| `securityContext` | Security context for the _external-dns_ container, this supports the full [SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#securitycontext-v1-core) API. | _see values.yaml_ | +| `priorityClassName` | Priority class name to use for the pod. | `""` | +| `terminationGracePeriodSeconds` | Termination grace period for the pod. | `null` | +| `serviceMonitor.enabled` | If `true`, create a _Prometheus_ service monitor. | `false` | +| `serviceMonitor.additionalLabels` | Additional labels to be set on the ServiceMonitor. | `{}` | +| `serviceMonitor.interval` | _Prometheus_ scrape frequency. | `1m` | +| `serviceMonitor.scrapeTimeout` | _Prometheus_ scrape timeout. | `10s` | +| `env` | [Environment variables](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/) for the _external-dns_ container, this supports the full [EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#envvar-v1-core) API including secrets and configmaps. | `[]` | +| `livenessProbe` | [Liveness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) for the _external-dns_ container, this supports the full [Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#probe-v1-core) API. | See _values.yaml_ | +| `readinessProbe` | [Readiness probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) for the _external-dns_ container, this supports the full [Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#probe-v1-core) API. | See _values.yaml_ | +| `service.port` | Port to expose via the service. | `7979` | +| `extraVolumes` | Additional volumes for the pod, this supports the full [VolumeDevice](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#volumedevice-v1-core) API. | `[]` | +| `extraVolumeMounts` | Additional volume mounts for the _external-dns_ container, this supports the full [VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#volumemount-v1-core) API. | `[]` | +| `resources` | Resource requests and limits for the _external-dns_ container, this supports the full [ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#resourcerequirements-v1-core) API. | `{}` | +| `nodeSelector` | Node labels for pod assignment. | `{}` | +| `tolerations` | Tolerations for pod assignment, this supports the full [Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#toleration-v1-core) API. | `[]` | +| `affinity` | Affinity settings for pod assignment, this supports the full [Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#affinity-v1-core) API. | `{}` | +| `logLevel` | Verbosity of the logs, available values are: `panic`, `debug`, `info`, `warn`, `error`, `fatal`. | `info` | +| `logFormat` | Formats of the logs, available values are: `text`, `json`. | `text` | +| `interval` | The interval for DNS updates. | `1m` | +| `triggerLoopOnEvent` | When enabled, triggers run loop on create/update/delete events in addition of regular interval. | `false` | +| `sources` | K8s resources type to be observed for new DNS entries. | See _values.yaml_ | +| `policy` | How DNS records are synchronized between sources and providers, available values are: `sync`, `upsert-only`. | `upsert-only` | +| `registry` | Registry Type, available types are: `txt`, `noop`. | `txt` | +| `txtOwnerId` | TXT registry identifier. | `""` | +| `txtPrefix` | Prefix to create a TXT record with a name following the pattern `prefix.`. | `""` | +| `domainFilters` | Limit possible target zones by domain suffixes. | `[]` | +| `provider` | DNS provider where the DNS records will be created, for the available providers and how to configure them see the [README](https://github.com/kubernetes-sigs/external-dns#deploying-to-a-cluster). | `aws` | +| `extraArgs` | Extra arguments to pass to the _external-dns_ container, these are needed for provider specific arguments. | `[]` | diff --git a/charts/external-dns/templates/NOTES.txt b/charts/external-dns/templates/NOTES.txt new file mode 100644 index 0000000000..5e37ecca04 --- /dev/null +++ b/charts/external-dns/templates/NOTES.txt @@ -0,0 +1,7 @@ +*********************************************************************** +* External DNS * +*********************************************************************** + Chart version: {{ .Chart.Version }} + App version: {{ .Chart.AppVersion }} + Image tag: {{ include "external-dns.image" . }} +*********************************************************************** diff --git a/charts/external-dns/templates/_helpers.tpl b/charts/external-dns/templates/_helpers.tpl new file mode 100644 index 0000000000..7f6e52f052 --- /dev/null +++ b/charts/external-dns/templates/_helpers.tpl @@ -0,0 +1,69 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "external-dns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "external-dns.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "external-dns.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "external-dns.labels" -}} +helm.sh/chart: {{ include "external-dns.chart" . }} +{{ include "external-dns.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "external-dns.selectorLabels" -}} +app.kubernetes.io/name: {{ include "external-dns.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "external-dns.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "external-dns.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +The image to use +*/}} +{{- define "external-dns.image" -}} +{{- printf "%s:%s" .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- end }} diff --git a/charts/external-dns/templates/clusterrole.yaml b/charts/external-dns/templates/clusterrole.yaml new file mode 100644 index 0000000000..e46a66dd75 --- /dev/null +++ b/charts/external-dns/templates/clusterrole.yaml @@ -0,0 +1,18 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "external-dns.fullname" . }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["services","endpoints","pods"] + verbs: ["get","watch","list"] + - apiGroups: ["extensions","networking.k8s.io"] + resources: ["ingresses"] + verbs: ["get","watch","list"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["list","watch"] +{{- end }} diff --git a/charts/external-dns/templates/clusterrolebinding.yaml b/charts/external-dns/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..9028c6f962 --- /dev/null +++ b/charts/external-dns/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ printf "%s-viewer" (include "external-dns.fullname" .) }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "external-dns.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "external-dns.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/external-dns/templates/deployment.yaml b/charts/external-dns/templates/deployment.yaml new file mode 100644 index 0000000000..ca598d48a9 --- /dev/null +++ b/charts/external-dns/templates/deployment.yaml @@ -0,0 +1,108 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "external-dns.fullname" . }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "external-dns.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "external-dns.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "external-dns.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} + {{- with .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ . }} + {{- end }} + containers: + - name: external-dns + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: {{ include "external-dns.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.env }} + env: + {{- toYaml . | nindent 12 }} + {{- end }} + args: + - --log-level={{ .Values.logLevel }} + - --log-format={{ .Values.logFormat }} + - --interval={{ .Values.interval }} + {{- if .Values.triggerLoopOnEvent }} + - --events + {{- end }} + {{- range .Values.sources }} + - --source={{ . }} + {{- end }} + - --policy={{ .Values.policy }} + {{- if eq .Values.registry "txt" }} + {{- if .Values.txtOwnerId }} + - --txt-owner-id={{ .Values.txtOwnerId }} + {{- end }} + {{- if .Values.txtPrefix }} + - --txt-prefix={{ .Values.txtPrefix }} + {{- end }} + {{- end }} + {{- range .Values.domainFilters }} + - --domain-filter={{ . }} + {{- end }} + - --provider={{ .Values.provider }} + {{- range .Values.extraArgs }} + - {{ . }} + {{- end }} + ports: + - name: http + protocol: TCP + containerPort: 7979 + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + {{- with .Values.extraVolumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.extraVolumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/external-dns/templates/service.yaml b/charts/external-dns/templates/service.yaml new file mode 100644 index 0000000000..0c0c000bd2 --- /dev/null +++ b/charts/external-dns/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "external-dns.fullname" . }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} +spec: + type: ClusterIP + selector: + {{- include "external-dns.selectorLabels" . | nindent 4 }} + ports: + - name: http + port: {{ .Values.service.port }} + targetPort: http + protocol: TCP diff --git a/charts/external-dns/templates/serviceaccount.yaml b/charts/external-dns/templates/serviceaccount.yaml new file mode 100644 index 0000000000..aa6deed586 --- /dev/null +++ b/charts/external-dns/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "external-dns.serviceAccountName" . }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/external-dns/templates/servicemonitor.yaml b/charts/external-dns/templates/servicemonitor.yaml new file mode 100644 index 0000000000..c5be444923 --- /dev/null +++ b/charts/external-dns/templates/servicemonitor.yaml @@ -0,0 +1,28 @@ +{{- if.Values.serviceMonitor.enabled -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "external-dns.fullname" . }} + labels: + {{- include "external-dns.labels" . | nindent 4 }} + {{- with .Values.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ .Release.Name }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + {{- include "external-dns.selectorLabels" . | nindent 6 }} + endpoints: + - port: http + path: /metrics + {{- with .Values.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} +{{- end }} diff --git a/charts/external-dns/values.yaml b/charts/external-dns/values.yaml new file mode 100644 index 0000000000..d949d578c3 --- /dev/null +++ b/charts/external-dns/values.yaml @@ -0,0 +1,109 @@ +# Default values for external-dns. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: k8s.gcr.io/external-dns/external-dns + # Overrides the image tag whose default is v{{ .Chart.AppVersion }} + tag: "" + pullPolicy: IfNotPresent + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +rbac: + # Specifies whether RBAC resources should be created + create: true + +podLabels: {} + +podAnnotations: {} + +podSecurityContext: + fsGroup: 65534 + +securityContext: + runAsNonRoot: true + runAsUser: 65534 + readOnlyRootFilesystem: true + capabilities: + drop: ["ALL"] + +priorityClassName: "" + +terminationGracePeriodSeconds: + +serviceMonitor: + enabled: false + additionalLabels: {} + interval: 1m + scrapeTimeout: 10s + +env: [] + +livenessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 2 + successThreshold: 1 + +readinessProbe: + httpGet: + path: /healthz + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + successThreshold: 1 + +service: + port: 7979 + +extraVolumes: [] + +extraVolumeMounts: [] + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +logLevel: info +logFormat: text + +interval: 1m +triggerLoopOnEvent: false + +sources: + - service + - ingress + +policy: upsert-only + +registry: txt +txtOwnerId: "" +txtPrefix: "" + +domainFilters: [] + +provider: aws + +extraArgs: []