Dockerize Grafana Self Provisioned Configuration with Dashboards
Sometimes you need to deploy a grafana for your project and configure all the datasources and dashboards on it by hand, using the UI.
In this article I will show, how to deploy an entire grafana, pre configure with self-provisiong datasources and dashboards.
Here is the Repo
The Context
There are two components: A grafana with a single dashboard that takes data from a postgreSQL instance. So we move it to a dockerize enviroment.
Let’s start from the beginning:
- Create a Dockerfile for Postgres with initial data.
- Create a Dockerfile for Grafana, it includes some enviroment variable that allows configure the startup of Grafana and two folders, one is for the dashboards and other the operative configuration, datasources and where the dashboard will be deployed.
- Create a docker-compose with the declaration of the services for Grafana and Postgres.
Postgres Dockerfile
FROM postgres:12.15
COPY script/db_init.sql /docker-entrypoint-initdb.d/
ENV POSTGRES_USER=postgres
ENV POSTGRES_PASSWORD=postgres
ENV POSTGRES_DB=testdb
ENV PGDATA=/data
The Init db_init.sql
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
ALTER DATABASE testdb OWNER TO postgres;
\connect testdb
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
SET default_tablespace = '';
SET schema 'public';
SET default_table_access_method = heap;
CREATE TABLE cars (
car_id SERIAL PRIMARY KEY,
make VARCHAR(50) NOT NULL,
model VARCHAR(50) NOT NULL,
year INT NOT NULL,
color VARCHAR(20),
price NUMERIC(10, 2),
registration_date TIMESTAMP
);
-- Insert data into Car table
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Toyota', 'Corolla', 2020, 'Silver', 23000.00, '2023-08-07 10:30:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Honda', 'Civic', 2019, 'Red', 22000.00, '2023-08-07 14:20:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Ford', 'Mustang', 2022, 'Blue', 35000.00, '2023-08-08 09:45:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Chevrolet', 'Malibu', 2021, 'White', 27000.00, '2023-08-08 15:10:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Nissan', 'Altima', 2018, 'Black', 19000.00, '2023-08-09 11:00:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('BMW', 'X5', 2023, 'Gray', 60000.00, '2023-08-09 16:30:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Mercedes-Benz', 'C-Class', 2022, 'White', 45000.00, '2023-08-10 12:15:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Audi', 'A4', 2021, 'Blue', 42000.00, '2023-08-10 17:45:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Hyundai', 'Elantra', 2020, 'Silver', 18000.00, '2023-08-11 13:20:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Kia', 'Sorento', 2019, 'Red', 25000.00, '2023-08-11 18:10:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Volkswagen', 'Jetta', 2022, 'Black', 28000.00, '2023-08-12 14:50:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Subaru', 'Outback', 2023, 'Green', 32000.00, '2023-08-12 19:25:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Mazda', 'CX-5', 2021, 'Blue', 26000.00, '2023-08-13 15:40:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Jeep', 'Wrangler', 2020, 'Orange', 35000.00, '2023-08-13 20:15:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Ford', 'Focus', 2023, 'White', 27000.00, '2023-08-14 16:55:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Chevrolet', 'Equinox', 2022, 'Black', 19000.00, '2023-08-14 21:35:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Toyota', 'Rav4', 2019, 'Blue', 32000.00, '2023-08-15 17:30:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Honda', 'Accord', 2021, 'Red', 24000.00, '2023-08-15 22:00:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Nissan', 'Rogue', 2018, 'Silver', 22000.00, '2023-08-16 18:40:00');
INSERT INTO cars (make, model, year, color, price, registration_date)
VALUES ('Ford', 'Escape', 2020, 'Gray', 27000.00, '2023-08-16 23:20:00');
Grafana Dockerfile
FROM grafana/grafana:8.3.7
# ENV Variables for cofiguration
ENV GF_AUTH_ANONYMOUS_ENABLED=true #Enabled the Anonymous user no user/pass needed
ENV GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer #Activate the ROLE VIEWER as Default
ENV GF_AUTH_BASIC_ENABLED=false #Disable the AUTH Method
ENV GF_AUTH_DISABLE_LOGIN_FORM=true #Disable the login on show
ENV GF_AUTH_DISABLE_SIGNOUT_MENU=true #Diabled the menu
ENV GF_SECURITY_ALLOW_EMBEDDING=true #Allow IFRAME Calls
ENV GF_SERVER_SERVE_FROM_SUB_PATH=true
ENV GF_SERVE_FROM_SUB_PATH=true
EXPOSE 3000
ADD ./provisioning /etc/grafana/provisioning #Add the configuration
ADD ./dashboards /var/lib/grafana/dashboards #Add the Dashboard
CMD [ "grafana-reporter" ]
So, now we need to provides all the configuration for grafana
- Create the folders for provisioning with the sub-folder dashboards and datasources
- Create on the dashboards subfolder the dashboard.yml file.
- Create on the datasourcessubfolder the datasource.yml file.
Dashboard Provisioning (dashboard.yml)
apiVersion: 1
providers:
- name: "default"
orgId: 1
folder: ""
type: file
disableDeletion: false
updateIntervalSeconds: 10
options:
path: /var/lib/grafana/dashboards
Datasource Provisioning (datasource.yml)
apiVersion: 1
datasources:
- name: postgres-datasource
uid: pgds #THIS IS IMPORTANT ON THE DASHBOARD MUST BE THE SAME
orgId: 1
type: postgres
access: proxy
url: pg-db:5432
database: testdb
user: postgres
basicAuth: false
secureJsonData:
password: "postgres"
jsonData:
sslmode: "disable"
tlsAuth: false
tlsAuthWithCACert: false
connMaxLifetime: 14400
postgresVersion: 903
timescaledb: false
isDefault: true
Now we will provides the dashboards files
- Create the dashboards folder at the same level of the provisioning folder
- Copy your dashboards
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 1,
"links": [],
"liveNow": false,
"panels": [
{
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"axisSoftMin": 0,
"fillOpacity": 80,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineWidth": 1
},
"mappings": [],
"thresholds": {
"mode": "percentage",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "orange",
"value": 70
},
{
"color": "red",
"value": 85
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"barWidth": 0.97,
"groupWidth": 0.7,
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"orientation": "auto",
"showValue": "auto",
"stacking": "none",
"tooltip": {
"mode": "single"
},
"xTickLabelRotation": 0
},
"pluginVersion": "8.3.7",
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "pgds"
},
"format": "table",
"group": [
{
"params": ["color"],
"type": "column"
}
],
"hide": false,
"metricColumn": "color",
"rawQuery": true,
"rawSql": "SELECT\n \n color AS metric,\n count(*) AS \"quantity\"\nFROM cars\nWHERE\n $__timeFilter(registration_date)\nGROUP BY color\nORDER BY 1\n",
"refId": "A",
"select": [
[
{
"params": ["car_id"],
"type": "column"
},
{
"params": ["count"],
"type": "aggregate"
},
{
"params": ["quantity"],
"type": "alias"
}
]
],
"table": "cars",
"timeColumn": "registration_date",
"timeColumnType": "date",
"where": [
{
"name": "$__timeFilter",
"params": [],
"type": "macro"
}
]
}
],
"title": "Panel Title",
"type": "barchart"
}
],
"refresh": false,
"schemaVersion": 34,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-5y",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Color Cars",
"uid": "XZDyKc64k",
"version": 2,
"weekStart": ""
}
Finally we create the Docker-compose file to put all together to work.
version: "3"
services:
grafana:
build:
context: grafana
dockerfile: Dockerfile
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
depends_on:
- pg-db
pg-db:
build:
context: postgres
dockerfile: Dockerfile
ports:
- "1599:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
grafana-data:
postgres-data:
Conclusion:
Grafana is a great tool, I try show a easy way to deploy it quickly.
I hope that this will useful for you. Thanks for reading.
Here is the Repo