This commit is contained in:
David Burke 2021-05-28 21:33:04 +00:00
parent 0079a1dcb9
commit fd14c6d228
19 changed files with 158 additions and 128 deletions

View file

@ -1,7 +1,12 @@
image:
name: alpine/helm:3.2.4
name: alpine/helm:3.5.4
entrypoint: ["/bin/sh", "-c"]
lint:
stage: test
script:
- helm lint
pages:
stage: deploy
script:

View file

@ -1,9 +1,9 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 10.3.17
version: 10.4.8
- name: redis
repository: https://charts.bitnami.com/bitnami
version: 13.0.1
digest: sha256:ef9c8ed96cc70ed6d6c6fc0e83a166e46ce1a8c29fe03b6164b361e78782cb46
generated: "2021-04-16T16:13:30.720115202-04:00"
version: 14.2.1
digest: sha256:400dc8c7d3450f4f2cb2e7be70688092634a00c177771988bd03c0ec13d290d8
generated: "2021-05-27T11:09:15.228491774-04:00"

View file

@ -1,6 +1,6 @@
apiVersion: v2
name: glitchtip
description: Open source error tracking that is compatible with Sentry
name: django
description: Generic Django + Celery Helm Chart
# A chart can be either an 'application' or a 'library' chart.
#
@ -22,10 +22,10 @@ appVersion: 1.0.0
dependencies:
- name: postgresql
version: 10.3.17
version: ~10.4.8
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
- name: redis
version: 13.0.1
version: ~14.2.1
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2020 GlitchTip
Copyright (c) 2021 Burke Software and Consulting LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,10 +1,58 @@
# GlitchTip Helm Chart
# Django Helm Chart
We use this chart internally. However it's not fully documented yet nor tested in a wide range of scenarios.
If you are a helm and kubernetes expert - feel free to use this and help contribute to this repo.
A generic Django (plus Celery) Helm chart.
# Preparing your Django app
This chart supports a web plus optional celery and beat deployments. Be prepared to extend it as necessary.
Django settings will be managed by environment variables. `os.getenv` is fine. `django-environ` is nice as well. This chart expects SECRET_KEY and DATABASE_URL variables.
Kubernetes works best when it is able to determine application health. You Django app should have a `/_health/` view such as
```
def health(request):
return HttpResponse("ok", content_type="text/plain")
urlpatterns = [
path("_health/", health),
...
```
# Usage
1. Add our Helm chart repo `helm repo add glitchtip https://glitchtip.gitlab.io/glitchtip-helm-chart/`
2. Review our values.yaml. At a minimum you'll need to set databaseURL and secretKey.
2. Review our values.yaml. At a minimum you'll need to set SECRET_KEY.
3. Install the chart `helm install glitchtip/glitchtip --set databaseURL=your_db --set secretKey=random_string`
# Tips
- Do you really need kubernetes? It's very complex.
- Don't use helm without [helm diff](https://github.com/databus23/helm-diff). One typo will wipe your app without warning otherwise.
- While supported, I don't suggest running stateful services like PostgreSQL in kubernetes. Upgrades will likely involve downtime or extensive and arcane knowledge.
- It's fine to use this chart as a reference for your own chart instead of directly using it.
## Managing environment variables and secrets
I suggest either
- Keep them in a values.yml file in a private repo
- Make use of --reuse-values and --set
- Keep them in a non helm chart managed service
## Deploying in CI
I use lwolf/helm-kubectl-docker with Gitlab CI. [Example](https://gitlab.com/glitchtip/glitchtip-frontend/-/blob/master/.gitlab-ci.yml).
# Support development
Maintaining this chart takes time. Considering supporting it by
- [Donating on liberapay](https://liberapay.com/burke-software/)
- Check out [GlitchTip](https://glitchtip.com) error tracking, which is where this project started
Commercial support is available - email info@burkesoftware.com
# Contributing
Contributions are welcome. Report bugs on gitlab issues. Please only open feature requests that you'd like to implement yourself or pay for.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
charts/redis-14.2.1.tgz Normal file

Binary file not shown.

View file

@ -78,19 +78,29 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
{{- end -}}
{{- end -}}
{{- end -}}
{{- define "django.redis.fullname" -}}
{{- if .Values.redis.fullnameOverride -}}
{{- .Values.redis.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.redis.nameOverride -}}
{{- $name := default .Chart.Name -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name "django-redis" | trunc 63 | trimSuffix "-" -}}
{{- printf "%s-%s" .Release.Name "redis-master" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Set postgresql url
*/}}
{{- define "django.postgresql.url" -}}
{{- if .Values.postgresql.enabled -}}
postgres://{{ .Values.postgresql.postgresqlUsername }}:{{ .Values.postgresql.postgresqlPassword }}@{{- template "django.postgresql.fullname" . -}}
{{- end -}}
{{- end -}}
{{/*
Set redis host
*/}}
@ -107,7 +117,7 @@ Set redis url
*/}}
{{- define "django.redis.url" -}}
{{- if .Values.redis.enabled -}}
redis://{{- template "django.redis.password" -}}{{- template "django.redis.fullname" . -}}-master
redis://:{{ .Values.redis.auth.password }}@{{- template "django.redis.fullname" . -}}:{{- template "django.redis.port" . -}}/0
{{- end -}}
{{- end -}}
@ -116,8 +126,8 @@ Set redis port
*/}}
{{- define "django.redis.port" -}}
{{- if .Values.redis.enabled -}}
"6379"
6379
{{- else -}}
{{- default "6379" .Values.redis.port | quote -}}
{{- default "6379" .Values.redis.port -}}
{{- end -}}
{{- end -}}

View file

@ -1,3 +1,4 @@
{{- if .Values.worker.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
@ -43,23 +44,9 @@ spec:
env:
- name: SERVER_ROLE
value: "beat"
{{- if .Values.redisURL }}
- name: REDIS_URL
value: {{ .Values.redisURL }}
{{- end }}
{{- if .Values.redis.enabled }}
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
key: redis-password
name: {{ include "django.fullname" . }}-redis
- name: REDIS_HOST
value: {{ template "django.redis.host" . }}
- name: REDIS_PORT
value: {{ template "django.redis.port" . }}
{{- end }}
envFrom:
- secretRef:
name: {{ include "django.fullname" . }}
- configMapRef:
name: {{ include "django.fullname" . }}
{{- end }}

View file

@ -7,6 +7,6 @@ metadata:
annotations:
"helm.sh/hook-weight": "-1"
data:
{{- range $k, $v := .Values.environmentVariables }}
{{- range $k, $v := .Values.env.normal }}
{{ $k }}: {{ $v | quote }}
{{- end }}
{{- end }}

View file

@ -15,6 +15,10 @@ spec:
activeDeadlineSeconds: 600
template:
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
restartPolicy: Never
containers:
- name: pre-install-job
@ -24,9 +28,12 @@ spec:
env:
- name: DEBUG
value: "False"
- name: STATIC_URL
value: /
{{- if .Values.env.secret.DATABASE_URL }}
- name: DATABASE_URL
value: {{ required "databaseURL is a required value." .Values.databaseURL }}
value: {{ .Values.env.secret.DATABASE_URL }}
{{- else if .Values.postgresql.enabled }}
- name: DATABASE_URL
value: {{ include "django.postgresql.url" . | b64enc | quote }}
{{- end }}
- name: SECRET_KEY
value: {{ required "secretKey is a required value." .Values.secretKey }}
value: {{ required "env.secret.SECRET_KEY is a required value." .Values.env.secret.SECRET_KEY }}

View file

@ -6,12 +6,12 @@ metadata:
{{- include "django.labels" . | nindent 4 }}
type: Opaque
data:
DATABASE_URL: {{ required "databaseURL is a required value." .Values.databaseURL | b64enc | quote }}
SECRET_KEY: {{ required "secretKey is a required value." .Values.secretKey | b64enc | quote }}
REDIS_URL: {{ printf "redis://:@glitchtip-staging-redis-master:6379/0" | b64enc | quote }}
{{- if .Values.stripeLiveSecretKey }}
STRIPE_LIVE_SECRET_KEY: {{ .Values.stripeLiveSecretKey | b64enc | quote }}
{{- range $k, $v := .Values.env.secret }}
{{ $k }}: {{ $v | b64enc | quote }}
{{- end }}
{{- if .Values.djstripeWebhookSecret }}
DJSTRIPE_WEBHOOK_SECRET: {{ .Values.djstripeWebhookSecret | b64enc | quote }}
{{- if .Values.redis.enabled }}
REDIS_URL: {{ include "django.redis.url" . | b64enc | quote }}
{{- end }}
{{- if .Values.postgresql.enabled }}
DATABASE_URL: {{ include "django.postgresql.url" . | b64enc | quote }}
{{- end }}

View file

@ -57,21 +57,6 @@ spec:
resources:
{{- toYaml .Values.web.resources | nindent 12 }}
env:
{{- if .Values.redisURL }}
- name: REDIS_URL
value: {{ .Values.redisURL }}
{{- end }}
{{- if .Values.redis.enabled }}
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
key: redis-password
name: {{ include "django.fullname" . }}-redis
- name: REDIS_HOST
value: {{ template "django.redis.host" . }}
- name: REDIS_PORT
value: {{ template "django.redis.port" . }}
{{- end }}
- name: POD_IP
valueFrom:
fieldRef:

View file

@ -1,7 +1,14 @@
{{- if .Values.web.ingress.enabled -}}
{{- $fullName := include "django.fullname" . -}}
{{- $svcPort := .Values.web.service.port -}}
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
{{- if and .Values.web.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.web.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.web.ingress.annotations "kubernetes.io/ingress.class" .Values.web.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
@ -16,6 +23,9 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.web.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.web.ingress.className }}
{{- end }}
{{- if .Values.web.ingress.tls }}
tls:
{{- range .Values.web.ingress.tls }}
@ -33,9 +43,19 @@ spec:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
serviceName: {{ $fullName }}-web
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -1,3 +1,4 @@
{{- if .Values.worker.enabled -}}
apiVersion: apps/v1
kind: Deployment
metadata:
@ -38,21 +39,6 @@ spec:
env:
- name: SERVER_ROLE
value: "worker"
{{- if .Values.redisURL }}
- name: REDIS_URL
value: {{ .Values.redisURL }}
{{- end }}
{{- if .Values.redis.enabled }}
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
key: redis-password
name: {{ include "django.fullname" . }}-redis
- name: REDIS_HOST
value: {{ template "django.redis.host" . }}
- name: REDIS_PORT
value: {{ template "django.redis.port" . }}
{{- end }}
envFrom:
- secretRef:
name: {{ include "django.fullname" . }}
@ -70,3 +56,4 @@ spec:
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View file

@ -1,18 +0,0 @@
web:
hpa:
enabled: true
resources:
limits:
cpu: 1000m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
worker:
hpa:
enabled: true
environmentVariables:
ENABLE_SOCIAL_AUTH: true
GLITCHTIP_DOMAIN: https://staging.glitchtip.com

View file

@ -1,25 +1,22 @@
# Default values for glitchtip.
# Default values for django.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
image:
repository: glitchtip/glitchtip
repository: glitchtip/glitchtip # Demo app, change this.
tag: latest
pullPolicy: Always
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
databaseURL:
secretKey:
redisURL:
# Only needed when using stripe for saas environment
stripeLiveSecretKey:
djstripeWebhookSecret:
environmentVariables:
ENABLE_SOCIAL_AUTH: false
GLITCHTIP_DOMAIN: https://example.com
env:
normal: {}
secret: {}
# SECRET_KEY:
# DATABASE_URL:
# REDIS_URL:
web:
replicaCount: 2
@ -41,18 +38,18 @@ web:
memory: 128Mi
nodeSelector: {}
tolerations: []
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/instance
operator: In
values:
- glitchtip-prod-web
topologyKey: kubernetes.io/hostname
affinity: {}
# podAntiAffinity:
# preferredDuringSchedulingIgnoredDuringExecution:
# - weight: 100
# podAffinityTerm:
# labelSelector:
# matchExpressions:
# - key: app.kubernetes.io/instance
# operator: In
# values:
# - glitchtip-prod-web
# topologyKey: kubernetes.io/hostname
livenessProbe:
failureThreshold: 5
initialDelaySeconds: 5
@ -67,19 +64,22 @@ web:
ingress:
enabled: false
annotations:
{}
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
worker:
enabled: true
replicaCount: 1
autoscaling:
enabled: false
@ -110,13 +110,12 @@ redis:
master:
persistence:
enabled: false
slave:
replica:
replicaCount: 1
persistence:
enabled: false
cluster:
enabled: false
slaveCount: 1
# Default to disabled, use a managed database service. But can be enabled here.
postgresql:
enabled: false
postgresqlPassword: # Must be set