diff --git a/conf/grafana/provisioning/datasources/prometheus.yaml b/conf/grafana/provisioning/datasources/prometheus.yaml index 979db11..cc97378 100644 --- a/conf/grafana/provisioning/datasources/prometheus.yaml +++ b/conf/grafana/provisioning/datasources/prometheus.yaml @@ -1,11 +1,11 @@ # config file version apiVersion: 1 datasources: - name: Prometheus type: prometheus - url: http://nginx:5081/prometheus + url: http://prometheus:9090 access: proxy isDefault: true version: 1 editable: false diff --git a/images/grafana/Dockerfile b/images/grafana/Dockerfile new file mode 100644 index 0000000..29bcf26 --- /dev/null +++ b/images/grafana/Dockerfile @@ -0,0 +1,3 @@ +FROM grafana/grafana + +COPY conf /etc/grafana diff --git a/images/grafana/conf/dashboards/backend-stats.json b/images/grafana/conf/dashboards/backend-stats.json new file mode 100644 index 0000000..595c000 --- /dev/null +++ b/images/grafana/conf/dashboards/backend-stats.json @@ -0,0 +1,612 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "iteration": 1600443173782, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "interval": "", + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "mean resp time", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(swh_storage_request_duration_seconds_count{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "number of req/s", + "refId": "A" + }, + { + "expr": "rate(swh_storage_request_duration_seconds_sum{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]) / rate(swh_storage_request_duration_seconds_count{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval])", + "legendFormat": "mean resp time", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 5 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (object_type, operation) (rate(swh_storage_operations_bytes_total{instance=\"$instance\"} [$interval]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{object_type}} {{operation}}ed", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Data rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 10 + }, + "hiddenSeries": false, + "id": 7, + "interval": "", + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [], + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 0.5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "0.5", + "fill": 0, + "linewidth": 2 + }, + { + "alias": "0.75", + "fillBelowTo": "0.25", + "lines": false + }, + { + "alias": "0.25", + "lines": false + }, + { + "alias": "max", + "fill": 1, + "zindex": -3 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(swh_storage_request_duration_seconds_sum{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]) / rate(swh_storage_request_duration_seconds_count{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval])", + "format": "time_series", + "hide": true, + "instant": false, + "intervalFactor": 1, + "legendFormat": "mean", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.25, rate(swh_storage_request_duration_seconds_bucket{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]))", + "instant": false, + "intervalFactor": 1, + "legendFormat": "0.25", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.5, rate(swh_storage_request_duration_seconds_bucket{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]))", + "instant": false, + "intervalFactor": 1, + "legendFormat": "0.5", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.75, rate(swh_storage_request_duration_seconds_bucket{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]))", + "instant": false, + "intervalFactor": 1, + "legendFormat": "0.75", + "refId": "D" + }, + { + "expr": "histogram_quantile(1.0, rate(swh_storage_request_duration_seconds_bucket{instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]))", + "instant": false, + "intervalFactor": 1, + "legendFormat": "max", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Response time (25%-75%)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 2, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateYlGnBu", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 15 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 2, + "interval": "", + "legend": { + "show": false + }, + "links": [], + "reverseYBuckets": false, + "targets": [ + { + "expr": "rate(swh_storage_request_duration_seconds_bucket{instance=\"$instance\",endpoint=\"$endpoint\"}[$interval])", + "format": "heatmap", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Response time distribution", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": 0, + "format": "s", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "upper", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "refresh": "30s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "auto": true, + "auto_count": 50, + "auto_min": "2m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "hide": 0, + "label": null, + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "2m", + "value": "2m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "2m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "prometheus-statsd-exporter:9102", + "value": "prometheus-statsd-exporter:9102" + }, + "datasource": "Prometheus", + "definition": "label_values(swh_storage_request_duration_seconds_bucket, instance)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "instance", + "options": [], + "query": "label_values(swh_storage_request_duration_seconds_bucket, instance)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "revision_add", + "value": "revision_add" + }, + "datasource": "Prometheus", + "definition": "label_values(swh_storage_request_duration_seconds_bucket{instance=\"$instance\"}, endpoint)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "endpoint", + "options": [], + "query": "label_values(swh_storage_request_duration_seconds_bucket{instance=\"$instance\"}, endpoint)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Storage backend statistics", + "uid": "8ywqc76mk", + "version": 1 +} \ No newline at end of file diff --git a/images/grafana/conf/dashboards/content-replayer.json b/images/grafana/conf/dashboards/content-replayer.json new file mode 100644 index 0000000..1fa1c4a --- /dev/null +++ b/images/grafana/conf/dashboards/content-replayer.json @@ -0,0 +1,326 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(swh_content_replayer_bytes[5m])", + "legendFormat": "Volume", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Volume Processed", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 8 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(swh_content_replayer_operations_total[5m])", + "legendFormat": "Blobs", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Number of blobs processed", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 17 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(swh_content_replayer_duration_seconds_sum[5m])", + "legendFormat": "{{request}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Content Replayer", + "uid": "XUY3DVaZz", + "version": 1 +} \ No newline at end of file diff --git a/images/grafana/conf/dashboards/graph-replayer.json b/images/grafana/conf/dashboards/graph-replayer.json new file mode 100644 index 0000000..b8db659 --- /dev/null +++ b/images/grafana/conf/dashboards/graph-replayer.json @@ -0,0 +1,142 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 3, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(swh_graph_replayer_operations_total[5m])", + "legendFormat": "{{object_type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Graph Replayer Object processed", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Graph Replayer", + "uid": "nJ_uDV-Zk", + "version": 1 +} \ No newline at end of file diff --git a/images/grafana/conf/dashboards/task-processing.json b/images/grafana/conf/dashboards/task-processing.json new file mode 100644 index 0000000..42b9127 --- /dev/null +++ b/images/grafana/conf/dashboards/task-processing.json @@ -0,0 +1,387 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 2, + "iteration": 1600443190630, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": null, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "/uncaught/", + "color": "#bf1b00" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(swh_task_called_count{worker=~\"$worker\"}[$interval])) by (task)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{task}}", + "refId": "A" + }, + { + "expr": "sum(rate(swh_task_failure_count{worker=~\"$worker\"}[$interval])) by (task)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{task}} uncaught exceptions", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Task counts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "tasks per second", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#c15c17", + "colorScale": "sqrt", + "colorScheme": "interpolateViridis", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "Prometheus", + "description": "Each square's color represents the number of tasks that completed within that duration range.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 14, + "w": 24, + "x": 0, + "y": 9 + }, + "heatmap": {}, + "hideTimeOverride": false, + "hideZeroBuckets": false, + "highlightCards": true, + "id": 2, + "legend": { + "show": true + }, + "links": [], + "repeat": "task", + "repeatDirection": "v", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(increase(swh_task_duration_seconds_bucket{task=~\"$task\",worker=~\"$worker\"}[$interval])) by (le)", + "format": "heatmap", + "instant": false, + "interval": "$interval", + "intervalFactor": 1, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "title": "$task durations", + "tooltip": { + "show": true, + "showHistogram": true + }, + "tooltipDecimals": null, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": 0, + "format": "s", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "upper", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "refresh": false, + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "auto": true, + "auto_count": 100, + "auto_min": "2m", + "current": { + "selected": false, + "text": "auto", + "value": "$__auto_interval_interval" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": true, + "text": "auto", + "value": "$__auto_interval_interval" + }, + { + "selected": false, + "text": "2m", + "value": "2m" + }, + { + "selected": false, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "2m,5m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "definition": "label_values(swh_task_called_count, task)", + "hide": 0, + "includeAll": true, + "label": "Task name", + "multi": false, + "name": "task", + "options": [], + "query": "label_values(swh_task_called_count, task)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "Prometheus", + "definition": "label_values(swh_task_called_count{task=~\"$task\"}, worker)", + "hide": 0, + "includeAll": true, + "label": "Worker", + "multi": true, + "name": "worker", + "options": [], + "query": "label_values(swh_task_called_count{task=~\"$task\"}, worker)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Worker task processing", + "uid": "b_xh3f9ik", + "version": 1 +} \ No newline at end of file diff --git a/images/grafana/conf/provisioning/dashboards/all.yaml b/images/grafana/conf/provisioning/dashboards/all.yaml new file mode 100644 index 0000000..25088f6 --- /dev/null +++ b/images/grafana/conf/provisioning/dashboards/all.yaml @@ -0,0 +1,6 @@ +- name: 'default' # name of this dashboard configuration (not dashboard itself) + org_id: 1 # id of the org to hold the dashboard + folder: '' # name of the folder to put the dashboard (http://docs.grafana.org/v5.0/reference/dashboard_folders/) + type: 'file' # type of dashboard description (json files) + options: + folder: '/etc/grafana/dashboards' # where dashboards are diff --git a/conf/grafana/provisioning/datasources/prometheus.yaml b/images/grafana/conf/provisioning/datasources/prometheus.yaml similarity index 81% copy from conf/grafana/provisioning/datasources/prometheus.yaml copy to images/grafana/conf/provisioning/datasources/prometheus.yaml index 979db11..cc97378 100644 --- a/conf/grafana/provisioning/datasources/prometheus.yaml +++ b/images/grafana/conf/provisioning/datasources/prometheus.yaml @@ -1,11 +1,11 @@ # config file version apiVersion: 1 datasources: - name: Prometheus type: prometheus - url: http://nginx:5081/prometheus + url: http://prometheus:9090 access: proxy isDefault: true version: 1 editable: false diff --git a/kubernetes/01-prometheus.yml b/kubernetes/01-prometheus.yml new file mode 100644 index 0000000..9f7ec19 --- /dev/null +++ b/kubernetes/01-prometheus.yml @@ -0,0 +1,279 @@ +# ------- +# Prometheus statsd exporter configuration +# ------- +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-statsd-exporter +data: + config.yml: | + defaults: + timer_type: histogram + buckets: + - .005 + - .01 + - .025 + - .05 + - .1 + - .25 + - .5 + - .75 + - 1 + - 2 + - 5 + - 10 + - 15 + - 30 + - 45 + - 60 + - 120 + - 300 + - 600 + - 900 + - 1800 + - 2700 + - 3600 + - 7200 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus-statsd-exporter + labels: + app: prometheus-statsd-exporter +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus-statsd-exporter + template: + metadata: + labels: + app: prometheus-statsd-exporter + spec: + containers: + - name: prometheus-statsd-exporter + image: prom/statsd-exporter + imagePullPolicy: Always + args: + - "--statsd.mapping-config=/etc/prometheus/statsd-mapping.yml" + ports: + - containerPort: 9125 + volumeMounts: + - name: config + mountPath: /etc/prometheus/statsd-mapping.yml + subPath: config.yml + readOnly: true + volumes: + - name: config + configMap: + name: prometheus-statsd-exporter +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-statsd-exporter +spec: + type: ClusterIP + selector: + app: prometheus-statsd-exporter + ports: + - name: statsd + port: 9125 + targetPort: 9125 + - name: http + port: 9102 + targetPort: 9102 +--- +# ------- +# Prometheus configuration +# ------- + +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus +data: + config.yml: | + # my global config + global: + scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute. + evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. + # scrape_timeout is set to the global default (10s). + + scrape_configs: + - job_name: prometheus + static_configs: + - targets: + - prometheus:9090 + metrics_path: /prometheus/metrics + + - job_name: statsd-exporter + static_configs: + - targets: + - prometheus-statsd-exporter:9102 + + - job_name: jmx-exporter-cassandra + static_configs: + - targets: + - prometheus-jmx-exporter-cassandra:5556 + +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: prometheus-pv +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete + storageClassName: prometheus-pv + local: + path: /srv/softwareheritage-kube/prometheus + nodeAffinity: + required: + nodeSelectorTerms: + - matchExpressions: + # TODO adapt for your needs + - key: kubernetes.io/os + operator: In + values: + - linux +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: prometheus-pvc +spec: + accessModes: + - ReadWriteOnce + storageClassName: prometheus-pv + resources: + requests: + storage: 10Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + labels: + app: prometheus +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + spec: + containers: + - name: prometheus + image: prom/prometheus + imagePullPolicy: Always + args: + - "--config.file=/etc/prometheus/prometheus.yml" + ports: + - containerPort: 9090 + volumeMounts: + - name: config + mountPath: /etc/prometheus/prometheus.yml + subPath: config.yml + readOnly: true + - mountPath: "/prometheus/data" + name: prometheus-pvc + volumes: + - name: config + configMap: + name: prometheus + - name: prometheus-pvc + persistentVolumeClaim: + claimName: prometheus-pvc +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus +spec: + type: ClusterIP + selector: + app: prometheus + ports: + - port: 9090 + targetPort: 9090 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: prometheus +spec: + rules: + - host: prometheus.default + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: prometheus + port: + number: 9090 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + labels: + app: grafana +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + spec: + containers: + - name: grafana + image: registry.default/softwareheritage/grafana + imagePullPolicy: Always + # args: + # - "--config.file=/etc/prometheus/prometheus.yml" + ports: + - containerPort: 3000 +--- +apiVersion: v1 +kind: Service +metadata: + name: grafana +spec: + type: ClusterIP + selector: + app: grafana + ports: + - port: 3000 + targetPort: 3000 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: grafana +spec: + rules: + - host: grafana.default + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: grafana + port: + number: 3000 diff --git a/kubernetes/01-objstorage.yml b/kubernetes/02-objstorage.yml similarity index 97% rename from kubernetes/01-objstorage.yml rename to kubernetes/02-objstorage.yml index db1d239..2af559a 100644 --- a/kubernetes/01-objstorage.yml +++ b/kubernetes/02-objstorage.yml @@ -1,107 +1,106 @@ --- apiVersion: v1 kind: ConfigMap metadata: name: objstorage data: config.yml: | objstorage: cls: pathslicing args: root: "/srv/softwareheritage/objects" slicing: 0:1/1:5 client_max_size: 1073741824 --- apiVersion: v1 kind: PersistentVolume metadata: name: objstorage-pv spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: objstorage-pv local: path: /srv/softwareheritage-kube/objects nodeAffinity: required: nodeSelectorTerms: - matchExpressions: # TODO adapt for your needs - key: kubernetes.io/os operator: In values: - linux --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: objstorage-pvc spec: accessModes: - ReadWriteOnce storageClassName: objstorage-pv resources: requests: storage: 10Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: objstorage labels: app: objstorage spec: replicas: 1 selector: matchLabels: app: objstorage template: metadata: labels: app: objstorage spec: containers: - name: objstorage image: registry.default/softwareheritage/base:latest - command: - - /entrypoint.sh + args: - objstorage ports: - containerPort: 5003 env: - name: PORT value: "5003" - name: STATSD_HOST value: "prometheus-statsd-exporter" - name: STATSD_PORT value: "9125" volumeMounts: - mountPath: "/srv/softwareheritage/objects" name: objstorage-pvc - name: config mountPath: /etc/softwareheritage/config.yml subPath: config.yml readOnly: true volumes: - name: config configMap: name: objstorage - name: objstorage-pvc persistentVolumeClaim: claimName: objstorage-pvc --- apiVersion: v1 kind: Service metadata: name: objstorage spec: type: ClusterIP selector: app: objstorage ports: - port: 5003 targetPort: 5003 diff --git a/kubernetes/02_storage-db.yml b/kubernetes/03_storage-db.yml similarity index 98% rename from kubernetes/02_storage-db.yml rename to kubernetes/03_storage-db.yml index cb9b5fc..4fd1fc9 100644 --- a/kubernetes/02_storage-db.yml +++ b/kubernetes/03_storage-db.yml @@ -1,117 +1,118 @@ --- apiVersion: v1 kind: PersistentVolume metadata: name: storage-db-pv spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: storage-db local: path: /srv/softwareheritage-kube/storage-db nodeAffinity: required: nodeSelectorTerms: - matchExpressions: # TODO adapt for your needs - key: kubernetes.io/os operator: In values: - linux --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: storage-db-pvc spec: accessModes: - ReadWriteOnce storageClassName: storage-db resources: requests: storage: 10Gi --- ## TODO Change this to your real postgresql password apiVersion: v1 kind: Secret metadata: name: storage-db type: Opaque # data: # POSTGRES_PASSWORD: | # "echo 'strong password' | base64" stringData: POSTGRES_PASSWORD: swh --- apiVersion: v1 kind: ConfigMap metadata: name: storage-db data: # property-like keys; each key maps to a simple value POSTGRES_USER: swh POSTGRES_DB: swh --- apiVersion: apps/v1 kind: Deployment metadata: name: storage-db labels: app: storage-db spec: replicas: 1 selector: matchLabels: app: storage-db template: metadata: labels: app: storage-db spec: containers: - name: storage-db image: postgres:13.0 + imagePullPolicy: Always ports: - containerPort: 5432 env: - name: PGOPTIONS value: -c shared_buffers=4GB -c effective_cache_size=4GB -c random_page_cost=1.5 -c max_wal_size=4GB - name: POSTGRES_USER valueFrom: configMapKeyRef: name: storage-db key: POSTGRES_USER - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: storage-db key: POSTGRES_PASSWORD - name: POSTGRES_DB valueFrom: configMapKeyRef: name: storage-db key: POSTGRES_DB volumeMounts: - mountPath: "/var/lib/postgresql/data" name: storage-db-pvc volumes: - name: storage-db-pvc persistentVolumeClaim: claimName: storage-db-pvc --- apiVersion: v1 kind: Service metadata: name: storage-db spec: type: ClusterIP selector: app: storage-db ports: - port: 5432 targetPort: 5432 diff --git a/kubernetes/03-storage.yml b/kubernetes/04-storage.yml similarity index 97% rename from kubernetes/03-storage.yml rename to kubernetes/04-storage.yml index 24461cf..5bd3247 100644 --- a/kubernetes/03-storage.yml +++ b/kubernetes/04-storage.yml @@ -1,95 +1,94 @@ --- apiVersion: v1 kind: ConfigMap metadata: name: storage data: config.yml: | storage: cls: local args: db: postgresql:///?service=swh objstorage: cls: remote args: url: http://objstorage:5000/ --- apiVersion: apps/v1 kind: Deployment metadata: name: storage labels: app: storage spec: replicas: 1 selector: matchLabels: app: storage template: metadata: labels: app: storage spec: containers: - name: storage image: registry.default/softwareheritage/base:latest imagePullPolicy: Always - command: - - /entrypoint.sh + args: - storage ports: - containerPort: 5002 env: - name: PORT value: "5002" - name: STATSD_HOST value: "prometheus-statsd-exporter" - name: STATSD_PORT value: "9125" - name: POSTGRES_PASSWORD_FILE value: "/etc/softwareheritage/db-password" - name: PGHOST value: "storage-db" - name: PGUSER valueFrom: configMapKeyRef: name: storage-db key: POSTGRES_USER - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: storage-db key: POSTGRES_PASSWORD - name: POSTGRES_DB valueFrom: configMapKeyRef: name: storage-db key: POSTGRES_DB volumeMounts: - name: config mountPath: /etc/softwareheritage/config.yml subPath: config.yml readOnly: true - name: db-password mountPath: /run/secrets/postgres-password subPath: POSTGRES_PASSWORD readOnly: true volumes: - name: config configMap: name: storage - name: db-password secret: secretName: storage-db --- apiVersion: v1 kind: Service metadata: name: storage spec: type: ClusterIP selector: app: storage ports: - port: 5002 targetPort: 5002 diff --git a/kubernetes/05-web.yml b/kubernetes/05-web.yml new file mode 100644 index 0000000..47bb5be --- /dev/null +++ b/kubernetes/05-web.yml @@ -0,0 +1,176 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: web +data: + config.yml: | + storage: + cls: remote + args: + url: http://storage:5002/ + timeout: 1 + + objstorage: + cls: remote + args: + url: http://objstorage:5003/ + + # indexer_storage: + # cls: remote + # args: + # url: http://indexer-storage:5007/ + + # scheduler: + # cls: remote + # args: + # url: http://scheduler:5008/ + + # vault: + # cls: remote + # args: + # url: http://vault:5005/ + + # deposit: + # private_api_url: https://deposit:5006/1/private/ + # private_api_user: swhworker + # private_api_password: '' + + # TODO: remove the * + allowed_hosts: + - "*" + - appserver + + debug: yes + + serve_assets: yes + + throttling: + cache_uri: 127.0.0.1:11211 + scopes: + swh_api: + limiter_rate: + default: 120/h + exempted_networks: + - 0.0.0.0/0 + swh_api_origin_search: + limiter_rate: + default: 70/m + exempted_networks: + - 0.0.0.0/0 + swh_api_origin_visit_latest: + limiter_rate: + default: 700/m + exempted_networks: + - 0.0.0.0/0 + swh_vault_cooking: + limiter_rate: + default: 120/h + exempted_networks: + - 0.0.0.0/0 + swh_save_origin: + limiter_rate: + default: 120/h + exempted_networks: + - 0.0.0.0/0 + + search: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: memcached + labels: + app: memcached +spec: + replicas: 1 + selector: + matchLabels: + app: memcached + template: + metadata: + labels: + app: memcached + spec: + containers: + - name: memcached + image: memcached + imagePullPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + name: memcached +spec: + type: ClusterIP + selector: + app: memcached + ports: + - port: 11211 + targetPort: 11211 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: web + labels: + app: web +spec: + replicas: 1 + selector: + matchLabels: + app: web + template: + metadata: + labels: + app: web + spec: + containers: + - name: web + image: registry.default/softwareheritage/web:latest + imagePullPolicy: Always + args: + - serve + ports: + - containerPort: 5004 + env: + - name: PORT + value: "5004" + volumeMounts: + - name: config + mountPath: /etc/softwareheritage/config.yml + subPath: config.yml + readOnly: true + volumes: + - name: config + configMap: + name: web +--- +apiVersion: v1 +kind: Service +metadata: + name: web +spec: + type: ClusterIP + selector: + app: web + ports: + - port: 5004 + targetPort: 5004 +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: web +spec: + rules: + - host: web.default + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: web + port: + number: 5004 diff --git a/kubernetes/Readme.md b/kubernetes/Readme.md index f854166..823bf0a 100644 --- a/kubernetes/Readme.md +++ b/kubernetes/Readme.md @@ -1,130 +1,158 @@ ## Current status - basic configuration for one node cluster - use a private registry to deploy the docker image Services : - objstorage - storage-db - storage ## Prerquisite ### Directories ``` # sudo mkdir -p /srv/softwareheritage-kube/storage-db # sudo mkdir -p /srv/softwareheritage-kube/objects +# sudo mkdir -p /srv/softwareheritage-kube/prometheus +# sudo chown nobody /srv/softwareheritage-kube/prometheus # prometheus is running with user nobody ``` Must match the content of `02-storage-db.yaml` ### Registry - Add the following line on your `/etc/hosts` file. It's needed to be able to push the image to it from docker ``` 127.0.0.1 registry.default ``` - Start the registry in kubernetes ``` # cd kubernetes # kubectl apply -f registry/00-registry.yml ``` -## Build the base image +## Build the images + +### SWH images ``` # cd images # ./build_images.sh # docker tag softwareheritage/base:latest registry.default/softwareheritage/base:latest # docker push registry.default/softwareheritage/base:latest +# docker tag softwareheritage/web:latest registry.default/softwareheritage/web:latest +# docker push registry.default/softwareheritage/web:latest + +``` + +### grafana image + +This image goal is to be able to configure grafana during the startup + +``` +# cd images/grafana +# docker build --pull -t registry.default/softwareheritage/grafana . +# docker push registry.default/softwareheritage/grafana ``` ## start the objstorage - start the service ``` # cd kubernetes # kubectl apply -f 01-objstorage.yml configmap/objstorage created persistentvolume/objstorage-pv created persistentvolumeclaim/objstorage-pvc created deployment.apps/objstorage created service/objstorage created ``` - test it From a node of the cluster : ``` # kubectl get pods NAME READY STATUS RESTARTS AGE registry-deployment-7595868dc8-657ps 1/1 Running 0 46m objstorage-8587d58b68-76jbn 1/1 Running 0 12m # kubectl get services objstorage NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE objstorage ClusterIP 10.43.185.191 5003/TCP 17m # curl http://$(kubectl get services objstorage -o jsonpath='{.spec.clusterIP}'):5003 SWH Objstorage API server% ``` ## Start the storage - Start the db ``` # cd kubernetes # kubectl apply -f 02-storage-db.yml persistentvolume/storage-db-pv created persistentvolumeclaim/storage-db-pvc created secret/storage-db created configmap/storage-db created deployment.apps/storage-db created service/storage-db created # kubectl get pods NAME READY STATUS RESTARTS AGE registry-deployment-7595868dc8-657ps 1/1 Running 0 46m objstorage-8587d58b68-76jbn 1/1 Running 0 15m storage-db-64b7f8b684-48n7w 1/1 Running 0 4m52s # kubectl get services storage-db NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE storage-db ClusterIP 10.43.213.178 5432/TCP 8m19s ``` - Start the storage ``` # cd kubernetes # kubectl apply -f 03-storage.yml configmap/storage created deployment.apps/storage created service/storage created ``` - Test the service From a node of the cluster : ``` # kubectl get pods NAME READY STATUS RESTARTS AGE registry-deployment-7595868dc8-657ps 1/1 Running 0 49m storage-db-64b7f8b684-48n7w 1/1 Running 0 7m40s storage-6b759fb974-w9rzj 1/1 Running 0 66s # kubectl get services storage NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE storage ClusterIP 10.43.212.116 5002/TCP 2m24s # curl http://$(kubectl get services storage -o jsonpath='{.spec.clusterIP}'):5002 Software Heritage storage server

You have reached the Software Heritage storage server.
See its documentation and API for more information

``` + +# TODOs + +- [ ] registry persistence +- [ ] storage for sqlite database for web +- [ ] prometheus exporter +- [ ] prometheus +- [ ] grafana +- [ ] graph replayer +- [ ] content replayer +- [ ] clustered configuration