diff --git a/Chart.yaml b/Chart.yaml index 1e43a45..b23cd92 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -15,7 +15,7 @@ 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: 1.0.4 +version: 1.0.5 # 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 @@ -28,3 +28,7 @@ dependencies: condition: postgresql.enabled version: ^12.0.0 repository: "https://charts.bitnami.com/bitnami" + - name: redis + condition: redis.enabled + version: ^20.0.0 + repository: "https://charts.bitnami.com/bitnami" \ No newline at end of file diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 59e8224..30c6783 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -50,6 +50,15 @@ app.kubernetes.io/name: {{ include "grader-api.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} +{{/* +Flower selector labels +*/}} +{{- define "grader-api.flowerSelectorLabels" -}} +app.kubernetes.io/name: {{ include "grader-api.name" . }}-flower +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + {{/* Create the name of the service account to use */}} @@ -66,4 +75,11 @@ Print the Grader API postgresql secret name */}} {{- define "grader-api.postgresqlSecretName" -}} {{- printf "%s" .Values.postgresql.auth.existingSecret }} +{{- end }} + +{{/* +Print the Grader API redis secret name +*/}} +{{- define "grader-api.redisSecretName" -}} +{{- printf "%s" .Values.redis.auth.existingSecret }} {{- end }} \ No newline at end of file diff --git a/templates/celery-deployment.yaml b/templates/celery-deployment.yaml new file mode 100644 index 0000000..a0f1080 --- /dev/null +++ b/templates/celery-deployment.yaml @@ -0,0 +1,227 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "grader-api.fullname" . }}-celery + labels: + {{- include "grader-api.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "grader-api.flowerSelectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "grader-api.flowerSelectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "grader-api.fullname" . }}-sa + securityContext: + {{- toYaml .Values.celery.podSecurityContext | nindent 8 }} + initContainers: + {{- if .Values.postgresql.enabled }} + - name: wait-for-postgresql + image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}" + imagePullPolicy: "{{ .Values.postgresql.image.pullPolicy }}" + command: + - sh + - -c + - until pg_isready -h {{ include "grader-api.fullname" . }}-postgresql -p 5432 -U postgres; do echo "waiting for postgresql"; sleep 5; done + {{- end }} + {{ if .Values.redis.enabled }} + - name: wait-for-redis + image: goodsmileduck/redis-cli:6.0.4 + command: ['sh', '-c', 'until [ "$(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDIS_PASSWORD} --user ${REDIS_USER} ping | grep PONG)" = "PONG" ]; do echo waiting for redis; sleep 2; done;'] + env: + - name: REDIS_HOST + valueFrom: + configMapKeyRef: + name: {{ include "grader-api.fullname" . }} + key: BROKER_HOST + - name: REDIS_PORT + valueFrom: + configMapKeyRef: + name: {{ include "grader-api.fullname" . }} + key: BROKER_PORT + - name: REDIS_USER + valueFrom: + configMapKeyRef: + name: {{ include "grader-api.fullname" . }} + key: BROKER_USER + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "grader-api.redisSecretName" . }} + key: BROKER_PASSWORD + {{ end }} + containers: + - name: celery-worker + securityContext: + {{- toYaml .Values.celery.worker.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["celery"] + args: [ + "-A", "app.celery", + "worker", + "--pool", "{{ .Values.celery.worker.options.pool }}", + "--concurrency", "{{ .Values.celery.worker.options.concurrency }}", + "--loglevel", "{{ .Values.celery.worker.options.loglevel }}" + ] + livenessProbe: + exec: + command: ["celery"] + args: [ + "-A", "app.celery", + "inspect", + "ping", + "-d", "celery@$HOSTNAME", + "--timeout", "{{ .Values.celery.worker.livenessProbe.timeoutSeconds }}" + ] + timeoutSeconds: {{ .Values.celery.worker.livenessProbe.timeoutSeconds }} + initialDelaySeconds: {{ .Values.celery.worker.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.celery.worker.livenessProbe.periodSeconds }} + readinessProbe: + exec: + command: ["celery"] + args: [ + "-A", "app.celery", + "inspect", + "ping", + "-d", "celery@$HOSTNAME", + "--timeout", "{{ .Values.celery.worker.readinessProbe.timeoutSeconds }}" + ] + timeoutSeconds: {{ .Values.celery.worker.readinessProbe.timeoutSeconds }} + initialDelaySeconds: {{ .Values.celery.worker.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.celery.worker.readinessProbe.periodSeconds }} + resources: + {{- toYaml .Values.celery.worker.resources | nindent 12 }} + envFrom: + - configMapRef: + name: {{ include "grader-api.fullname" . }} + - secretRef: + name: {{ include "grader-api.fullname" . }} + {{- if .Values.postgresql.enabled }} + - secretRef: + name: {{ .Values.postgresql.auth.existingSecret }} + {{- end }} + {{- if .Values.redis.enabled }} + - secretRef: + name: {{ .Values.redis.auth.existingSecret }} + {{- end }} + - name: celery-beat + securityContext: + {{- toYaml .Values.celery.beat.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["celery"] + args: [ + "-A", "app.celery", + "beat", + "--loglevel", "{{ .Values.celery.beat.options.loglevel }}" + ] + livenessProbe: + exec: + command: ["celery"] + args: [ + "-A", "app.celery", + "inspect", + "ping", + "-d", "celery@$HOSTNAME", + "--timeout", "{{ .Values.celery.beat.livenessProbe.timeoutSeconds }}" + ] + timeoutSeconds: {{ .Values.celery.beat.livenessProbe.timeoutSeconds }} + initialDelaySeconds: {{ .Values.celery.beat.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.celery.beat.livenessProbe.periodSeconds }} + readinessProbe: + exec: + command: ["celery"] + args: [ + "-A", "app.celery", + "inspect", + "ping", + "-d", "celery@$HOSTNAME", + "--timeout", "{{ .Values.celery.beat.readinessProbe.timeoutSeconds }}" + ] + timeoutSeconds: {{ .Values.celery.beat.readinessProbe.timeoutSeconds }} + initialDelaySeconds: {{ .Values.celery.beat.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.celery.beat.readinessProbe.periodSeconds }} + resources: + {{- toYaml .Values.celery.beat.resources | nindent 12 }} + envFrom: + - configMapRef: + name: {{ include "grader-api.fullname" . }} + - secretRef: + name: {{ include "grader-api.fullname" . }} + {{- if .Values.postgresql.enabled }} + - secretRef: + name: {{ .Values.postgresql.auth.existingSecret }} + {{- end }} + {{- if .Values.redis.enabled }} + - secretRef: + name: {{ .Values.redis.auth.existingSecret }} + {{- end }} + {{- if .Values.celery.flower.enabled }} + - name: celery-flower + securityContext: + {{- toYaml .Values.celery.flower.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["celery"] + args: [ + "-A", "app.celery", + "flower" + ] + ports: + - name: http + containerPort: 5555 + protocol: TCP + livenessProbe: + tcpSocket: + port: 5555 + timeoutSeconds: {{ .Values.celery.flower.livenessProbe.timeoutSeconds }} + initialDelaySeconds: {{ .Values.celery.flower.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.celery.flower.livenessProbe.periodSeconds }} + readinessProbe: + tcpSocket: + port: 5555 + timeoutSeconds: {{ .Values.celery.flower.readinessProbe.timeoutSeconds }} + initialDelaySeconds: {{ .Values.celery.flower.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.celery.flower.readinessProbe.periodSeconds }} + resources: + {{- toYaml .Values.celery.flower.resources | nindent 12 }} + envFrom: + - configMapRef: + name: {{ include "grader-api.fullname" . }} + - secretRef: + name: {{ include "grader-api.fullname" . }} + {{- if .Values.postgresql.enabled }} + - secretRef: + name: {{ .Values.postgresql.auth.existingSecret }} + {{- end }} + {{- if .Values.redis.enabled }} + - secretRef: + name: {{ .Values.redis.auth.existingSecret }} + {{- end }} + {{- 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/templates/configmap.yaml b/templates/configmap.yaml index b6d6837..dfd7e6a 100644 --- a/templates/configmap.yaml +++ b/templates/configmap.yaml @@ -6,4 +6,11 @@ metadata: data: {{- toYaml .Values.config.data | nindent 2 }} POSTGRES_HOST: {{ printf "%s-%s" (include "grader-api.fullname" .) "postgresql" }} + BROKER_HOST: {{ printf "%s-%s" (include "grader-api.fullname" .) "redis-master" }} + {{ if .Values.redis.sentinel.enabled }} + BROKER_PORT: "{{ .Values.redis.sentinel.service.ports.redis }}" + {{ else }} + BROKER_PORT: "{{ .Values.redis.master.service.ports.redis }}" + {{ end }} + BROKER_USER: default {{- end }} diff --git a/templates/deployment.yaml b/templates/deployment.yaml index 340cb95..5232a90 100644 --- a/templates/deployment.yaml +++ b/templates/deployment.yaml @@ -28,9 +28,15 @@ spec: securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} initContainers: - - name: wait-for-postgres - image: busybox:1.28 - command: ['sh', '-c', 'until nc -z {{ printf "%s%s" (include "grader-api.fullname" .) "-postgresql" }} 5432; do echo waiting for postgres; sleep 2; done;'] + {{- if .Values.postgresql.enabled }} + - name: wait-for-postgresql + image: "{{ .Values.postgresql.image.repository }}:{{ .Values.postgresql.image.tag }}" + imagePullPolicy: "{{ .Values.postgresql.image.pullPolicy }}" + command: + - sh + - -c + - until pg_isready -h {{ include "grader-api.fullname" . }}-postgresql -p 5432 -U postgres; do echo "waiting for postgresql"; sleep 5; done + {{- end }} containers: - name: {{ .Chart.Name }} securityContext: @@ -66,6 +72,10 @@ spec: - secretRef: name: {{ .Values.postgresql.auth.existingSecret }} {{- end }} + {{- if .Values.redis.enabled }} + - secretRef: + name: {{ .Values.redis.auth.existingSecret }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/templates/flower-service.yaml b/templates/flower-service.yaml new file mode 100644 index 0000000..7f832ad --- /dev/null +++ b/templates/flower-service.yaml @@ -0,0 +1,17 @@ +{{- if .Values.celery.flower.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "grader-api.fullname" . }}-flower + labels: + {{- include "grader-api.labels" . | nindent 4 }} +spec: + type: {{ .Values.celery.flower.service.type }} + ports: + - port: {{ .Values.celery.flower.service.port }} + targetPort: 5555 + protocol: TCP + name: http + selector: + {{- include "grader-api.flowerSelectorLabels" . | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/templates/redis-secret.yaml b/templates/redis-secret.yaml new file mode 100644 index 0000000..b52b872 --- /dev/null +++ b/templates/redis-secret.yaml @@ -0,0 +1,14 @@ +{{- if and (.Release.IsInstall) (.Values.redis.enabled) }} +{{- if not (lookup "v1" "Secret" .Release.Namespace (include "grader-api.redisSecretName" .)) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "grader-api.redisSecretName" . }} + annotations: + helm.sh/resource-policy: keep +data: + {{- $redisPassword := (randAlphaNum 24 | b64enc) }} + redis-password: {{ $redisPassword }} + BROKER_PASSWORD: {{ $redisPassword }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/secret.yaml b/templates/secret.yaml index 133af91..2be5bcf 100644 --- a/templates/secret.yaml +++ b/templates/secret.yaml @@ -5,4 +5,16 @@ metadata: name: {{ include "grader-api.fullname" . }} stringData: {{- toYaml .Values.config.secretData | nindent 2 }} + {{- $flowerPassword := "" }} + {{ if .Values.celery.flower.auth.password }} + {{- $flowerPassword = .Values.celery.flower.auth.password }} + {{- else }} + {{- if .Release.IsInstall }} + {{- $flowerPassword = randAlphaNum 20 }} + {{ else }} + {{- $flowerPassword = index (lookup "v1" "Secret" .Release.Namespace ( include "grader-api.fullname" . )).data "FLOWER_PASSWORD" | b64dec }} + {{ end }} + {{- end }} + FLOWER_PASSWORD: {{ $flowerPassword }} + FLOWER_BASIC_AUTH: "{{ .Values.celery.flower.auth.username }}:{{ $flowerPassword }}" {{- end }} \ No newline at end of file diff --git a/values.yaml b/values.yaml index 2210962..ef2bbe2 100644 --- a/values.yaml +++ b/values.yaml @@ -25,10 +25,12 @@ serviceAccount: podAnnotations: {} -podSecurityContext: {} +podSecurityContext: + runAsGroup: 0 # fsGroup: 2000 -securityContext: {} +securityContext: + runAsGroup: 0 # capabilities: # drop: # - ALL @@ -81,15 +83,74 @@ tolerations: [] affinity: {} +celery: + flower: + enabled: true + auth: + username: admin + password: "" + service: + type: ClusterIP + port: 5555 + resources: {} + securityContext: + runAsGroup: 0 + livenessProbe: + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 10 + readinessProbe: + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + worker: + options: + pool: prefork + concurrency: 4 + loglevel: info + resources: {} + securityContext: + runAsGroup: 0 + livenessProbe: + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 10 + readinessProbe: + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + beat: + options: + loglevel: info + resources: {} + securityContext: + runAsGroup: 0 + livenessProbe: + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 10 + readinessProbe: + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 10 + podSecurityContext: + runAsGroup: 0 + config: enabled: true data: DEV_PHASE: dev + DOCUMENTATION_URL: https://renci.atlassian.net/wiki/spaces/EHI/overview GITEA_SSH_URL: ssh://git@:2222 GITEA_ASSIST_API_URL: POSTGRES_PORT: "5432" POSTGRES_DB: postgres POSTGRES_USER: postgres + CANVAS_API_KEY: "YOUR_API_KEY" + CANVAS_API_URL: "https://uncch.instructure.com/api/v1" + CANVAS_COURSE_ID: "12345" + CANVAS_COURSE_START_DATE: "1970-01-01T00:00:00Z" + CANVAS_COURSE_END_DATE: "9999-01-01T00:00:00Z" STUDENT_APPSTORE_HOST: "http://my-student-appstore-service:8000" INSTRUCTOR_APPSTORE_HOST: "http://my-instructor-appstore-service:8000" LDAP_HOST: ldap.unc.edu @@ -118,3 +179,8 @@ postgresql: enabled: true auth: existingSecret: grader-api-postgresql + +redis: + enabled: true + auth: + existingSecret: grader-api-redis-password \ No newline at end of file