diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml deleted file mode 100644 index 2eb7dec4..00000000 --- a/.github/workflows/publish_docs.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: publish_docs - -on: - pull_request: - push: - branches: - - main - paths: - - 'docs/sources/**' - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Check out code - uses: actions/checkout@v1 - - name: Build Website - run: | - docker run -v ${PWD}/sources:/hugo/content/docs/amixr --rm grafana/docs-base:latest /bin/bash -c 'make hugo' -# sync: -# runs-on: ubuntu-latest -# needs: test -# if: github.ref == 'refs/heads/main' -# steps: -# - uses: actions/checkout@v1 -# - run: git clone --single-branch --no-tags --depth 1 -b master https://grafanabot:${{ secrets.GH_BOT_ACCESS_TOKEN }}@github.com/grafana/website-sync ./.github/actions/website-sync -# - name: publish-to-git -# uses: ./.github/actions/website-sync -# id: publish -# with: -# repository: grafana/website -# branch: master -# host: github.com -# github_pat: '${{ secrets.GH_BOT_ACCESS_TOKEN }}' -# source_folder: docs/sources -# target_folder: content/docs/amixr/v0.0.39 -# - shell: bash -# run: | -# test -n "${{ steps.publish.outputs.commit_hash }}" -# test -n "${{ steps.publish.outputs.working_directory }}" diff --git a/DEVELOPER.md b/DEVELOPER.md index 08086609..37a0a526 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -64,7 +64,7 @@ python manage.py createsuperuser 3. Launch the backend: ```bash # Http server: -python manage.py runserver +python manage.py runserver 8080 # Worker for background tasks (run it in the parallel terminal, don't forget to export .env there) python manage.py start_celery @@ -226,6 +226,7 @@ pytest --ds=settings.dev - Set Settings to settings/dev.py 5. Create a new Django Server run configuration to Run/Debug the engine - Use a plugin such as EnvFile to load the .env file + - Change port from 8000 to 8080 ## Update drone build The .drone.yml build file must be signed when changes are made to it. Follow these steps: diff --git a/README.md b/README.md index b9569831..81e710fd 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ We prepared multiple environments: [production](https://grafana.com/docs/grafana 1. Download docker-compose.yaml: ```bash -curl https://github.com/grafana/oncall/blob/dev/docker-compose.yml -o docker-compose.yaml +curl -fsSL https://raw.githubusercontent.com/grafana/oncall/dev/docker-compose.yml -o docker-compose.yaml ``` 2. Set variables: diff --git a/docker-compose.yml b/docker-compose.yml index c4695fd8..3642e441 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,6 @@ services: engine: - # TODO: change to the public image once it's public - # image: ... - build: engine + image: grafana/oncall ports: - 8080:8080 command: > @@ -36,7 +34,7 @@ services: celery: # TODO: change to the public image once it's public - build: engine + image: grafana/oncall command: sh -c "./celery_with_exporter.sh" environment: BASE_URL: $DOMAIN @@ -70,7 +68,7 @@ services: condition: service_started oncall_db_migration: - build: engine + image: grafana/oncall command: python manage.py migrate --noinput environment: BASE_URL: $DOMAIN diff --git a/docs/img/architecture_diagram.png b/docs/img/architecture_diagram.png new file mode 100644 index 00000000..cec88050 Binary files /dev/null and b/docs/img/architecture_diagram.png differ diff --git a/engine/settings/helm.py b/engine/settings/helm.py new file mode 100644 index 00000000..5e35613b --- /dev/null +++ b/engine/settings/helm.py @@ -0,0 +1,85 @@ +import os +import sys + +# Workaround to use pymysql instead of mysqlclient +import pymysql + +from .prod_without_db import * # noqa + +pymysql.install_as_MySQLdb() + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.mysql", + "NAME": os.environ.get("MYSQL_DB_NAME"), + "USER": os.environ.get("MYSQL_USER"), + "PASSWORD": os.environ["MYSQL_PASSWORD"], + "HOST": os.environ.get("MYSQL_HOST"), + "PORT": os.environ.get("MYSQL_PORT"), + "OPTIONS": { + "charset": "utf8mb4", + "connect_timeout": 1, + }, + }, +} + +RABBITMQ_USERNAME = os.environ.get("RABBITMQ_USERNAME") +RABBITMQ_PASSWORD = os.environ.get("RABBITMQ_PASSWORD") +RABBITMQ_HOST = os.environ.get("RABBITMQ_HOST") +RABBITMQ_PORT = os.environ.get("RABBITMQ_PORT") + +CELERY_BROKER_URL = f"amqp://{RABBITMQ_USERNAME}:{RABBITMQ_PASSWORD}@{RABBITMQ_HOST}:{RABBITMQ_PORT}" + +REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD") +REDIS_HOST = os.environ.get("REDIS_HOST") +REDIS_PORT = os.environ.get("REDIS_PORT", "6379") +REDIS_URI = f"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}" + +CACHES = { + "default": { + "BACKEND": "redis_cache.RedisCache", + "LOCATION": [ + REDIS_URI, + ], + "OPTIONS": { + "DB": 1, + "PARSER_CLASS": "redis.connection.HiredisParser", + "CONNECTION_POOL_CLASS": "redis.BlockingConnectionPool", + "CONNECTION_POOL_CLASS_KWARGS": { + "max_connections": 50, + "timeout": 20, + }, + "MAX_CONNECTIONS": 1000, + "PICKLE_VERSION": -1, + }, + }, +} + +APPEND_SLASH = False +SECURE_SSL_REDIRECT = False + +TESTING = "pytest" in sys.modules or "unittest" in sys.modules + + +if TESTING: + TELEGRAM_TOKEN = "0000000000:XXXXXXXXXXXXXXXXXXXXXXXXXXXX-XXXXXX" + TWILIO_AUTH_TOKEN = "twilio_auth_token" + +# TODO: OSS: Add these setting to oss settings file. Add Version there too. +OSS_INSTALLATION_FEATURES_ENABLED = True + +INSTALLED_APPS += ["apps.oss_installation"] # noqa + +CELERY_BEAT_SCHEDULE["send_usage_stats"] = { # noqa + "task": "apps.oss_installation.tasks.send_usage_stats_report", + "schedule": crontab(hour=0, minute=randrange(0, 59)), # Send stats report at a random minute past midnight # noqa + "args": (), +} # noqa + +CELERY_BEAT_SCHEDULE["send_cloud_heartbeat"] = { # noqa + "task": "apps.oss_installation.tasks.send_cloud_heartbeat", + "schedule": crontab(minute="*/3"), # noqa + "args": (), +} # noqa + +SEND_ANONYMOUS_USAGE_STATS = True diff --git a/grafana-plugin/CHANGELOG.md b/grafana-plugin/CHANGELOG.md deleted file mode 120000 index 04c99a55..00000000 --- a/grafana-plugin/CHANGELOG.md +++ /dev/null @@ -1 +0,0 @@ -../CHANGELOG.md \ No newline at end of file diff --git a/grafana-plugin/CHANGELOG.md b/grafana-plugin/CHANGELOG.md new file mode 100644 index 00000000..8893332c --- /dev/null +++ b/grafana-plugin/CHANGELOG.md @@ -0,0 +1,5 @@ +# Change Log + +## 0.0.71 (2022-06-06) + +- Initial Release \ No newline at end of file diff --git a/helm/oncall/.helmignore b/helm/oncall/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/helm/oncall/.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/helm/oncall/Chart.yaml b/helm/oncall/Chart.yaml new file mode 100644 index 00000000..81051591 --- /dev/null +++ b/helm/oncall/Chart.yaml @@ -0,0 +1,43 @@ +apiVersion: v2 +name: oncall +description: Developer-friendly incident response with brilliant Slack integration + + +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.0 + +# 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: "v1.0.0" +dependencies: + - name: cert-manager + version: v1.8.0 + repository: https://charts.jetstack.io + condition: cert-manager.enabled + + - name: mariadb + version: 11.0.10 + repository: https://charts.bitnami.com/bitnami + condition: mariadb.enabled + - name: rabbitmq + version: 10.1.1 + repository: https://charts.bitnami.com/bitnami + condition: rabbitmq.enabled + - name: redis + version: 16.10.1 + repository: https://charts.bitnami.com/bitnami + condition: redis.enabled + - name: grafana + version: 6.29.6 + repository: https://grafana.github.io/helm-charts + condition: grafana.enabled + - name: ingress-nginx + version: 4.1.4 + repository: https://kubernetes.github.io/ingress-nginx + condition: ingress-nginx.enabled \ No newline at end of file diff --git a/helm/oncall/README.md b/helm/oncall/README.md new file mode 100644 index 00000000..2aa7845d --- /dev/null +++ b/helm/oncall/README.md @@ -0,0 +1,120 @@ +# Grafana OnCall Helm Chart + +This Grafana OnCall Chart is the best way to operate Grafana OnCall on Kubernetes. +It will deploy Grafana OnCall engine and celery workers, along with RabbitMQ cluster, Redis Cluster, and MySQL 5.7 database. +It will also deploy cert manager and nginx ingress controller, as Grafana OnCall backend might need to be externally available +to receive alerts from other monitoring systems. Grafana OnCall engine acts as a backend and can be connected to the Grafana frontend plugin named Grafana OnCall. +Architecture diagram can be found [here](https://raw.githubusercontent.com/grafana/oncall/dev/docs/img/architecture_diagram.png) + +> Default helm chart configuration is not intended for production. The helm chart includes all the services into a single release, +> which is not recommended for production usage. It is recommended to run stateful services such as MySQL and RabbitMQ +> separately from this release or use managed PaaS solutions. It will significantly reduce the overhead of managing them + + +Cluster requirements: +* ensure you can run x86-64/amd64 workloads. arm64 architecture is currently not supported + +## Install +### Installing the helm chart +```bash +helm install \ + --wait \ + --set base_url=example.com \ + --set grafana."grafana\.ini".server.domain=example.com \ + oncall \ + . +``` + +Follow the `helm install` output to finish setting up Grafana OnCall backend and Grafana OnCall frontend plugin + +## Configuration + +You can edit values.yml to make changes to the helm chart configuration and re-deploy the release with the following command: +```bash +helm upgrade \ + --install \ + --wait \ + --set base_url=example.com \ + --set grafana."grafana\.ini".server.domain=example.com \ + oncall \ + . +``` + +### Set up external access +Grafana OnCall can be connected to the external monitoring systems or grafana deployed to the other cluster. +Nginx Ingress Controller and Cert Manager charts are included in the helm chart with the default configuration. +If you set the DNS A Record pointing to the external IP address of the installation with the Hostname matching base_url parameter, https will be automatically set up. If grafana is enabled in the chart values, it will also be available on https:///grafana/. See the details in `helm install` output. + +To use a different ingress controller or tls certificate management system, set the following values to false and edit ingress settings + +``` +nginx-ingress: + enabled: false + +cert-manager: + enabled: false + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + cert-manager.io/issuer: "letsencrypt-prod" +``` + +### Connect external MySQL + +It is recommended to use the managed MySQL 5.7 database provided by your cloud provider +Make sure to create the database with the following parameters before installing this chart +``` +CREATE DATABASE oncall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +``` + +To use an external MySQL instance set mysql.enabled to `false` and configure the `externalMysql` parameters. +``` +mariadb: + enabled: true + +# Make sure to create the database with the following parameters: +# CREATE DATABASE oncall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +externalMysql: + host: + port: + db_name: + user: + password: + ``` + +### Connect external RabbitMQ + +Option 1. Install RabbitMQ separately into the cluster using the [official documentation](https://www.rabbitmq.com/kubernetes/operator/operator-overview.html) +Option 2. Use managed solution such as [CloudAMPQ](https://www.cloudamqp.com/) + +To use an external RabbitMQ instance set rabbitmq.enabled to `false` and configure the `externalRabbitmq` parameters. +``` +rabbitmq: + enabled: false # Disable the RabbitMQ dependency from the release + +externalRabbitmq: + host: + port: + user: + password: +``` + +## Uninstall +### Uninstalling the helm chart +```bash +helm delete oncall +``` + +### Clean up PVC's +```bash +kubectl delete pvc data-oncall-mariadb-0 data-oncall-rabbitmq-0 \ +redis-data-oncall-redis-master-0 redis-data-oncall-redis-replicas-0 \ +redis-data-oncall-redis-replicas-1 redis-data-oncall-redis-replicas-2 +``` + +### Clean up secrets +```bash +kubectl delete secrets certificate-tls oncall-cert-manager-webhook-ca oncall-ingress-nginx-admission +``` diff --git a/helm/oncall/charts/cert-manager-v1.8.0.tgz b/helm/oncall/charts/cert-manager-v1.8.0.tgz new file mode 100644 index 00000000..c04b5b79 Binary files /dev/null and b/helm/oncall/charts/cert-manager-v1.8.0.tgz differ diff --git a/helm/oncall/charts/grafana-6.29.6.tgz b/helm/oncall/charts/grafana-6.29.6.tgz new file mode 100644 index 00000000..ed0a64c9 Binary files /dev/null and b/helm/oncall/charts/grafana-6.29.6.tgz differ diff --git a/helm/oncall/charts/ingress-nginx-4.1.4.tgz b/helm/oncall/charts/ingress-nginx-4.1.4.tgz new file mode 100644 index 00000000..2c999e7a Binary files /dev/null and b/helm/oncall/charts/ingress-nginx-4.1.4.tgz differ diff --git a/helm/oncall/charts/mariadb-11.0.10.tgz b/helm/oncall/charts/mariadb-11.0.10.tgz new file mode 100644 index 00000000..0e41a301 Binary files /dev/null and b/helm/oncall/charts/mariadb-11.0.10.tgz differ diff --git a/helm/oncall/charts/rabbitmq-10.1.1.tgz b/helm/oncall/charts/rabbitmq-10.1.1.tgz new file mode 100644 index 00000000..955e49d1 Binary files /dev/null and b/helm/oncall/charts/rabbitmq-10.1.1.tgz differ diff --git a/helm/oncall/charts/redis-16.10.1.tgz b/helm/oncall/charts/redis-16.10.1.tgz new file mode 100644 index 00000000..dfb1e8df Binary files /dev/null and b/helm/oncall/charts/redis-16.10.1.tgz differ diff --git a/helm/oncall/templates/NOTES.txt b/helm/oncall/templates/NOTES.txt new file mode 100644 index 00000000..95573ac4 --- /dev/null +++ b/helm/oncall/templates/NOTES.txt @@ -0,0 +1,54 @@ +================================================================= +📞 Grafana OnCall Notes +================================================================= + +👋 Your Grafana OnCall instance has been successfully deployed + +TODO: Add disclaimer about stateful services, ingress controller, certificates + +{{- if not .Values.migrate.enabled }} + 🤖 To migrate the database run these commands: + + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oncall.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=engine" -o jsonpath="{.items[0].metadata.name}") + kubectl exec -it $POD_NAME -c wait-for-db -- bash -c "python manage.py migrate;" +{{- end }} + + ❗ Set up a DNS record for your domain (use A Record and "@" to point a root domain to the IP address) + Get the external IP address by running the following commands and point {{ .Values.base_url }} to it: + + kubectl get ingress {{ include "oncall.fullname" . }} -o jsonpath="{.status.loadBalancer.ingress[0].ip}" + + Wait until the dns record got propagated. + NOTE: Check with the following command: nslookup {{ .Values.base_url }} + Try reaching https://{{ .Values.base_url }}/ready/ from the browser, make sure it is not cached locally + +{{- if .Values.grafana.enabled }} + 🦎 Grafana was installed as a part of this helm release. Open https://{{ .Values.base_url }}/grafana/plugins/grafana-oncall-app + The User is {{ .Values.grafana.adminUser }} + Get password by running this command: + + kubectl get secret --namespace {{ .Release.Namespace }} {{ template "oncall.grafana.fullname" . }} -o jsonpath="{.data.admin-password}" | base64 --decode ; echo + +{{- else }} + 🦎 Grafana was NOT installed as a part of this helm release. Open external Grafana, go to "Configuration" - "Plugins" and find Grafana OnCall plugin + NOTE: Make sure your external Grafana is available by the network for the containers installed by this release. +{{- end }} + + 🔗 Connect Grafana OnCall Plugin to Grafana OnCall backend: + + Issue the one-time token to connect Grafana OnCall backend and Grafana OnCall plugin by running these commands: + + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "oncall.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=engine" -o jsonpath="{.items[0].metadata.name}") + kubectl exec -it $POD_NAME -- bash -c "python manage.py issue_invite_for_the_frontend --override" + + Fill the Grafana OnCall Backend URL: + + http://{{ include "oncall.engine.fullname" . }}:8080 + + Fill the Grafana URL: + + {{ if .Values.grafana.enabled }}http://{{ include "oncall.grafana.fullname" . }}{{ else }}https://{{- end }} + + + +🎉🎉🎉 Done! 🎉🎉🎉 diff --git a/helm/oncall/templates/_env.tpl b/helm/oncall/templates/_env.tpl new file mode 100644 index 00000000..db8b3e14 --- /dev/null +++ b/helm/oncall/templates/_env.tpl @@ -0,0 +1,165 @@ +{{- define "snippet.oncall.env" -}} +- name: BASE_URL + value: https://{{ .Values.base_url }} +- name: SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ template "oncall.fullname" . }} + key: SECRET_KEY +- name: MIRAGE_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ template "oncall.fullname" . }} + key: MIRAGE_SECRET_KEY +- name: MIRAGE_CIPHER_IV + value: "1234567890abcdef" +- name: DJANGO_SETTINGS_MODULE + value: "settings.helm" +- name: AMIXR_DJANGO_ADMIN_PATH + value: "admin" +- name: OSS + value: "True" +{{- end }} + +{{- define "snippet.celery.env" -}} +- name: CELERY_WORKER_QUEUE + value: "default,critical,long,slack,telegram,webhook,celery" +- name: CELERY_WORKER_CONCURRENCY + value: "1" +- name: CELERY_WORKER_MAX_TASKS_PER_CHILD + value: "100" +- name: CELERY_WORKER_SHUTDOWN_INTERVAL + value: "65m" +- name: CELERY_WORKER_BEAT_ENABLED + value: "True" +{{- end }} + +{{- define "snippet.mysql.env" -}} +- name: MYSQL_HOST + value: {{ include "snippet.mysql.host" . }} +- name: MYSQL_PORT + value: {{ include "snippet.mysql.port" . }} +- name: MYSQL_DB_NAME + value: {{ include "snippet.mysql.db" . }} +- name: MYSQL_USER + value: {{ include "snippet.mysql.user" . }} +- name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "snippet.mysql.password.secret.name" . }} + key: mariadb-root-password +{{- end }} + +{{- define "snippet.mysql.password.secret.name" -}} +{{- if and (not .Values.mariadb.enabled) .Values.externalMysql.password -}} +{{ include "oncall.fullname" . }}-mysql-external +{{- else -}} +{{ include "oncall.mariadb.fullname" . }} +{{- end -}} +{{- end -}} + +{{- define "snippet.mysql.host" -}} +{{- if and (not .Values.mariadb.enabled) .Values.externalMysql.host -}} +{{- required "externalMysql.host is required if not mariadb.enabled" .Values.externalMysql.host | quote }} +{{- else -}} +{{ include "oncall.mariadb.fullname" . }} +{{- end -}} +{{- end -}} + +{{- define "snippet.mysql.port" -}} +{{- if and (not .Values.mariadb.enabled) .Values.externalMysql.port -}} +{{- required "externalMysql.port is required if not mariadb.enabled" .Values.externalMysql.port | quote }} +{{- else -}} +"3306" +{{- end -}} +{{- end -}} + +{{- define "snippet.mysql.db" -}} +{{- if and (not .Values.mariadb.enabled) .Values.externalMysql.db -}} +{{- required "externalMysql.db is required if not mariadb.enabled" .Values.externalMysql.db | quote}} +{{- else -}} +"oncall" +{{- end -}} +{{- end -}} + +{{- define "snippet.mysql.user" -}} +{{- if and (not .Values.mariadb.enabled) .Values.externalMysql.user -}} +{{- .Values.externalMysql.user | quote}} +{{- else -}} +"root" +{{- end -}} +{{- end -}} + +{{- define "snippet.rabbitmq.env" -}} +- name: RABBITMQ_USERNAME + value: {{ include "snippet.rabbitmq.user" . }} +- name: RABBITMQ_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "snippet.rabbitmq.password.secret.name" . }} + key: rabbitmq-password +- name: RABBITMQ_HOST + value: {{ include "snippet.rabbitmq.host" . }} +- name: RABBITMQ_PORT + value: {{ include "snippet.rabbitmq.port" . }} +{{- end }} + +{{- define "snippet.rabbitmq.user" -}} +{{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.user -}} +{{- required "externalRabbitmq.user is required if not rabbitmq.enabled" .Values.externalRabbitmq.user | quote }} +{{- else -}} +"user" +{{- end -}} +{{- end -}} + +{{- define "snippet.rabbitmq.host" -}} +{{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.host -}} +{{- required "externalRabbitmq.host is required if not rabbitmq.enabled" .Values.externalRabbitmq.host | quote }} +{{- else -}} +{{ include "oncall.rabbitmq.fullname" . }} +{{- end -}} +{{- end -}} + +{{- define "snippet.rabbitmq.port" -}} +{{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.port -}} +{{- required "externalRabbitmq.port is required if not rabbitmq.enabled" .Values.externalRabbitmq.port | quote }} +{{- else -}} +"5672" +{{- end -}} +{{- end -}} + +{{- define "snippet.rabbitmq.password.secret.name" -}} +{{- if and (not .Values.rabbitmq.enabled) .Values.externalRabbitmq.password -}} +{{ include "oncall.fullname" . }}-rabbitmq-external +{{- else -}} +{{ include "oncall.rabbitmq.fullname" . }} +{{- end -}} +{{- end -}} + +{{- define "snippet.redis.host" -}} +{{- if and (not .Values.redis.enabled) .Values.externalRedis.host -}} +{{- required "externalRedis.host is required if not redis.enabled" .Values.externalRedis.host | quote }} +{{- else -}} +{{ include "oncall.redis.fullname" . }}-master +{{- end -}} +{{- end -}} + +{{- define "snippet.redis.password.secret.name" -}} +{{- if and (not .Values.redis.enabled) .Values.externalRedis.password -}} +{{ include "oncall.fullname" . }}-redis-external +{{- else -}} +{{ include "oncall.redis.fullname" . }} +{{- end -}} +{{- end -}} + +{{- define "snippet.redis.env" -}} +- name: REDIS_HOST + value: {{ include "snippet.redis.host" . }} +- name: REDIS_PORT + value: "6379" +- name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "snippet.redis.password.secret.name" . }} + key: redis-password +{{- end }} diff --git a/helm/oncall/templates/_helpers.tpl b/helm/oncall/templates/_helpers.tpl new file mode 100644 index 00000000..bf137b40 --- /dev/null +++ b/helm/oncall/templates/_helpers.tpl @@ -0,0 +1,96 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "oncall.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 "oncall.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 "oncall.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "oncall.labels" -}} +helm.sh/chart: {{ include "oncall.chart" . }} +{{ include "oncall.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "oncall.selectorLabels" -}} +app.kubernetes.io/name: {{ include "oncall.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "oncall.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "oncall.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* Generate the fullname of mariadb subchart */}} +{{- define "oncall.mariadb.fullname" -}} +{{- printf "%s-%s" .Release.Name "mariadb" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "oncall.grafana.fullname" -}} +{{- printf "%s-%s" .Release.Name "grafana" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* Generate the fullname of rabbitmq subchart */}} +{{- define "oncall.rabbitmq.fullname" -}} +{{- printf "%s-%s" .Release.Name "rabbitmq" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* Generate the fullname of redis subchart */}} +{{- define "oncall.redis.fullname" -}} +{{- printf "%s-%s" .Release.Name "redis" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "oncall.mariadb.wait-for-db" }} +- name: wait-for-db + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ['sh', '-c', "until (python manage.py migrate --check); do echo Waiting for database migrations; sleep 2; done"] + env: + {{- include "snippet.oncall.env" . | nindent 12 }} + {{- include "snippet.mysql.env" . | nindent 12 }} + {{- include "snippet.rabbitmq.env" . | nindent 12 }} + {{- include "snippet.redis.env" . | nindent 12 }} + {{- if .Values.env }} + {{- toYaml .Values.env | nindent 12 }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/helm/oncall/templates/celery/_deployment.tpl b/helm/oncall/templates/celery/_deployment.tpl new file mode 100644 index 00000000..e8a7d40c --- /dev/null +++ b/helm/oncall/templates/celery/_deployment.tpl @@ -0,0 +1,60 @@ +{{- define "template.oncall.celery.deployment" -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "oncall.celery.fullname" . }} + labels: + {{- include "oncall.celery.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.celery.replicaCount }} + selector: + matchLabels: + {{- include "oncall.celery.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + random-annotation: {{ randAlphaNum 10 | lower }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "oncall.celery.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "oncall.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + command: ["./celery_with_exporter.sh"] + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- include "snippet.celery.env" . | nindent 12 }} + {{- include "snippet.oncall.env" . | nindent 12 }} + {{- include "snippet.mysql.env" . | nindent 12 }} + {{- include "snippet.rabbitmq.env" . | nindent 12 }} + {{- include "snippet.redis.env" . | nindent 12 }} + {{- if .Values.env }} + {{- toYaml .Values.env | nindent 12 }} + {{- end }} + livenessProbe: + exec: + command: [ + "bash", + "-c", + "celery inspect ping -A engine -d celery@$HOSTNAME" + ] + initialDelaySeconds: 30 + periodSeconds: 300 + timeoutSeconds: 10 + resources: + {{- toYaml .Values.celery.resources | nindent 12 }} +{{- end}} \ No newline at end of file diff --git a/helm/oncall/templates/celery/_helpers.tpl b/helm/oncall/templates/celery/_helpers.tpl new file mode 100644 index 00000000..8c37e957 --- /dev/null +++ b/helm/oncall/templates/celery/_helpers.tpl @@ -0,0 +1,26 @@ +{{/* +Maximum of 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "oncall.celery.name" -}} +{{ include "oncall.name" . | trunc 55 }}-celery +{{- end }} + +{{- define "oncall.celery.fullname" -}} +{{ include "oncall.fullname" . | trunc 55 }}-celery +{{- end }} + +{{/* +Engine common labels +*/}} +{{- define "oncall.celery.labels" -}} +{{ include "oncall.labels" . }} +app.kubernetes.io/component: celery +{{- end }} + +{{/* +Engine selector labels +*/}} +{{- define "oncall.celery.selectorLabels" -}} +{{ include "oncall.selectorLabels" . }} +app.kubernetes.io/component: celery +{{- end }} diff --git a/helm/oncall/templates/celery/deployment-celery.yaml b/helm/oncall/templates/celery/deployment-celery.yaml new file mode 100644 index 00000000..a9d49bf1 --- /dev/null +++ b/helm/oncall/templates/celery/deployment-celery.yaml @@ -0,0 +1 @@ +{{ include "template.oncall.celery.deployment" . }} \ No newline at end of file diff --git a/helm/oncall/templates/cert-issuer.yaml b/helm/oncall/templates/cert-issuer.yaml new file mode 100644 index 00000000..60c2b690 --- /dev/null +++ b/helm/oncall/templates/cert-issuer.yaml @@ -0,0 +1,22 @@ +{{- if (index .Values "cert-manager") }} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: letsencrypt-prod + annotations: + "helm.sh/hook": post-install,post-upgrade +spec: + acme: + # The ACME server URL + server: https://acme-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: no-reply@{{ .Values.base_url }} + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-prod + # Enable the HTTP-01 challenge provider + solvers: + - http01: + ingress: + class: nginx +{{- end }} diff --git a/helm/oncall/templates/engine/_helpers-engine.tpl b/helm/oncall/templates/engine/_helpers-engine.tpl new file mode 100644 index 00000000..6d498e93 --- /dev/null +++ b/helm/oncall/templates/engine/_helpers-engine.tpl @@ -0,0 +1,26 @@ +{{/* +Maximum of 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "oncall.engine.name" -}} +{{ include "oncall.name" . | trunc 55 }}-engine +{{- end }} + +{{- define "oncall.engine.fullname" -}} +{{ include "oncall.fullname" . | trunc 55 }}-engine +{{- end }} + +{{/* +Engine common labels +*/}} +{{- define "oncall.engine.labels" -}} +{{ include "oncall.labels" . }} +app.kubernetes.io/component: engine +{{- end }} + +{{/* +Engien selector labels +*/}} +{{- define "oncall.engine.selectorLabels" -}} +{{ include "oncall.selectorLabels" . }} +app.kubernetes.io/component: engine +{{- end }} diff --git a/helm/oncall/templates/engine/deployment.yaml b/helm/oncall/templates/engine/deployment.yaml new file mode 100644 index 00000000..9c9d0f76 --- /dev/null +++ b/helm/oncall/templates/engine/deployment.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "oncall.engine.fullname" . }} + labels: + {{- include "oncall.engine.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.engine.replicaCount }} + selector: + matchLabels: + {{- include "oncall.engine.selectorLabels" . | nindent 6 }} + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + random-annotation: {{ randAlphaNum 10 | lower }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "oncall.engine.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "oncall.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + {{- include "oncall.mariadb.wait-for-db" . | indent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + {{- include "snippet.oncall.env" . | nindent 12 }} + {{- include "snippet.mysql.env" . | nindent 12 }} + {{- include "snippet.rabbitmq.env" . | nindent 12 }} + {{- include "snippet.redis.env" . | nindent 12 }} + {{- if .Values.env }} + {{- toYaml .Values.env | nindent 12 }} + {{- end }} + livenessProbe: + httpGet: + path: /health/ + port: http + periodSeconds: 60 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: /ready/ + port: http + periodSeconds: 60 + timeoutSeconds: 3 + startupProbe: + httpGet: + path: /startupprobe/ + port: http + periodSeconds: 60 + timeoutSeconds: 3 + resources: + {{- toYaml .Values.engine.resources | nindent 12 }} diff --git a/helm/oncall/templates/engine/job-migrate.yaml b/helm/oncall/templates/engine/job-migrate.yaml new file mode 100644 index 00000000..5bfc3019 --- /dev/null +++ b/helm/oncall/templates/engine/job-migrate.yaml @@ -0,0 +1,54 @@ +{{- if .Values.migrate.enabled -}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ printf "%s-migrate-%s" (include "oncall.engine.fullname" .) (now | date "2006-01-02-15-04-05") }} + labels: + {{- include "oncall.engine.labels" . | nindent 4 }} +spec: + ttlSecondsAfterFinished: 20 + template: + metadata: + name: {{ printf "%s-migrate-%s" (include "oncall.engine.fullname" .) (now | date "2006-01-02-15-04-05") }} + {{- with .Values.podAnnotations }} + annotations: + random-annotation: {{ randAlphaNum 10 | lower }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "oncall.engine.selectorLabels" . | nindent 8 }} + spec: + restartPolicy: Never + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "oncall.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }}-migrate + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /bin/sh + - -c + - | + until (nc -vz $MYSQL_HOST $MYSQL_PORT); + do + echo "waiting for MySQL"; sleep 1; + done + python manage.py migrate + env: + {{- include "snippet.oncall.env" . | nindent 12 }} + {{- include "snippet.mysql.env" . | nindent 12 }} + {{- include "snippet.rabbitmq.env" . | nindent 12 }} + {{- include "snippet.redis.env" . | nindent 12 }} + {{- if .Values.env }} + {{- toYaml .Values.env | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.engine.resources | nindent 12 }} +{{- end }} diff --git a/helm/oncall/templates/engine/service-external.yaml b/helm/oncall/templates/engine/service-external.yaml new file mode 100644 index 00000000..9c204a24 --- /dev/null +++ b/helm/oncall/templates/engine/service-external.yaml @@ -0,0 +1,17 @@ +{{- if .Values.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "oncall.engine.fullname" . }}-external + labels: + {{- include "oncall.engine.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "oncall.engine.selectorLabels" . | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/helm/oncall/templates/engine/service-internal.yaml b/helm/oncall/templates/engine/service-internal.yaml new file mode 100644 index 00000000..07785035 --- /dev/null +++ b/helm/oncall/templates/engine/service-internal.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "oncall.engine.fullname" . }} + labels: + {{- include "oncall.engine.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 8080 + targetPort: http + protocol: TCP + name: http + selector: + {{- include "oncall.engine.selectorLabels" . | nindent 4 }} diff --git a/helm/oncall/templates/ingress-regular.yaml b/helm/oncall/templates/ingress-regular.yaml new file mode 100644 index 00000000..31c4e367 --- /dev/null +++ b/helm/oncall/templates/ingress-regular.yaml @@ -0,0 +1,48 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "oncall.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.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 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "oncall.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + tls: + - hosts: + - {{ .Values.base_url | quote }} + secretName: certificate-tls + rules: + - host: {{ .Values.base_url | quote }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "oncall.engine.fullname" . }} + port: + number: 8080 + - path: /grafana + pathType: Prefix + backend: + service: + name: {{ include "oncall.grafana.fullname" . }} + port: + number: 80 +{{- end }} diff --git a/helm/oncall/templates/secrets.yaml b/helm/oncall/templates/secrets.yaml new file mode 100644 index 00000000..2a1ecba9 --- /dev/null +++ b/helm/oncall/templates/secrets.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "oncall.fullname" . }} + labels: + {{- include "oncall.labels" . | nindent 4 }} +type: Opaque +data: + SECRET_KEY: {{ randAlphaNum 40 | b64enc | quote }} + MIRAGE_SECRET_KEY: {{ randAlphaNum 40 | b64enc | quote }} + MIRAGE_CIPHER_IV: {{ randAlphaNum 40 | b64enc | quote }} + +--- +{{ if not .Values.mariadb.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "oncall.fullname" . }}-mysql-external +type: Opaque +data: + mariadb-root-password: {{ required "externalMysql.password is required if not mariadb.enabled" .Values.externalMysql.password | b64enc | quote }} +{{- end }} +--- +{{ if not .Values.rabbitmq.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "oncall.fullname" . }}-rabbitmq-external +type: Opaque +data: + rabbitmq-password: {{ required "externalRabbitmq.password is required if not rabbitmq.enabled" .Values.externalRabbitmq.password | b64enc | quote }} +{{- end }} +--- +{{ if not .Values.redis.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "oncall.fullname" . }}-redis-external +type: Opaque +data: + rabbitmq-password: {{ required "externalRedis.password is required if not redis.enabled" .Values.externalRedis.password | b64enc | quote }} +{{- end }} + diff --git a/helm/oncall/templates/serviceaccount.yaml b/helm/oncall/templates/serviceaccount.yaml new file mode 100644 index 00000000..88184b27 --- /dev/null +++ b/helm/oncall/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "oncall.serviceAccountName" . }} + labels: + {{- include "oncall.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/oncall/templates/tests/test-connection.yaml b/helm/oncall/templates/tests/test-connection.yaml new file mode 100644 index 00000000..fc82b110 --- /dev/null +++ b/helm/oncall/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "oncall.fullname" . }}-test-connection" + labels: + {{- include "oncall.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "oncall.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/helm/oncall/values.yaml b/helm/oncall/values.yaml new file mode 100644 index 00000000..6c781718 --- /dev/null +++ b/helm/oncall/values.yaml @@ -0,0 +1,162 @@ +# Values for configuring the deployment of Grafana OnCall + +# Set the domain name Grafana OnCall will be installed on. +# If you want to install grafana as a part of this release make sure to configure grafana.grafana.ini.server.domain too +base_url: example.com + +image: + # Grafana OnCall docker image repository + repository: grafana/oncall + tag: + pullPolicy: IfNotPresent + +# Whether to create additional service for external connections +# ClusterIP service is always created +service: + enabled: false + type: LoadBalancer + port: 8080 + +# Engine pods configuration +engine: + replicaCount: 1 + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# Celery workers pods configuration +celery: + replicaCount: 1 + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# Whether to run django database migrations automatically +migrate: + enabled: true + +# Additional env variables to add to deployments +env: [] + +# Enable ingress object for external access to the resources +ingress: + enabled: true +# className: "" + annotations: + kubernetes.io/ingress.class: "nginx" + cert-manager.io/issuer: "letsencrypt-prod" + +# Whether to install ingress controller +nginx-ingress: + enabled: true + +# Install cert-manager as a part of the release +cert-manager: + enabled: true + # Instal CRD resources + installCRDs: true + webhook: + timeoutSeconds: 30 + # cert-manager tries to use the already used port, changing to another one + # https://github.com/cert-manager/cert-manager/issues/3237 + # https://cert-manager.io/docs/installation/compatibility/ + securePort: 10260 + # Fix self-checks https://github.com/jetstack/cert-manager/issues/4286 + podDnsPolicy: None + podDnsConfig: + nameservers: + - 8.8.8.8 + - 1.1.1.1 + +# MySQL is included into this release for the convenience. +# It is recommended to host it separately from this release +# Set mariadb.enabled = false and configure externalMysql +mariadb: + enabled: true + auth: + database: oncall + primary: + extraEnvVars: + - name: MARIADB_COLLATE + value: utf8mb4_unicode_ci + - name: MARIADB_CHARACTER_SET + value: utf8mb4 + secondary: + extraEnvVars: + - name: MARIADB_COLLATE + value: utf8mb4_unicode_ci + - name: MARIADB_CHARACTER_SET + value: utf8mb4 + +# Make sure to create the database with the following parameters: +# CREATE DATABASE oncall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +externalMysql: + host: + port: + db_name: + user: + password: + +# RabbitMQ is included into this release for the convenience. +# It is recommended to host it separately from this release +# Set rabbitmq.enabled = false and configure externalRabbitmq +rabbitmq: + enabled: true + +externalRabbitmq: + host: + port: + user: + password: + +redis: + enabled: true + +external_redis: + host: + password: + +grafana: + enabled: true + grafana.ini: + server: + domain: example.com + root_url: "%(protocol)s://%(domain)s/grafana" + serve_from_sub_path: true + persistence: + enabled: true + plugins: + - grafana-oncall-app + +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: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000