diff --git a/charts/redirect/.helmignore b/charts/redirect/.helmignore new file mode 100644 index 0000000..50af031 --- /dev/null +++ b/charts/redirect/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/redirect/Chart.yaml b/charts/redirect/Chart.yaml new file mode 100644 index 0000000..d32d508 --- /dev/null +++ b/charts/redirect/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: redirect +description: Redirect Delpoyment + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 0.0.1 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: random diff --git a/charts/redirect/templates/_helpers.tpl b/charts/redirect/templates/_helpers.tpl new file mode 100644 index 0000000..79035a7 --- /dev/null +++ b/charts/redirect/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define ".helm.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 ".helm.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 ".helm.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define ".helm.labels" -}} +helm.sh/chart: {{ include ".helm.chart" . }} +{{ include ".helm.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define ".helm.selectorLabels" -}} +app.kubernetes.io/name: {{ include ".helm.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define ".helm.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include ".helm.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Host rule +*/}} +{{- define ".helm.hostRule" -}} +- host: {{ .Host | quote }} + http: + paths: + - path: / + backend: + serviceName: {{ .FullName }} + servicePort: {{ .SvcPort }} +{{- end -}} + +{{/* +Host TLS config +*/}} +{{- define ".helm.hostTLS" -}} +- hosts: + - {{ .Host | quote }} + secretName: tls-{{ .Host | replace "." "-" }} +{{- end -}} diff --git a/charts/redirect/templates/config.yaml b/charts/redirect/templates/config.yaml new file mode 100644 index 0000000..88d58c8 --- /dev/null +++ b/charts/redirect/templates/config.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include ".helm.fullname" . }} + labels: + app: {{ include ".helm.fullname" . }} +data: + config.yaml: | + defaultFallbackTarget: {{ .Values.redirect.defaultFallbackTarget }} + buildin: + wwwToNonWww: {{ if eq .Values.redirect.buildin "wwwToNonWww" -}}true{{- else -}}false{{- end }} + nonWwwToWww: {{ if eq .Values.redirect.buildin "nonWwwToWww" -}}true{{- else -}}false{{- end }} + {{ if .Values.redirect.hosts -}}hosts: + {{- toYaml .Values.redirect.hosts | nindent 6 }}{{- end }} diff --git a/charts/redirect/templates/deployment.yaml b/charts/redirect/templates/deployment.yaml new file mode 100644 index 0000000..5034d80 --- /dev/null +++ b/charts/redirect/templates/deployment.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include ".helm.fullname" . }} + labels: + app: {{ include ".helm.fullname" . }} + release: {{ include ".helm.fullname" . }} + {{- include ".helm.labels" . | nindent 4 }} + {{- toYaml .Values.labels | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include ".helm.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: {{ .Values.service.metricsPort | quote}} + labels: + app: {{ include ".helm.fullname" . }} + release: {{ include ".helm.fullname" . }} + {{- include ".helm.selectorLabels" . | nindent 8 }} + {{- toYaml .Values.labels | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include ".helm.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + - name: http-metrics + containerPort: {{ .Values.service.metricsPort }} + protocol: TCP + livenessProbe: + httpGet: + path: /ping + port: http-metrics + readinessProbe: + httpGet: + path: /ping + port: http-metrics + volumeMounts: + - name: {{ include ".helm.fullname" . }}-configmap-volume + mountPath: /etc/redirect/ + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumes: + - name: {{ include ".helm.fullname" . }}-configmap-volume + configMap: + name: {{ include ".helm.fullname" . }} + {{- 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/redirect/templates/grafana-influxdb-dashboard.yaml b/charts/redirect/templates/grafana-influxdb-dashboard.yaml new file mode 100644 index 0000000..1081cfd --- /dev/null +++ b/charts/redirect/templates/grafana-influxdb-dashboard.yaml @@ -0,0 +1,195 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include ".helm.fullname" . }}-influxdb-grafana-dashboard + labels: + grafana_dashboard: redirects +data: + redirects.json: | + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 6, + "iteration": 1584821926151, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "interval": "", + "legend": { + "avg": false, + "current": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "[[tag_fromHost]]", + "groupBy": [ + { + "params": [ + "10m" + ], + "type": "time" + }, + { + "params": [ + "fromHost" + ], + "type": "tag" + } + ], + "measurement": "http_requests_total", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT derivative(\"counter\", 1s) FROM \"http_requests_total\" WHERE (\"namespace\" = 'redirect') AND $timeFilter GROUP BY \"fromHost\"", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "counter" + ], + "type": "field" + }, + { + "params": [], + "type": "count" + }, + { + "params": [ + "10m" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "namespace", + "operator": "=", + "value": "redirect" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests / 10 minutes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": true, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 22, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-24h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Redirects", + "uid": "Tcemi9yZz", + "version": 1 + } diff --git a/charts/redirect/templates/ingress.yaml b/charts/redirect/templates/ingress.yaml new file mode 100644 index 0000000..125500d --- /dev/null +++ b/charts/redirect/templates/ingress.yaml @@ -0,0 +1,45 @@ +{{- $fullName := include ".helm.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- $hosts := .Values.redirect.hosts -}} +{{- $ingressHosts := .Values.redirect.ingressHosts -}} +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include ".helm.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + tls: + {{- if $hosts -}} + {{- range $hostFrom, $hostTo := $hosts }} + {{- $host := dict "Host" $hostFrom -}} + {{ include ".helm.hostTLS" $host | nindent 4 }} + {{- end }} + {{- end }} + {{- if $ingressHosts -}} + {{- range $host := $ingressHosts }} + {{- if eq (hasKey $hosts $host) false -}} + {{- $host := dict "Host" $host -}} + {{ include ".helm.hostTLS" $host | nindent 4 }} + {{- end }} + {{- end }} + {{- end }} + rules: + {{- if $hosts -}} + {{- range $hostFrom, $hostTo := $hosts }} + {{- $host := dict "Host" $hostFrom "FullName" $fullName "SvcPort" $svcPort -}} + {{ include ".helm.hostRule" $host | nindent 4 }} + {{- end }} + {{- end }} + {{- if $ingressHosts -}} + {{- range $host := $ingressHosts }} + {{- if eq (hasKey $hosts $host) false -}} + {{- $host := dict "Host" $host "FullName" $fullName "SvcPort" $svcPort -}} + {{ include ".helm.hostRule" $host | nindent 4 }} + {{- end }} + {{- end }} + {{- end }} diff --git a/charts/redirect/templates/pod-disruption-budget.yaml b/charts/redirect/templates/pod-disruption-budget.yaml new file mode 100644 index 0000000..0a628df --- /dev/null +++ b/charts/redirect/templates/pod-disruption-budget.yaml @@ -0,0 +1,10 @@ +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ include ".helm.fullname" . }} +spec: + minAvailable: 1 + selector: + matchLabels: + app: {{ include ".helm.fullname" . }} + release: {{ include ".helm.fullname" . }} \ No newline at end of file diff --git a/charts/redirect/templates/service-account.yaml b/charts/redirect/templates/service-account.yaml new file mode 100644 index 0000000..2353a79 --- /dev/null +++ b/charts/redirect/templates/service-account.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include ".helm.serviceAccountName" . }} + labels: +{{ include ".helm.labels" . | nindent 4 }} +{{- end -}} diff --git a/charts/redirect/templates/service.yaml b/charts/redirect/templates/service.yaml new file mode 100644 index 0000000..43a8506 --- /dev/null +++ b/charts/redirect/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include ".helm.fullname" . }} + labels: + {{- include ".helm.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: http + - port: {{ .Values.service.metricsPort }} + targetPort: {{ .Values.service.metricsPort }} + protocol: TCP + name: http-metrics + selector: + {{- include ".helm.selectorLabels" . | nindent 4 }} diff --git a/charts/redirect/templates/tests/test-metrics-connection.yaml b/charts/redirect/templates/tests/test-metrics-connection.yaml new file mode 100644 index 0000000..7aadf18 --- /dev/null +++ b/charts/redirect/templates/tests/test-metrics-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include ".helm.fullname" . }}-test-metrics-connection" + labels: +{{ include ".helm.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include ".helm.fullname" . }}:{{ .Values.service.metricsPort }}'] + restartPolicy: Never diff --git a/charts/redirect/templates/tests/test-redirect-connection.yaml b/charts/redirect/templates/tests/test-redirect-connection.yaml new file mode 100644 index 0000000..655650d --- /dev/null +++ b/charts/redirect/templates/tests/test-redirect-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include ".helm.fullname" . }}-test-redirect-connection" + labels: +{{ include ".helm.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include ".helm.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/redirect/values.yaml b/charts/redirect/values.yaml new file mode 100644 index 0000000..3324e84 --- /dev/null +++ b/charts/redirect/values.yaml @@ -0,0 +1,79 @@ +# Default values for .helm. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Redirect Application Configuration +redirect: +# The default fallback is use in case the application can't find a domain to redirect to within the other configuration options + defaultFallbackTarget: https://wyrihaximus.net/ + buildin: nonWwwToWww + hosts: {} +# For example we're redirect the real name domain, to the nickname domain here. This is useful for migrations to new hostnames +# www.ceesjankiewiet.nl: wyrihaximus.net + ingressHosts: [] +# For example we're could be redirecting from wyrihaximus.net to www.wyrihaximus.net so we need the wyrihaximus.net ingress host defined here +# - wyrihaximus.net + +replicaCount: 2 + +image: + repository: wyrihaximusnet/redirect + tag: random + pullPolicy: Always + +serviceAccount: + # Specifies whether a service account should be created + create: true + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + +labels: + language: random + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 7132 + metricsPort: 7133 + +ingress: + annotations: + kubernetes.io/ingress.class: nginx + kubernetes.io/tls-acme: "true" + +resources: + # Setting this pretty low since this is a low resource intensive application, increase when needed + limits: + cpu: 50m + memory: 16Mi + requests: + cpu: 10m + memory: 16Mi + +nodeSelector: {} ## WE should set this to always run on two different nodes + +tolerations: [] + +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - redirect + topologyKey: "kubernetes.io/hostname"