Merge pull request #28 from grafana/hobby-docker-compose
Add docker compose stack
This commit is contained in:
commit
8b1c5e7f24
9 changed files with 260 additions and 56 deletions
88
README.md
88
README.md
|
|
@ -1,76 +1,54 @@
|
|||
# Grafana OnCall Incident Response
|
||||
Grafana OnCall, cloud version of Grafana OnCall: https://grafana.com/products/cloud/
|
||||
<img width="400px" src="docs/img/logo.png">
|
||||
|
||||
Developer-friendly, incident response management with brilliant Slack integration.
|
||||
- Connect monitoring systems
|
||||
- Collect and analyze data
|
||||
- On-call rotation
|
||||
- Automatic escalation
|
||||
- Never miss alerts with calls and SMS
|
||||
|
||||

|
||||
<img width="60%" src="screenshot.png">
|
||||
|
||||
- Collect and analyze alerts from multiple monitoring systems
|
||||
- On-call rotations based on schedules
|
||||
- Automatic escalations
|
||||
- Phone calls, SMS, Slack, Telegram notifications
|
||||
|
||||
<a href="https://github.com/grafana/oncall/discussions/categories/community-calls"><img width="200px" src="docs/img/community_call.png"></a>
|
||||
<a href="https://github.com/grafana/oncall/discussions"><img width="200px" src="docs/img/GH_discussions.png"></a>
|
||||
<a href="https://slack.grafana.com/"><img width="200px" src="docs/img/slack.png"></a>
|
||||
|
||||
## Getting Started
|
||||
OnCall consists of two parts:
|
||||
1. OnCall backend
|
||||
2. "Grafana OnCall" plugin you need to install in your Grafana
|
||||
|
||||
### How to run OnCall backend
|
||||
1. An all-in-one image of OnCall is available on docker hub to run it:
|
||||
### Environments:
|
||||
|
||||
Production: [PRODUCTION.md](PRODUCTION.md).
|
||||
Developer: [DEVELOPER.md](DEVELOPER.md).
|
||||
|
||||
### Hobby environment
|
||||
|
||||
Download docker-compose.yaml:
|
||||
```bash
|
||||
docker run -it --name oncall-backend -p 8000:8000 grafana/oncall-all-in-one
|
||||
curl https://github.com/... -o docker-compose.yaml
|
||||
```
|
||||
|
||||
2. When the image starts up you will see a message like this:
|
||||
Set environment:
|
||||
```bash
|
||||
👋 This script will issue an invite token to securely connect the frontend.
|
||||
Maintainers will be happy to help in the slack channel #grafana-oncall: https://slack.grafana.com/
|
||||
Your invite token: <TOKEN>, use it in the Grafana OnCall plugin.
|
||||
export DOMAIN=http://localhost
|
||||
export SECRET_KEY=my_random_secret_must_be_more_than_32_characters_long
|
||||
export RABBITMQ_PASSWORD=rabbitmq_secret_pw
|
||||
export MYSQL_PASSWORD=mysql_secret_pw
|
||||
export COMPOSE_PROFILES=with_grafana
|
||||
export GRAFANA_USER=admin
|
||||
export GRAFANA_PASSWORD=admin
|
||||
```
|
||||
|
||||
3. If you started your container detached with -d check the log:
|
||||
Launch services:
|
||||
```bash
|
||||
docker logs oncall-backend
|
||||
docker-compose -f docker-compose.yml up --build -d
|
||||
```
|
||||
|
||||
### How to install "Grafana OnCall" Plugin and connect with a backend
|
||||
1. Open Grafana in your browser and login as an Admin
|
||||
2. Navigate to Configuration → Plugins
|
||||
3. Type Grafana OnCall into the "Search Grafana plugins" field
|
||||
4. Select the Grafana OnCall plugin and press the "Install" button
|
||||
5. On the Grafana OnCall Plugin page Enable the plugin and go to the Configuration tab you should see a status field with the message
|
||||
Issue invite token and get further instructions:
|
||||
```bash
|
||||
docker-compose -f docker-compose.yml run engine python manage.py issue_invite_for_the_frontend --override
|
||||
```
|
||||
OnCall has not been setup, configure & initialize below.
|
||||
```
|
||||
6. Fill in configuration fields using the token you got from the backend earlier, then press "Install Configuration"
|
||||
```
|
||||
OnCall API URL: (The URL & port used to access OnCall)
|
||||
http://host.docker.internal:8000
|
||||
|
||||
OnCall Invitation Token (Single use token to connect Grafana instance):
|
||||
Invitation token from docker startup
|
||||
|
||||
Grafana URL (URL OnCall will use to talk to this Grafana instance):
|
||||
http://localhost:3000 (or http://host.docker.internal:3000 if your grafana is running in Docker locally)
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
- `#grafana-oncall` channel at https://slack.grafana.com/
|
||||
- Grafana Labs community forum for OnCall: https://community.grafana.com
|
||||
- File an [issue](https://github.com/grafana/oncall/issues) for bugs, issues and feature suggestions.
|
||||
|
||||
## Production Setup
|
||||
|
||||
Looking for the production instructions? We're going to release them soon. Please join our Slack channel to be the first to know about them.
|
||||
|
||||
## Further Reading
|
||||
- *Documentation* - [Grafana OnCall](https://grafana.com/docs/grafana-cloud/oncall/)
|
||||
- *Blog Post* - [Announcing Grafana OnCall, the easiest way to do on-call management](https://grafana.com/blog/2021/11/09/announcing-grafana-oncall/)
|
||||
- *Presentation* - [Deep dive into the Grafana, Prometheus, and Alertmanager stack for alerting and on-call management](https://grafana.com/go/observabilitycon/2021/alerting/?pg=blog)
|
||||
|
||||
## FAQ
|
||||
|
||||
- How do I generate a new invitation token to connect plugin with a backend?
|
||||
```bash
|
||||
docker exec oncall-backend python manage.py issue_invite_for_the_frontend --override
|
||||
```
|
||||
|
|
|
|||
0
deploy/docker-compose/README.md
Normal file
0
deploy/docker-compose/README.md
Normal file
169
deploy/docker-compose/docker-compose.yml
Normal file
169
deploy/docker-compose/docker-compose.yml
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
services:
|
||||
engine:
|
||||
# TODO: change to the public image once it's public
|
||||
# image: ...
|
||||
build: ../../engine
|
||||
ports:
|
||||
- 8080:8080
|
||||
command: >
|
||||
sh -c "uwsgi --ini uwsgi.ini"
|
||||
environment:
|
||||
BASE_URL: https://$DOMAIN
|
||||
SECRET_KEY: $SECRET_KEY
|
||||
RABBITMQ_USERNAME: "rabbitmq"
|
||||
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD
|
||||
RABBITMQ_HOST: "rabbitmq"
|
||||
RABBITMQ_PORT: "5672"
|
||||
RABBITMQ_DEFAULT_VHOST: "/"
|
||||
MYSQL_PASSWORD: $MYSQL_PASSWORD
|
||||
MYSQL_DB_NAME: oncall_hobby
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_HOST: ${MYSQL_HOST:-mysql}
|
||||
MYSQL_PORT: 3306
|
||||
REDIS_URI: redis://redis:6379/0
|
||||
DJANGO_SETTINGS_MODULE: settings.hobby
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
oncall_db_migration:
|
||||
condition: service_completed_successfully
|
||||
rabbitmq:
|
||||
condition: service_started
|
||||
redis:
|
||||
condition: service_started
|
||||
|
||||
celery:
|
||||
# TODO: change to the public image once it's public
|
||||
build: ../../engine
|
||||
command: sh -c "./celery_with_exporter.sh"
|
||||
environment:
|
||||
BASE_URL: https://$DOMAIN
|
||||
SECRET_KEY: $SECRET_KEY
|
||||
RABBITMQ_USERNAME: "rabbitmq"
|
||||
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD
|
||||
RABBITMQ_HOST: "rabbitmq"
|
||||
RABBITMQ_PORT: "5672"
|
||||
RABBITMQ_DEFAULT_VHOST: "/"
|
||||
MYSQL_PASSWORD: $MYSQL_PASSWORD
|
||||
MYSQL_DB_NAME: oncall_hobby
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_HOST: ${MYSQL_HOST:-mysql}
|
||||
MYSQL_PORT: 3306
|
||||
REDIS_URI: redis://redis:6379/0
|
||||
DJANGO_SETTINGS_MODULE: settings.hobby
|
||||
CELERY_WORKER_QUEUE: "celery"
|
||||
CELERY_WORKER_CONCURRENCY: "1"
|
||||
CELERY_WORKER_MAX_TASKS_PER_CHILD: "100"
|
||||
CELERY_WORKER_SHUTDOWN_INTERVAL: "65m"
|
||||
CELERY_WORKER_BEAT_ENABLED: "True"
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
oncall_db_migration:
|
||||
condition: service_completed_successfully
|
||||
rabbitmq:
|
||||
condition: service_started
|
||||
redis:
|
||||
condition: service_started
|
||||
|
||||
oncall_db_migration:
|
||||
build: ../../engine
|
||||
command: python manage.py migrate --noinput
|
||||
environment:
|
||||
BASE_URL: https://$DOMAIN
|
||||
SECRET_KEY: $SECRET_KEY
|
||||
RABBITMQ_USERNAME: "rabbitmq"
|
||||
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD
|
||||
RABBITMQ_HOST: "rabbitmq"
|
||||
RABBITMQ_PORT: "5672"
|
||||
RABBITMQ_DEFAULT_VHOST: "/"
|
||||
MYSQL_PASSWORD: $MYSQL_PASSWORD
|
||||
MYSQL_DB_NAME: oncall_hobby
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_HOST: ${MYSQL_HOST:-mysql}
|
||||
MYSQL_PORT: 3306
|
||||
REDIS_URI: redis://redis:6379/0
|
||||
DJANGO_SETTINGS_MODULE: settings.hobby
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
platform: linux/x86_64
|
||||
mem_limit: 500m
|
||||
cpus: 0.5
|
||||
command: --default-authentication-plugin=mysql_native_password
|
||||
restart: always
|
||||
ports:
|
||||
- 3306:3306
|
||||
volumes:
|
||||
- dbdata:/var/lib/mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: $MYSQL_PASSWORD
|
||||
MYSQL_DATABASE: oncall_hobby
|
||||
healthcheck:
|
||||
test: "mysql -uroot -p$MYSQL_PASSWORD oncall_hobby -e 'select 1'"
|
||||
timeout: 20s
|
||||
retries: 10
|
||||
|
||||
redis:
|
||||
image: redis
|
||||
mem_limit: 100m
|
||||
cpus: 0.1
|
||||
restart: always
|
||||
ports:
|
||||
- 6379:6379
|
||||
|
||||
rabbitmq:
|
||||
image: "rabbitmq:3.7.15-management"
|
||||
hostname: rabbitmq
|
||||
mem_limit: 1000m
|
||||
cpus: 0.5
|
||||
volumes:
|
||||
- rabbitmqdata:/var/lib/rabbitmq
|
||||
environment:
|
||||
RABBITMQ_DEFAULT_USER: "rabbitmq"
|
||||
RABBITMQ_DEFAULT_PASS: $RABBITMQ_PASSWORD
|
||||
RABBITMQ_DEFAULT_VHOST: "/"
|
||||
|
||||
mysql_to_create_grafana_db:
|
||||
image: mysql:5.7
|
||||
platform: linux/x86_64
|
||||
command: bash -c "mysql -h ${MYSQL_HOST:-mysql} -uroot -p${MYSQL_PASSWORD:?err} -e 'CREATE DATABASE IF NOT EXISTS grafana CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'"
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
profiles:
|
||||
- with_grafana
|
||||
|
||||
grafana:
|
||||
image: "grafana/grafana:8.3.2"
|
||||
mem_limit: 500m
|
||||
ports:
|
||||
- 3000:3000
|
||||
cpus: 0.5
|
||||
environment:
|
||||
GF_DATABASE_TYPE: mysql
|
||||
GF_DATABASE_HOST: ${MYSQL_HOST:-mysql}
|
||||
GF_DATABASE_USER: ${MYSQL_USER:-root}
|
||||
GF_DATABASE_PASSWORD: ${MYSQL_PASSWORD:?err}
|
||||
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
|
||||
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:?err}
|
||||
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app
|
||||
GF_INSTALL_PLUGINS: grafana-oncall-app
|
||||
volumes:
|
||||
- ../../grafana-plugin:/var/lib/grafana/plugins/grafana-plugin
|
||||
depends_on:
|
||||
mysql_to_create_grafana_db:
|
||||
condition: service_completed_successfully
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
profiles:
|
||||
- with_grafana
|
||||
|
||||
volumes:
|
||||
dbdata:
|
||||
rabbitmqdata:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
BIN
docs/img/GH_discussions.png
Normal file
BIN
docs/img/GH_discussions.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
BIN
docs/img/community_call.png
Normal file
BIN
docs/img/community_call.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/img/logo.png
Normal file
BIN
docs/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
docs/img/slack.png
Normal file
BIN
docs/img/slack.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
|
|
@ -9,4 +9,4 @@ You can use webhooks to send alert group notifications, and also to receive aler
|
|||
|
||||
Follow these links to learn more about using webhooks for OnCall alert notifications:
|
||||
|
||||
{{< section >}}
|
||||
{{< section >}}
|
||||
|
|
|
|||
57
engine/settings/hobby.py
Normal file
57
engine/settings/hobby.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# flake8: noqa: F405
|
||||
|
||||
from random import randrange
|
||||
|
||||
# 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}"
|
||||
|
||||
MIRAGE_SECRET_KEY = SECRET_KEY
|
||||
MIRAGE_CIPHER_IV = "1234567890abcdef" # use default
|
||||
|
||||
APPEND_SLASH = False
|
||||
SECURE_SSL_REDIRECT = False
|
||||
|
||||
# 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
|
||||
Loading…
Add table
Reference in a new issue