From 8039e6712f2dc4b5c47d8de1cdb05411f7b49e9c Mon Sep 17 00:00:00 2001 From: Frank Sauerburger <frank@sauerburger.com> Date: Tue, 25 Jan 2022 17:58:20 +0100 Subject: [PATCH] Add draft chart --- app/Dockerfile | 2 +- app/kube/settings.py | 6 +- app/requirements.txt | 1 + app/run.sh | 1 - k8s-templates/.helmignore | 23 +++ k8s-templates/Chart.yaml | 24 +++ k8s-templates/templates/_helpers.tpl | 62 +++++++ k8s-templates/templates/deployment.yaml | 222 ++++++++++++++++++++++++ k8s-templates/templates/ingress.yaml | 25 +++ k8s-templates/templates/pvc.yaml | 27 +++ k8s-templates/templates/secrets.yaml | 35 ++++ k8s-templates/templates/services.yaml | 36 ++++ k8s-templates/values.yaml | 25 +++ nginx/Dockerfile | 2 +- nginx/nginx.conf | 9 +- 15 files changed, 490 insertions(+), 10 deletions(-) create mode 100644 k8s-templates/.helmignore create mode 100644 k8s-templates/Chart.yaml create mode 100644 k8s-templates/templates/_helpers.tpl create mode 100644 k8s-templates/templates/deployment.yaml create mode 100644 k8s-templates/templates/ingress.yaml create mode 100644 k8s-templates/templates/pvc.yaml create mode 100644 k8s-templates/templates/secrets.yaml create mode 100644 k8s-templates/templates/services.yaml create mode 100644 k8s-templates/values.yaml diff --git a/app/Dockerfile b/app/Dockerfile index 71fda42..8cbc882 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -1,6 +1,6 @@ FROM docker.sauerburger.com/python:3.10.1 -RUN pip install uwsgi +RUN pip install --upgrade pip COPY requirements.txt /app/ RUN pip install -r /app/requirements.txt RUN rm /app/requirements.txt diff --git a/app/kube/settings.py b/app/kube/settings.py index bf89f73..d33bcd0 100644 --- a/app/kube/settings.py +++ b/app/kube/settings.py @@ -30,10 +30,10 @@ if is_production or is_staging: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'kubetemplates', - 'USER': 'webapp', + 'NAME': os.environ.get("DB_NAME"), + 'USER': os.environ.get("DB_USERNAME"), 'PASSWORD': os.environ["DB_PASSWORD"], - 'HOST': 'database', + 'HOST': os.environ["DB_HOST"], 'PORT': '5432', } } diff --git a/app/requirements.txt b/app/requirements.txt index 4beb54a..fbbd890 100644 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -5,3 +5,4 @@ django-libsass~=0.9.0 psycopg2~=2.9.2 django-pygmentify~=0.3.7 crispy-bootstrap5~=0.6 +uwsgi~=2.0.20 diff --git a/app/run.sh b/app/run.sh index a1ddb69..81d45a5 100755 --- a/app/run.sh +++ b/app/run.sh @@ -2,7 +2,6 @@ set -e python3 manage.py collectstatic --no-input python3 manage.py compress -chown app:app -R /app/static rm -rf /app/webcontent/static cp -a /app/static /app/webcontent/static diff --git a/k8s-templates/.helmignore b/k8s-templates/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/k8s-templates/.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/k8s-templates/Chart.yaml b/k8s-templates/Chart.yaml new file mode 100644 index 0000000..1af45cd --- /dev/null +++ b/k8s-templates/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: k8s-templates +description: A helm chart for the kubernetes template app + +# 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. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.6 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.5" diff --git a/k8s-templates/templates/_helpers.tpl b/k8s-templates/templates/_helpers.tpl new file mode 100644 index 0000000..b628fc0 --- /dev/null +++ b/k8s-templates/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "k8s-templates.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 "k8s-templates.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 "k8s-templates.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "k8s-templates.labels" -}} +helm.sh/chart: {{ include "k8s-templates.chart" . }} +{{ include "k8s-templates.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "k8s-templates.selectorLabels" -}} +app.kubernetes.io/name: {{ include "k8s-templates.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "k8s-templates.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "k8s-templates.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/k8s-templates/templates/deployment.yaml b/k8s-templates/templates/deployment.yaml new file mode 100644 index 0000000..1d277a6 --- /dev/null +++ b/k8s-templates/templates/deployment.yaml @@ -0,0 +1,222 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-backend + labels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/name: k8s-templates + app.kubernetes.io/instance: k8s-templates-main + app.kubernetes.io/version: "0.1.5" + app.kubernetes.io/component: backend +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/instance: k8s-templates-main + template: + metadata: + labels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/name: k8s-templates + app.kubernetes.io/instance: k8s-templates-main + app.kubernetes.io/version: "0.1.5" + app.kubernetes.io/component: backend + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: backend + image: gitlab.sauerburger.com:5049/frank/k8s-templates/k8s-templates-backend:0.1.5 + ports: + - containerPort: 8080 + env: + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-secret + key: password + - name: DB_USERNAME + value: {{ .Values.database.user | quote }} + - name: DB_NAME + value: {{ .Values.database.name | quote }} + - name: DB_HOST + value: {{ .Release.Name }}-database-service + - name: PRODUCTION + value: {{ .Values.production | quote }} + - name: STAGING + value: {{ .Values.staging | quote }} + - name: SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-app-secret + key: password + - name: SUPER_EMAIL + value: {{ .Values.super.email | quote }} + - name: SUPER_USERNAME + value: {{ .Values.super.username | quote }} + - name: SUPER_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-super-secret + key: password + resources: + requests: + memory: 100M + cpu: 100m + limits: + memory: 2000M + cpu: 2000m + readinessProbe: + tcpSocket: + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 30 + + livenessProbe: + tcpSocket: + port: 8080 + initialDelaySeconds: 120 + periodSeconds: 60 + volumeMounts: + - mountPath: /app/webcontent/static + name: static-files + volumes: + - name: static-files + persistentVolumeClaim: + claimName: {{ .Release.Name }}-static-files-pvc +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-postgres + labels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/name: postgres + app.kubernetes.io/instance: postgres-main + app.kubernetes.io/version: "14.0" + app.kubernetes.io/component: datbase +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/instance: postgres-main + template: + metadata: + labels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/name: postgres + app.kubernetes.io/instance: postgres-main + app.kubernetes.io/version: "14.0" + app.kubernetes.io/component: datbase + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: postgres + image: docker.sauerburger.com/postgres:14.0 + ports: + - containerPort: 5432 + env: + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-secret + key: password + - name: POSTGRES_USER + value: {{ .Values.database.user | quote }} + - name: POSTGRES_DB + value: {{ .Values.database.name | quote}} + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + resources: + requests: + memory: 500M + cpu: 100m + limits: + memory: 2000M + cpu: 2000m + readinessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 30 + periodSeconds: 30 + + livenessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 120 + periodSeconds: 30 + volumeMounts: + - mountPath: /var/lib/postgresql/data + name: vol + volumes: + - name: vol + persistentVolumeClaim: + claimName: {{ .Release.Name }}-database-pvc +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-webserver + labels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/name: nginx + app.kubernetes.io/instance: nginx-main + app.kubernetes.io/version: "0.1.0" + app.kubernetes.io/component: webserver +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/instance: nginx-main + template: + metadata: + labels: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/name: nginx + app.kubernetes.io/instance: nginx-main + app.kubernetes.io/version: "1.21.5" + app.kubernetes.io/component: backend + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: backend + image: docker.sauerburger.com/nginx:1.21.5 + ports: + - containerPort: 8080 + resources: + requests: + memory: 100M + cpu: 100m + limits: + memory: 2000M + cpu: 2000m + readinessProbe: + httpGet: + path: "/--healthz" + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: "/--healthz" + port: 8080 + initialDelaySeconds: 120 + periodSeconds: 60 + volumeMounts: + - mountPath: /app/webcontent/static + name: static-files + volumes: + - name: static-files + persistentVolumeClaim: + claimName: {{ .Release.Name }}-static-files-pvc diff --git a/k8s-templates/templates/ingress.yaml b/k8s-templates/templates/ingress.yaml new file mode 100644 index 0000000..badcf07 --- /dev/null +++ b/k8s-templates/templates/ingress.yaml @@ -0,0 +1,25 @@ +{{- if .Values.ingress.host -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{ .Values.ingress.tlsIssuerType}}: {{ .Values.ingress.tlsIssuer | quote }} + kubernetes.io/ingress.class: nginx + name: {{ .Release.Name }}-k8s-templates-ingress +spec: + rules: + - host: {{ .Values.ingress.host | quote }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-k8s-templates-service + port: + number: 80 + path: / + pathType: Prefix + tls: + - hosts: + - {{ .Values.ingress.host | quote }} + secretName: {{ .Release.Name }}-k8s-templates-tls-secret +{{- end -}} diff --git a/k8s-templates/templates/pvc.yaml b/k8s-templates/templates/pvc.yaml new file mode 100644 index 0000000..410e9bb --- /dev/null +++ b/k8s-templates/templates/pvc.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-database-pvc +spec: + accessModes: + - ReadWriteMany + {{- if .Values.storage.database.persistentStorageClass }} + storageClassName: {{ .Values.storage.database.persistentStorageClass | quote }} + {{- end}} + resources: + requests: + storage: {{ .Values.storage.database.requestSize | quote }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-static-files-pvc +spec: + accessModes: + - ReadWriteMany + {{- if .Values.storage.staticFiles.persistentStorageClass }} + storageClassName: {{ .Values.storage.staticFiles.persistentStorageClass | quote }} + {{- end }} + resources: + requests: + storage: 100Mi diff --git a/k8s-templates/templates/secrets.yaml b/k8s-templates/templates/secrets.yaml new file mode 100644 index 0000000..1a8445a --- /dev/null +++ b/k8s-templates/templates/secrets.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .Release.Name }}-app-secret +data: + {{- if .Release.IsInstall }} + password: {{ randAlphaNum 20 | b64enc }} + {{- else }} + password: {{ (lookup "v1" "Secret" .Release.Namespace (print .Release.Name "-app-secret")).data.password }} + {{- end }} +--- +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .Release.Name }}-db-secret +data: + {{- if .Release.IsInstall }} + password: {{ randAlphaNum 20 | b64enc }} + {{- else }} + password: {{ (lookup "v1" "Secret" .Release.Namespace (print .Release.Name "-db-secret")).data.password }} + {{- end }} +--- +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ .Release.Name }}-super-secret +data: + {{- if .Release.IsInstall }} + password: {{ randAlphaNum 20 | b64enc }} + {{- else }} + password: {{ (lookup "v1" "Secret" .Release.Namespace (print .Release.Name "-super-secret")).data.password }} + {{- end }} diff --git a/k8s-templates/templates/services.yaml b/k8s-templates/templates/services.yaml new file mode 100644 index 0000000..8ce3cd0 --- /dev/null +++ b/k8s-templates/templates/services.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-database-service +spec: + selector: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/instance: postgres-main + ports: + - protocol: TCP + port: 5432 +--- +apiVersion: v1 +kind: Service +metadata: + name: k8s-templates-backend-service +spec: + selector: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/instance: k8s-templates-main + ports: + - protocol: TCP + port: 80 + targetPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-web-service +spec: + selector: + app.kubernetes.io/part-of: {{ .Release.Name }} + app.kubernetes.io/instance: nginx-main + ports: + - protocol: TCP + port: 80 diff --git a/k8s-templates/values.yaml b/k8s-templates/values.yaml new file mode 100644 index 0000000..d792995 --- /dev/null +++ b/k8s-templates/values.yaml @@ -0,0 +1,25 @@ +ingress: + host: "" # Leave empty to disable ingress + tlsIssuer: "letsencrypt-production" + tlsIssuerType: "cert-manager.io/cluster-issuer" + +super: + email: "admin@example.com" + username: "admin" + +database: + user: webapp + name: kubetemplates + +production: 1 +staging: "" + +imagePullSecrets: [] + +storage: + database: + persistentStorageClass: "" # Leave empty to use default + requestSize: 100Mi + + staticFiles: + persistentStorageClass: "" # Leave empty to use default diff --git a/nginx/Dockerfile b/nginx/Dockerfile index d2d5946..e896a29 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,2 +1,2 @@ -FROM docker.sauerburger.com/nginx:1.21 +FROM docker.sauerburger.com/nginx:1.21.5 COPY nginx.conf /etc/nginx/nginx.conf diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 002115f..ce6962c 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -5,13 +5,10 @@ worker_processes 2; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; - events { worker_connections 1024; } - - http { include /etc/nginx/mime.types; default_type application/octet-stream; @@ -36,9 +33,13 @@ http { location /static { root /var/webcontent; } + location /--healthz { + add_header Content-Type text/plain; + return 200 'All systems go!'; + } location / { include uwsgi_params; - uwsgi_pass kubetemplates:8080; + uwsgi_pass k8s-templates-backend-service:8080; uwsgi_param HTTP_X_FORWARDED_PROTO https; } } -- GitLab