Merge dev to main (#73)
* Log (failed) attempt to notify a user with viewer role * Remove old publishing workflow Signed-off-by: Jack Baldry <jack.baldry@grafana.com> * Add publishing workflows for next (unreleased) and released documentation Notable features: - Merges are blocked by strict Hugo reference checking. However, this only works for references that resolve within the repository. Once you have Hugo references to website pages beyond this repository, you will want to remove this test job. - Pushes to main are automatically published to "next" documentation consistent with our other OSS projects. - Pushes of release tags publish to a versioned directory in the website. The website uses `v<MAJOR>.<MINOR>.x` versioning and the "Determine technical documentation version" step will make sure that a tag such as `v0.20.7` is mapped to `v0.20.x`. - Pushes to release branches will only be published if there is an existing corresponding release tag. For example, pushing to a new release branch `release-0.1000` will not trigger a publish of documentation until there is a `v0.1000.0` release tag. > **Note:** I have used a release branch naming convention `release-<MAJOR>-<MINOR>` which is consistent with grafana/mimir but I see that in the old amixr repository there are long lived release branches for patch versions. If that is required. I can update this PR to support that but I would recommend not including patch versions in release branch naming unless you have a good reason to do so. Signed-off-by: Jack Baldry <jack.baldry@grafana.com> * Add helm chaart installation * s/mimir/oncall/ Signed-off-by: Jack Baldry <jack.baldry@grafana.com> * Remove https:// prefix from BASE_URL docker env var * Fix cloud heartbeat name * Polishing telegram * Update docker-compose.yml * Update plugin README (#48) * Update README and screenshot, remove plop for build info since version is now displayed prominently * Sign build Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Build actions (#38) * Drone, github action changes * Minor version updates * Update frontend dependencies * Re-enable unit test Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Revert stylelint version (#52) * Revert stylelint version * Build plugin as well as lint * Build in previous step Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Update screenshot (#53) Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * oncall images for docs (#55) * Fix chart * Finalise helm chart * Update README.md * Top menu fix * Fix db encoding * Add api key docs * Reverting utf8 fix * bug fixes * fix for link for OSS version * Fixing utf8 and docker compose * 8080 -> 8000 port for consistency * Improve the helm chart * makeReq * Fixing images * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Add last moment improvements * Fixing port * Replace symlink with file for CHANGELOG.MD (#68) Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Edit Chart.yaml * Edit version * Edit README.md * Fixing port * Update README.md * Fix linting * image: grafana/oncall * Merge dev to main (#71) * Merge dev to main (#54) * Log (failed) attempt to notify a user with viewer role * Remove https:// prefix from BASE_URL docker env var * Fix cloud heartbeat name * Polishing telegram * Update docker-compose.yml * Update plugin README (#48) * Update README and screenshot, remove plop for build info since version is now displayed prominently * Sign build Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Build actions (#38) * Drone, github action changes * Minor version updates * Update frontend dependencies * Re-enable unit test Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Revert stylelint version (#52) * Revert stylelint version * Build plugin as well as lint * Build in previous step Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Update screenshot (#53) Co-authored-by: Michael Derynck <michael.derynck@grafana.com> Co-authored-by: Matias Bordese <mbordese@gmail.com> Co-authored-by: Matvey Kukuy <Matvey-Kuk@users.noreply.github.com> Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com> Co-authored-by: Matvey Kukuy <matvey@amixr.io> Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Merge dev to main (#69) * Log (failed) attempt to notify a user with viewer role * Remove https:// prefix from BASE_URL docker env var * Fix cloud heartbeat name * Polishing telegram * Update docker-compose.yml * Update plugin README (#48) * Update README and screenshot, remove plop for build info since version is now displayed prominently * Sign build Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Build actions (#38) * Drone, github action changes * Minor version updates * Update frontend dependencies * Re-enable unit test Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Revert stylelint version (#52) * Revert stylelint version * Build plugin as well as lint * Build in previous step Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Update screenshot (#53) Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * oncall images for docs (#55) * Update README.md * Top menu fix * Fix db encoding * Add api key docs * Reverting utf8 fix * bug fixes * fix for link for OSS version * Fixing utf8 and docker compose * 8080 -> 8000 port for consistency * makeReq * Fixing images * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Replace symlink with file for CHANGELOG.MD (#68) Co-authored-by: Michael Derynck <michael.derynck@grafana.com> Co-authored-by: Matias Bordese <mbordese@gmail.com> Co-authored-by: Matvey Kukuy <Matvey-Kuk@users.noreply.github.com> Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com> Co-authored-by: Matvey Kukuy <matvey@amixr.io> Co-authored-by: Michael Derynck <michael.derynck@grafana.com> Co-authored-by: Alyssa Wada <101596687+alyssawada@users.noreply.github.com> Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com> Co-authored-by: Ildar Iskhakov <Ildar.iskhakov@grafana.com> Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com> Co-authored-by: Matias Bordese <mbordese@gmail.com> Co-authored-by: Matvey Kukuy <Matvey-Kuk@users.noreply.github.com> Co-authored-by: Matvey Kukuy <matvey@amixr.io> Co-authored-by: Alyssa Wada <101596687+alyssawada@users.noreply.github.com> Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com> Co-authored-by: Matias Bordese <mbordese@gmail.com> Co-authored-by: Jack Baldry <jack.baldry@grafana.com> Co-authored-by: Ildar Iskhakov <ildar.iskhakov@grafana.com> Co-authored-by: Matvey Kukuy <Matvey-Kuk@users.noreply.github.com> Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com> Co-authored-by: Matvey Kukuy <matvey@amixr.io> Co-authored-by: Alyssa Wada <101596687+alyssawada@users.noreply.github.com> Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com>
This commit is contained in:
parent
846b898bb9
commit
4572131951
33 changed files with 1280 additions and 46 deletions
42
.github/workflows/publish-technical-documentation-next.yml
vendored
Normal file
42
.github/workflows/publish-technical-documentation-next.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
name: "publish-technical-documentation-next"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
paths:
|
||||
- "docs/sources/**"
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
test:
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: "actions/checkout@v3"
|
||||
- name: "Build website"
|
||||
# -e HUGO_REFLINKSERRORLEVEL=ERROR prevents merging broken refs with the downside
|
||||
# that no refs to external content can be used as these refs will not resolve in the
|
||||
# docs-base image.
|
||||
run: |
|
||||
docker run -v ${PWD}/docs/sources:/hugo/content/docs/oncall/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'make hugo'
|
||||
|
||||
sync:
|
||||
runs-on: "ubuntu-latest"
|
||||
needs: "test"
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: "actions/checkout@v3"
|
||||
|
||||
- name: "Clone website-sync Action"
|
||||
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 website repository (next)"
|
||||
uses: "./.github/actions/website-sync"
|
||||
id: "publish-next"
|
||||
with:
|
||||
repository: "grafana/website"
|
||||
branch: "master"
|
||||
host: "github.com"
|
||||
github_pat: "${{ secrets.GH_BOT_ACCESS_TOKEN }}"
|
||||
source_folder: "docs/sources"
|
||||
target_folder: "content/docs/oncall/next"
|
||||
74
.github/workflows/publish-technical-documentation-release.yml
vendored
Normal file
74
.github/workflows/publish-technical-documentation-release.yml
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
name: "publish-technical-documentation-release"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "release-*"
|
||||
tags:
|
||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
paths:
|
||||
- "docs/sources/**"
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
test:
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: "actions/checkout@v3"
|
||||
- name:
|
||||
"Build website"
|
||||
# -e HUGO_REFLINKSERRORLEVEL=ERROR prevents merging broken refs with the downside
|
||||
# that no refs to external content can be used as these refs will not resolve in the
|
||||
# docs-base image.
|
||||
run: |
|
||||
docker run -v ${PWD}/docs/sources:/hugo/content/docs/oncall/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'make hugo'
|
||||
|
||||
sync:
|
||||
runs-on: "ubuntu-latest"
|
||||
needs: "test"
|
||||
steps:
|
||||
- name: "Checkout code and tags"
|
||||
uses: "actions/checkout@v3"
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: "Checkout Actions library"
|
||||
uses: "actions/checkout@v3"
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: "./actions"
|
||||
|
||||
- name: "Install Actions from library"
|
||||
run: "npm install --production --prefix ./actions"
|
||||
|
||||
- name: "Determine if there is a matching release tag"
|
||||
id: "has-matching-release-tag"
|
||||
uses: "./actions/has-matching-release-tag"
|
||||
with:
|
||||
ref_name: "${{ github.ref_name }}"
|
||||
release_tag_regexp: "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
|
||||
release_branch_regexp: "^release-(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
|
||||
|
||||
- name: "Determine technical documentation version"
|
||||
if: "steps.has-matching-release-tag.outputs.bool == 'true'"
|
||||
uses: "./actions/docs-target"
|
||||
id: "target"
|
||||
with:
|
||||
ref_name: "${{ github.ref_name }}"
|
||||
|
||||
- name: "Clone website-sync Action"
|
||||
if: "steps.has-matching-release-tag.outputs.bool == 'true'"
|
||||
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 website repository (release)"
|
||||
if: "steps.has-matching-release-tag.outputs.bool == 'true'"
|
||||
uses: "./.github/actions/website-sync"
|
||||
id: "publish-release"
|
||||
with:
|
||||
repository: "grafana/website"
|
||||
branch: "master"
|
||||
host: "github.com"
|
||||
github_pat: "${{ secrets.GH_BOT_ACCESS_TOKEN }}"
|
||||
source_folder: "docs/sources"
|
||||
# Append ".x" to target to produce a v<major>.<minor>.x directory.
|
||||
target_folder: "content/docs/oncall/${{ steps.target.outputs.target }}.x"
|
||||
40
.github/workflows/publish_docs.yml
vendored
40
.github/workflows/publish_docs.yml
vendored
|
|
@ -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 }}"
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
BIN
docs/img/architecture_diagram.png
Normal file
BIN
docs/img/architecture_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 681 KiB |
85
engine/settings/helm.py
Normal file
85
engine/settings/helm.py
Normal file
|
|
@ -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
|
||||
23
helm/oncall/.helmignore
Normal file
23
helm/oncall/.helmignore
Normal file
|
|
@ -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/
|
||||
43
helm/oncall/Chart.yaml
Normal file
43
helm/oncall/Chart.yaml
Normal file
|
|
@ -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
|
||||
120
helm/oncall/README.md
Normal file
120
helm/oncall/README.md
Normal file
|
|
@ -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://<base_url>/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
|
||||
```
|
||||
BIN
helm/oncall/charts/cert-manager-v1.8.0.tgz
Normal file
BIN
helm/oncall/charts/cert-manager-v1.8.0.tgz
Normal file
Binary file not shown.
BIN
helm/oncall/charts/grafana-6.29.6.tgz
Normal file
BIN
helm/oncall/charts/grafana-6.29.6.tgz
Normal file
Binary file not shown.
BIN
helm/oncall/charts/ingress-nginx-4.1.4.tgz
Normal file
BIN
helm/oncall/charts/ingress-nginx-4.1.4.tgz
Normal file
Binary file not shown.
BIN
helm/oncall/charts/mariadb-11.0.10.tgz
Normal file
BIN
helm/oncall/charts/mariadb-11.0.10.tgz
Normal file
Binary file not shown.
BIN
helm/oncall/charts/rabbitmq-10.1.1.tgz
Normal file
BIN
helm/oncall/charts/rabbitmq-10.1.1.tgz
Normal file
Binary file not shown.
BIN
helm/oncall/charts/redis-16.10.1.tgz
Normal file
BIN
helm/oncall/charts/redis-16.10.1.tgz
Normal file
Binary file not shown.
54
helm/oncall/templates/NOTES.txt
Normal file
54
helm/oncall/templates/NOTES.txt
Normal file
|
|
@ -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://<external-grafana>{{- end }}
|
||||
|
||||
|
||||
|
||||
🎉🎉🎉 Done! 🎉🎉🎉
|
||||
165
helm/oncall/templates/_env.tpl
Normal file
165
helm/oncall/templates/_env.tpl
Normal file
|
|
@ -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 }}
|
||||
96
helm/oncall/templates/_helpers.tpl
Normal file
96
helm/oncall/templates/_helpers.tpl
Normal file
|
|
@ -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 }}
|
||||
60
helm/oncall/templates/celery/_deployment.tpl
Normal file
60
helm/oncall/templates/celery/_deployment.tpl
Normal file
|
|
@ -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}}
|
||||
26
helm/oncall/templates/celery/_helpers.tpl
Normal file
26
helm/oncall/templates/celery/_helpers.tpl
Normal file
|
|
@ -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 }}
|
||||
1
helm/oncall/templates/celery/deployment-celery.yaml
Normal file
1
helm/oncall/templates/celery/deployment-celery.yaml
Normal file
|
|
@ -0,0 +1 @@
|
|||
{{ include "template.oncall.celery.deployment" . }}
|
||||
22
helm/oncall/templates/cert-issuer.yaml
Normal file
22
helm/oncall/templates/cert-issuer.yaml
Normal file
|
|
@ -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 }}
|
||||
26
helm/oncall/templates/engine/_helpers-engine.tpl
Normal file
26
helm/oncall/templates/engine/_helpers-engine.tpl
Normal file
|
|
@ -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 }}
|
||||
73
helm/oncall/templates/engine/deployment.yaml
Normal file
73
helm/oncall/templates/engine/deployment.yaml
Normal file
|
|
@ -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 }}
|
||||
54
helm/oncall/templates/engine/job-migrate.yaml
Normal file
54
helm/oncall/templates/engine/job-migrate.yaml
Normal file
|
|
@ -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 }}
|
||||
17
helm/oncall/templates/engine/service-external.yaml
Normal file
17
helm/oncall/templates/engine/service-external.yaml
Normal file
|
|
@ -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 }}
|
||||
15
helm/oncall/templates/engine/service-internal.yaml
Normal file
15
helm/oncall/templates/engine/service-internal.yaml
Normal file
|
|
@ -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 }}
|
||||
48
helm/oncall/templates/ingress-regular.yaml
Normal file
48
helm/oncall/templates/ingress-regular.yaml
Normal file
|
|
@ -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 }}
|
||||
43
helm/oncall/templates/secrets.yaml
Normal file
43
helm/oncall/templates/secrets.yaml
Normal file
|
|
@ -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 }}
|
||||
|
||||
12
helm/oncall/templates/serviceaccount.yaml
Normal file
12
helm/oncall/templates/serviceaccount.yaml
Normal file
|
|
@ -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 }}
|
||||
15
helm/oncall/templates/tests/test-connection.yaml
Normal file
15
helm/oncall/templates/tests/test-connection.yaml
Normal file
|
|
@ -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
|
||||
162
helm/oncall/values.yaml
Normal file
162
helm/oncall/values.yaml
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Reference in a new issue