dotbalo 3 years ago
parent
commit
4a941ffc48
100 changed files with 5055 additions and 0 deletions
  1. BIN
      fklek/7.x/.logstash-cm.yaml.swp
  2. 22 0
      loki/loki-stack/.helmignore
  3. 13 0
      loki/loki-stack/Chart.yaml
  4. 60 0
      loki/loki-stack/README.md
  5. 2 0
      loki/loki-stack/charts/filebeat/.helmignore
  6. 12 0
      loki/loki-stack/charts/filebeat/Chart.yaml
  7. 1 0
      loki/loki-stack/charts/filebeat/Makefile
  8. 203 0
      loki/loki-stack/charts/filebeat/README.md
  9. 13 0
      loki/loki-stack/charts/filebeat/examples/default/Makefile
  10. 27 0
      loki/loki-stack/charts/filebeat/examples/default/README.md
  11. 47 0
      loki/loki-stack/charts/filebeat/examples/default/test/goss.yaml
  12. 13 0
      loki/loki-stack/charts/filebeat/examples/oss/Makefile
  13. 27 0
      loki/loki-stack/charts/filebeat/examples/oss/README.md
  14. 22 0
      loki/loki-stack/charts/filebeat/examples/oss/test/goss.yaml
  15. 5 0
      loki/loki-stack/charts/filebeat/examples/oss/values.yaml
  16. 13 0
      loki/loki-stack/charts/filebeat/examples/security/Makefile
  17. 28 0
      loki/loki-stack/charts/filebeat/examples/security/README.md
  18. 9 0
      loki/loki-stack/charts/filebeat/examples/security/test/goss.yaml
  19. 37 0
      loki/loki-stack/charts/filebeat/examples/security/values.yaml
  20. 2 0
      loki/loki-stack/charts/filebeat/templates/NOTES.txt
  21. 32 0
      loki/loki-stack/charts/filebeat/templates/_helpers.tpl
  22. 22 0
      loki/loki-stack/charts/filebeat/templates/clusterrole.yaml
  23. 19 0
      loki/loki-stack/charts/filebeat/templates/clusterrolebinding.yaml
  24. 17 0
      loki/loki-stack/charts/filebeat/templates/configmap.yaml
  25. 171 0
      loki/loki-stack/charts/filebeat/templates/daemonset.yaml
  26. 15 0
      loki/loki-stack/charts/filebeat/templates/serviceaccount.yaml
  27. 142 0
      loki/loki-stack/charts/filebeat/values.yaml
  28. 22 0
      loki/loki-stack/charts/fluent-bit/.helmignore
  29. 14 0
      loki/loki-stack/charts/fluent-bit/Chart.yaml
  30. 124 0
      loki/loki-stack/charts/fluent-bit/README.md
  31. 3 0
      loki/loki-stack/charts/fluent-bit/templates/NOTES.txt
  32. 66 0
      loki/loki-stack/charts/fluent-bit/templates/_helpers.tpl
  33. 17 0
      loki/loki-stack/charts/fluent-bit/templates/clusterrole.yaml
  34. 19 0
      loki/loki-stack/charts/fluent-bit/templates/clusterrolebinding.yaml
  35. 73 0
      loki/loki-stack/charts/fluent-bit/templates/configmap.yaml
  36. 80 0
      loki/loki-stack/charts/fluent-bit/templates/daemonset.yaml
  37. 34 0
      loki/loki-stack/charts/fluent-bit/templates/podsecuritypolicy.yaml
  38. 19 0
      loki/loki-stack/charts/fluent-bit/templates/role.yaml
  39. 19 0
      loki/loki-stack/charts/fluent-bit/templates/rolebinding.yaml
  40. 22 0
      loki/loki-stack/charts/fluent-bit/templates/service-headless.yaml
  41. 12 0
      loki/loki-stack/charts/fluent-bit/templates/serviceaccount.yaml
  42. 35 0
      loki/loki-stack/charts/fluent-bit/templates/servicemonitor.yaml
  43. 120 0
      loki/loki-stack/charts/fluent-bit/values.yaml
  44. 23 0
      loki/loki-stack/charts/grafana/.helmignore
  45. 17 0
      loki/loki-stack/charts/grafana/Chart.yaml
  46. 497 0
      loki/loki-stack/charts/grafana/README.md
  47. 1 0
      loki/loki-stack/charts/grafana/ci/default-values.yaml
  48. 53 0
      loki/loki-stack/charts/grafana/ci/with-dashboard-json-values.yaml
  49. 19 0
      loki/loki-stack/charts/grafana/ci/with-dashboard-values.yaml
  50. 19 0
      loki/loki-stack/charts/grafana/ci/with-image-renderer-values.yaml
  51. 1 0
      loki/loki-stack/charts/grafana/dashboards/custom-dashboard.json
  52. 54 0
      loki/loki-stack/charts/grafana/templates/NOTES.txt
  53. 102 0
      loki/loki-stack/charts/grafana/templates/_helpers.tpl
  54. 459 0
      loki/loki-stack/charts/grafana/templates/_pod.tpl
  55. 25 0
      loki/loki-stack/charts/grafana/templates/clusterrole.yaml
  56. 20 0
      loki/loki-stack/charts/grafana/templates/clusterrolebinding.yaml
  57. 26 0
      loki/loki-stack/charts/grafana/templates/configmap-dashboard-provider.yaml
  58. 69 0
      loki/loki-stack/charts/grafana/templates/configmap.yaml
  59. 35 0
      loki/loki-stack/charts/grafana/templates/dashboards-json-configmap.yaml
  60. 48 0
      loki/loki-stack/charts/grafana/templates/deployment.yaml
  61. 18 0
      loki/loki-stack/charts/grafana/templates/headless-service.yaml
  62. 112 0
      loki/loki-stack/charts/grafana/templates/image-renderer-deployment.yaml
  63. 76 0
      loki/loki-stack/charts/grafana/templates/image-renderer-network-policy.yaml
  64. 28 0
      loki/loki-stack/charts/grafana/templates/image-renderer-service.yaml
  65. 55 0
      loki/loki-stack/charts/grafana/templates/ingress.yaml
  66. 22 0
      loki/loki-stack/charts/grafana/templates/poddisruptionbudget.yaml
  67. 52 0
      loki/loki-stack/charts/grafana/templates/podsecuritypolicy.yaml
  68. 28 0
      loki/loki-stack/charts/grafana/templates/pvc.yaml
  69. 32 0
      loki/loki-stack/charts/grafana/templates/role.yaml
  70. 21 0
      loki/loki-stack/charts/grafana/templates/rolebinding.yaml
  71. 14 0
      loki/loki-stack/charts/grafana/templates/secret-env.yaml
  72. 22 0
      loki/loki-stack/charts/grafana/templates/secret.yaml
  73. 50 0
      loki/loki-stack/charts/grafana/templates/service.yaml
  74. 13 0
      loki/loki-stack/charts/grafana/templates/serviceaccount.yaml
  75. 36 0
      loki/loki-stack/charts/grafana/templates/servicemonitor.yaml
  76. 47 0
      loki/loki-stack/charts/grafana/templates/statefulset.yaml
  77. 17 0
      loki/loki-stack/charts/grafana/templates/tests/test-configmap.yaml
  78. 29 0
      loki/loki-stack/charts/grafana/templates/tests/test-podsecuritypolicy.yaml
  79. 14 0
      loki/loki-stack/charts/grafana/templates/tests/test-role.yaml
  80. 17 0
      loki/loki-stack/charts/grafana/templates/tests/test-rolebinding.yaml
  81. 9 0
      loki/loki-stack/charts/grafana/templates/tests/test-serviceaccount.yaml
  82. 48 0
      loki/loki-stack/charts/grafana/templates/tests/test.yaml
  83. 643 0
      loki/loki-stack/charts/grafana/values.yaml
  84. 2 0
      loki/loki-stack/charts/logstash/.helmignore
  85. 12 0
      loki/loki-stack/charts/logstash/Chart.yaml
  86. 1 0
      loki/loki-stack/charts/logstash/Makefile
  87. 208 0
      loki/loki-stack/charts/logstash/README.md
  88. 16 0
      loki/loki-stack/charts/logstash/examples/default/Makefile
  89. 17 0
      loki/loki-stack/charts/logstash/examples/default/README.md
  90. 43 0
      loki/loki-stack/charts/logstash/examples/default/test/goss.yaml
  91. 17 0
      loki/loki-stack/charts/logstash/examples/elasticsearch/Makefile
  92. 28 0
      loki/loki-stack/charts/logstash/examples/elasticsearch/README.md
  93. 56 0
      loki/loki-stack/charts/logstash/examples/elasticsearch/test/goss.yaml
  94. 12 0
      loki/loki-stack/charts/logstash/examples/elasticsearch/values.yaml
  95. 16 0
      loki/loki-stack/charts/logstash/examples/oss/Makefile
  96. 17 0
      loki/loki-stack/charts/logstash/examples/oss/README.md
  97. 42 0
      loki/loki-stack/charts/logstash/examples/oss/test/goss.yaml
  98. 2 0
      loki/loki-stack/charts/logstash/examples/oss/values.yaml
  99. 14 0
      loki/loki-stack/charts/logstash/examples/security/Makefile
  100. 28 0
      loki/loki-stack/charts/logstash/examples/security/README.md

BIN
fklek/7.x/.logstash-cm.yaml.swp


+ 22 - 0
loki/loki-stack/.helmignore

@@ -0,0 +1,22 @@
+# 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
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/

+ 13 - 0
loki/loki-stack/Chart.yaml

@@ -0,0 +1,13 @@
+apiVersion: v1
+appVersion: v2.1.0
+description: 'Loki: like Prometheus, but for logs.'
+home: https://grafana.com/loki
+icon: https://raw.githubusercontent.com/grafana/loki/master/docs/sources/logo.png
+kubeVersion: ^1.10.0-0
+maintainers:
+- email: lokiproject@googlegroups.com
+  name: Loki Maintainers
+name: loki-stack
+sources:
+- https://github.com/grafana/loki
+version: 2.4.1

+ 60 - 0
loki/loki-stack/README.md

@@ -0,0 +1,60 @@
+# Loki-Stack Helm Chart
+
+## Prerequisites
+
+Make sure you have Helm [installed](https://helm.sh/docs/using_helm/#installing-helm) installed.
+
+## Get Repo Info
+
+```console
+helm repo add grafana https://grafana.github.io/helm-charts
+helm repo update
+```
+
+_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._
+
+## Deploy Loki and Promtail to your cluster
+
+### Deploy with default config
+
+```bash
+helm upgrade --install loki grafana/loki-stack
+```
+
+### Deploy in a custom namespace
+
+```bash
+helm upgrade --install loki --namespace=loki-stack grafana/loki-stack
+```
+
+### Deploy with custom config
+
+```bash
+helm upgrade --install loki grafana/loki-stack --set "key1=val1,key2=val2,..."
+```
+
+## Deploy Loki and Fluent Bit to your cluster
+
+```bash
+helm upgrade --install loki grafana/loki-stack \
+    --set fluent-bit.enabled=true,promtail.enabled=false
+```
+
+## Deploy Grafana to your cluster
+
+The chart loki-stack contains a pre-configured Grafana, simply use `--set grafana.enabled=true`
+
+To get the admin password for the Grafana pod, run the following command:
+
+```bash
+kubectl get secret --namespace <YOUR-NAMESPACE> loki-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
+```
+
+To access the Grafana UI, run the following command:
+
+```bash
+kubectl port-forward --namespace <YOUR-NAMESPACE> service/loki-grafana 3000:80
+```
+
+Navigate to <http://localhost:3000> and login with `admin` and the password output above.
+Then follow the [instructions for adding the loki datasource](/docs/getting-started/grafana.md), using the URL `http://loki:3100/`.

+ 2 - 0
loki/loki-stack/charts/filebeat/.helmignore

@@ -0,0 +1,2 @@
+tests/
+.pytest_cache/

+ 12 - 0
loki/loki-stack/charts/filebeat/Chart.yaml

@@ -0,0 +1,12 @@
+apiVersion: v1
+appVersion: 7.8.1
+description: Official Elastic helm chart for Filebeat
+home: https://github.com/elastic/helm-charts
+icon: https://helm.elastic.co/icons/beats.png
+maintainers:
+- email: helm-charts@elastic.co
+  name: Elastic
+name: filebeat
+sources:
+- https://github.com/elastic/beats
+version: 7.8.1

+ 1 - 0
loki/loki-stack/charts/filebeat/Makefile

@@ -0,0 +1 @@
+include ../helpers/common.mk

+ 203 - 0
loki/loki-stack/charts/filebeat/README.md

@@ -0,0 +1,203 @@
+# Filebeat Helm Chart
+
+This Helm chart is a lightweight way to configure and run our official
+[Filebeat Docker image][].
+
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
+
+- [Requirements](#requirements)
+- [Installing](#installing)
+- [Upgrading](#upgrading)
+- [Usage notes](#usage-notes)
+- [Configuration](#configuration)
+- [FAQ](#faq)
+  - [How to use Filebeat with Elasticsearch with security (authentication and TLS) enabled?](#how-to-use-filebeat-with-elasticsearch-with-security-authentication-and-tls-enabled)
+  - [How to install OSS version of Filebeat?](#how-to-install-oss-version-of-filebeat)
+  - [Why is Filebeat host.name field set to Kubernetes pod name?](#why-is-filebeat-hostname-field-set-to-kubernetes-pod-name)
+  - [How to change readinessProbe for outputs which don't support testing](#how-to-change-readinessprobe-for-outputs-which-dont-support-testing)
+- [Contributing](#contributing)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+<!-- Use this to update TOC: -->
+<!-- docker run --rm -it -v $(pwd):/usr/src jorgeandrada/doctoc --github -->
+
+
+## Requirements
+
+* [Helm][] >=2.8.0 and <3.0.0
+* Kubernetes >=1.9
+
+See [supported configurations][] for more details.
+
+
+## Installing
+
+This chart is tested with 7.8.1 version.
+
+* Add the Elastic Helm charts repo:
+`helm repo add elastic https://helm.elastic.co`
+
+* Install 7.8.1 release:
+`helm install --name apm-server --version 7.8.1 elastic/filebeat`
+
+
+## Upgrading
+
+Please always check [CHANGELOG.md][] and [BREAKING_CHANGES.md][] before
+upgrading to a new chart version.
+
+
+## Usage notes
+
+* The default Filebeat configuration file for this chart is configured to use an
+Filebeat endpoint. Without any additional changes, Filebeat will send
+documents to the service URL that the Filebeat Helm chart sets up by
+default. You may either set the `FILEBEAT_HOSTS` environment variable in
+`extraEnvs` to override this endpoint or modify the default `filebeatConfig` to
+change this behavior.
+* The default Filebeat configuration file is also configured to capture
+container logs and enrich them with Kubernetes metadata by default. This will
+capture all container logs in the cluster.
+* This chart disables the [HostNetwork][] setting by default for compatibility
+reasons with the majority of kubernetes providers and scenarios. Some kubernetes
+providers may not allow enabling `hostNetwork` and deploying multiple Filebeat
+pods on the same node isn't possible with `hostNetwork` However Filebeat does
+recommend activating it. If your kubernetes provider is compatible with
+`hostNetwork` and you don't need to run multiple Filebeat DaemonSets, you can
+activate it by setting `hostNetworking: true` in [values.yaml][].
+* This repo includes a number of [examples][] configurations which can be used
+as a reference. They are also used in the automated testing of this chart.
+
+
+## Configuration
+
+| Parameter                | Description                                                                                                                                                                     | Default                            |
+|--------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|
+| `affinity`               | Configurable [affinity][]                                                                                                                                                       | `{}`                               |
+| `envFrom`                | Templatable string of envFrom to be passed to the [environment from variables][] which will be appended to the `envFrom:` definition for the container                          | `[]`                               |
+| `extraContainers`        | List of additional init containers to be added at the DaemonSet                                                                                                                 | `""`                               |
+| `extraEnvs`              | Extra [environment variables][] which will be appended to the `env:` definition for the container                                                                               | `[]`                               |
+| `extraInitContainers`    | List of additional init containers to be added at the DaemonSet. It also accepts a templatable string of additional containers to be passed to the `tpl` function               | `[]`                               |
+| `extraVolumeMounts`      | List of additional volumeMounts to be mounted on the DaemonSet                                                                                                                  | `[]`                               |
+| `extraVolumes`           | List of additional volumes to be mounted on the DaemonSet                                                                                                                       | `[]`                               |
+| `filebeatConfig`         | Allows you to add any config files in `/usr/share/filebeat` such as `filebeat.yml`                                                                                              | see [values.yaml][]                |
+| `fullnameOverride`       | Overrides the full name of the resources. If not set the name will default to " `.Release.Name` - `.Values.nameOverride or .Chart.Name` "                                       | `""`                               |
+| `hostNetworking`         | Use host networking in the DaemonSet so that hostname is reported correctly                                                                                                     | `false`                            |
+| `hostPathRoot`           | Fully-qualified [hostPath][] that will be used to persist Filebeat registry data                                                                                                | `/var/lib`                         |
+| `imagePullPolicy`        | The Kubernetes [imagePullPolicy][] value                                                                                                                                        | `IfNotPresent`                     |
+| `imagePullSecrets`       | Configuration for [imagePullSecrets][] so that you can use a private registry for your image                                                                                    | `[]`                               |
+| `imageTag`               | The Filebeat Docker image tag                                                                                                                                                   | `7.8.1`                            |
+| `image`                  | The Filebeat Docker image                                                                                                                                                       | `docker.elastic.co/beats/filebeat` |
+| `labels`                 | Configurable [labels][] applied to all Filebeat pods                                                                                                                            | `{}`                               |
+| `livenessProbe`          | Parameters to pass to liveness [probe][] checks for values such as timeouts and thresholds                                                                                      | see [values.yaml][]                |
+| `managedServiceAccount`  | Whether the `serviceAccount` should be managed by this Helm chart. Set this to `false` in order to manage your own service account and related roles                            | `true`                             |
+| `nameOverride`           | Overrides the chart name for resources. If not set the name will default to `.Chart.Name`                                                                                       | `""`                               |
+| `nodeSelector`           | Configurable [nodeSelector][]                                                                                                                                                   | `{}`                               |
+| `podAnnotations`         | Configurable [annotations][] applied to all Filebeat pods                                                                                                                       | `{}`                               |
+| `podSecurityContext`     | Configurable [podSecurityContext][] for Filebeat pod execution environment                                                                                                      | see [values.yaml][]                |
+| `priorityClassName`      | The name of the [PriorityClass][]. No default is supplied as the PriorityClass must be created first                                                                            | `""`                               |
+| `readinessProbe`         | Parameters to pass to readiness [probe][] checks for values such as timeouts and thresholds                                                                                     | see [values.yaml][]                |
+| `resources`              | Allows you to set the [resources][] for the `DaemonSet`                                                                                                                         | see [values.yaml][]                |
+| `secretMounts`           | Allows you easily mount a secret as a file inside the `DaemonSet`. Useful for mounting certificates and other secrets. See [values.yaml][] for an example                       | `[]`                               |
+| `serviceAccount`         | Custom [serviceAccount][] that Filebeat will use during execution. By default will use the service account created by this chart                                                | `""`                               |
+| `serviceAccountAnnotations` | Annotations to be added to the ServiceAccount that is created by this chart.                                                                                                 | `{}`
+| `terminationGracePeriod` | Termination period (in seconds) to wait before killing Filebeat pod process on pod shutdown                                                                                     | `30`                               |
+| `tolerations`            | Configurable [tolerations][]                                                                                                                                                    | `[]`                               |
+| `updateStrategy`         | The [updateStrategy][] for the `DaemonSet`. By default Kubernetes will kill and recreate pods on updates. Setting this to `OnDelete` will require that pods be deleted manually | `RollingUpdate`                    |
+
+
+## FAQ
+
+### How to use Filebeat with Elasticsearch with security (authentication and TLS) enabled?
+
+This Helm chart can use existing [Kubernetes secrets][] to setup
+credentials or certificates for examples. These secrets should be created
+outside of this chart and accessed using [environment variables][] and volumes.
+
+An example can be found in [examples/security][].
+
+### How to install OSS version of Filebeat?
+
+Deploying OSS version of Elasticsearch can be done by setting `image` value to
+[Filebeat OSS Docker image][]
+
+An example of Filebeat deployment using OSS version can be found in
+[examples/oss][].
+
+### Why is Filebeat host.name field set to Kubernetes pod name?
+
+The default Filebeat configuration is using Filebeat pod name for
+`agent.hostname` and `host.name` fields. The `hostname` of the Kubernetes nodes
+can be find in `kubernetes.node.name` field. If you would like to have
+`agent.hostname` and `host.name` fields set to the hostname of the nodes, you'll
+need to set `daemonset.hostNetworking` value to true.
+
+Note that enabling [hostNetwork][] make Filebeat pod use the host network
+namespace which gives it access to the host loopback device, services listening
+on localhost, could be used to snoop on network activity of other pods on the
+same node.
+
+### How to change readinessProbe for outputs which don't support testing
+
+Some [Filebeat outputs][] like [Kafka output][] don't support testing using
+`filebeat test output` command which is used by Filebeat chart readiness probe.
+
+This makes Filebeat pods crash before being ready with the following message:
+`Readiness probe failed: kafka output doesn't support testing`.
+
+The workaround when using this kind of output is to override the readiness probe
+command to check Filebeat API instead (same as existing liveness probe).
+
+```
+readinessProbe:
+  exec:
+    command:
+      - sh
+      - -c
+      - |
+        #!/usr/bin/env bash -e
+        curl --fail 127.0.0.1:5066
+```
+
+
+## Contributing
+
+Please check [CONTRIBUTING.md][] before any contribution or for any questions
+about our development and testing process.
+
+
+[BREAKING_CHANGES.md]: https://github.com/elastic/helm-charts/blob/master/BREAKING_CHANGES.md
+[CHANGELOG.md]: https://github.com/elastic/helm-charts/blob/master/CHANGELOG.md
+[CONTRIBUTING.md]: https://github.com/elastic/helm-charts/blob/master/CONTRIBUTING.md
+[affinity]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+[annotations]: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+[default Filebeat Helm chart]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/README.md#default
+[environment variables]: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/#using-environment-variables-inside-of-your-config
+[environment from variables]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables
+[examples]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/examples
+[examples/oss]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/examples/oss
+[examples/security]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/examples/security
+[filebeat docker image]: https://www.elastic.co/guide/en/beats/filebeat/7.8/running-on-docker.html
+[filebeat oss docker image]: https://www.docker.elastic.co/r/beats/filebeat-oss
+[filebeat outputs]: https://www.elastic.co/guide/en/beats/filebeat/7.8/configuring-output.html
+[helm]: https://helm.sh
+[hostNetwork]: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces
+[hostPath]: https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
+[imagePullPolicy]: https://kubernetes.io/docs/concepts/containers/images/#updating-images
+[imagePullSecrets]: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#create-a-pod-that-uses-your-secret
+[kafka output]: https://www.elastic.co/guide/en/beats/filebeat/master/kafka-output.html
+[kubernetes secrets]: https://kubernetes.io/docs/concepts/configuration/secret/
+[labels]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
+[nodeSelector]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+[podSecurityContext]: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+[priorityClass]: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+[probe]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
+[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
+[supported configurations]: https://github.com/elastic/helm-charts/tree/7.8/README.md#supported-configurations
+[serviceAccount]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
+[tolerations]: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+[updateStrategy]: https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/#daemonset-update-strategy
+[values.yaml]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/values.yaml

+ 13 - 0
loki/loki-stack/charts/filebeat/examples/default/Makefile

@@ -0,0 +1,13 @@
+default: test
+
+include ../../../helpers/examples.mk
+
+RELEASE := helm-filebeat-default
+
+install:
+	helm upgrade --wait --timeout=600 --install $(RELEASE) ../../
+
+test: install goss
+
+purge:
+	helm del --purge $(RELEASE)

+ 27 - 0
loki/loki-stack/charts/filebeat/examples/default/README.md

@@ -0,0 +1,27 @@
+# Default
+
+This example deploy Filebeat 7.8.1 using [default values][].
+
+
+## Usage
+
+* Deploy [Elasticsearch Helm chart][].
+
+* Deploy Filebeat chart with the default values: `make install`
+
+* You can now setup a port forward to query Filebeat indices:
+
+  ```
+  kubectl port-forward svc/elasticsearch-master 9200
+  curl localhost:9200/_cat/indices
+  ```
+
+
+## Testing
+
+You can also run [goss integration tests][] using `make test`
+
+
+[elasticsearch helm chart]: https://github.com/elastic/helm-charts/tree/7.8/elasticsearch/examples/default/
+[goss integration tests]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/examples/default/test/goss.yaml
+[default values]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/values.yaml

+ 47 - 0
loki/loki-stack/charts/filebeat/examples/default/test/goss.yaml

@@ -0,0 +1,47 @@
+port:
+  tcp:5066:
+    listening: true
+    ip:
+    - '127.0.0.1'
+
+mount:
+  /usr/share/filebeat/data:
+    exists: true
+  /run/docker.sock:
+    exists: true
+  /var/lib/docker/containers:
+    exists: true
+    opts:
+      - ro
+  /usr/share/filebeat/filebeat.yml:
+    exists: true
+    opts:
+      - ro
+
+user:
+  filebeat:
+    exists: true
+    uid: 1000
+    gid: 1000
+
+http:
+  http://elasticsearch-master:9200/_cat/indices:
+    status: 200
+    timeout: 2000
+    body:
+      - 'filebeat-7.8.1'
+
+file:
+  /usr/share/filebeat/filebeat.yml:
+    exists: true
+    contains:
+      - 'add_kubernetes_metadata'
+      - 'output.elasticsearch'
+      - 'elasticsearch-master:9200'
+
+command:
+  cd /usr/share/filebeat && filebeat test output:
+    exit-status: 0
+    stdout:
+      - 'elasticsearch: http://elasticsearch-master:9200'
+      - 'version: 7.8.1'

+ 13 - 0
loki/loki-stack/charts/filebeat/examples/oss/Makefile

@@ -0,0 +1,13 @@
+default: test
+
+include ../../../helpers/examples.mk
+
+RELEASE := helm-filebeat-oss
+
+install:
+	helm upgrade --wait --timeout=600 --install $(RELEASE) --values values.yaml ../../
+
+test: install goss
+
+purge:
+	helm del --purge $(RELEASE)

+ 27 - 0
loki/loki-stack/charts/filebeat/examples/oss/README.md

@@ -0,0 +1,27 @@
+# OSS
+
+This example deploy Filebeat 7.8.1 using [Filebeat OSS][] version.
+
+
+## Usage
+
+* Deploy [Elasticsearch Helm chart][].
+
+* Deploy Filebeat chart with the default values: `make install`
+
+* You can now setup a port forward to query Filebeat indices:
+
+  ```
+  kubectl port-forward svc/oss-master 9200
+  curl localhost:9200/_cat/indices
+  ```
+
+
+## Testing
+
+You can also run [goss integration tests][] using `make test`
+
+
+[filebeat oss]: https://www.elastic.co/downloads/beats/filebeat-oss
+[elasticsearch helm chart]: https://github.com/elastic/helm-charts/tree/7.8/elasticsearch/examples/oss/
+[goss integration tests]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/examples/oss/test/goss.yaml

+ 22 - 0
loki/loki-stack/charts/filebeat/examples/oss/test/goss.yaml

@@ -0,0 +1,22 @@
+port:
+  tcp:5066:
+    listening: true
+    ip:
+    - '127.0.0.1'
+
+mount:
+  /usr/share/filebeat/data:
+    exists: true
+
+user:
+  filebeat:
+    exists: true
+    uid: 1000
+    gid: 1000
+
+http:
+  http://oss-master:9200/_cat/indices:
+    status: 200
+    timeout: 2000
+    body:
+      - 'filebeat-7.8.1'

+ 5 - 0
loki/loki-stack/charts/filebeat/examples/oss/values.yaml

@@ -0,0 +1,5 @@
+image: docker.elastic.co/beats/filebeat-oss
+
+extraEnvs:
+  - name: ELASTICSEARCH_HOSTS
+    value: oss-master:9200

+ 13 - 0
loki/loki-stack/charts/filebeat/examples/security/Makefile

@@ -0,0 +1,13 @@
+default: test
+
+include ../../../helpers/examples.mk
+
+RELEASE := helm-filebeat-security
+
+install:
+	helm upgrade --wait --timeout=600 --install $(RELEASE) --values values.yaml ../../
+
+test: install goss
+
+purge:
+	helm del --purge $(RELEASE)

+ 28 - 0
loki/loki-stack/charts/filebeat/examples/security/README.md

@@ -0,0 +1,28 @@
+# Security
+
+This example deploy Filebeat 7.8.1 using authentication and TLS to connect to
+Elasticsearch (see [values][]).
+
+
+## Usage
+
+* Deploy [Elasticsearch Helm chart][].
+
+* Deploy Filebeat chart with security: `make install`
+
+* You can now setup a port forward to query Filebeat indices:
+
+  ```
+  kubectl port-forward svc/security-master 9200
+  curl -u elastic:changeme https://localhost:9200/_cat/indices
+  ```
+
+
+## Testing
+
+You can also run [goss integration tests][] using `make test`
+
+
+[elasticsearch helm chart]: https://github.com/elastic/helm-charts/tree/7.8/elasticsearch/examples/security/
+[goss integration tests]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/examples/security/test/goss.yaml
+[values]: https://github.com/elastic/helm-charts/tree/7.8/filebeat/examples/security/values.yaml

+ 9 - 0
loki/loki-stack/charts/filebeat/examples/security/test/goss.yaml

@@ -0,0 +1,9 @@
+http:
+  https://security-master:9200/_cat/indices:
+    status: 200
+    timeout: 2000
+    body:
+      - 'filebeat-7.8.1'
+    allow-insecure: true
+    username: '{{ .Env.ELASTICSEARCH_USERNAME }}'
+    password: '{{ .Env.ELASTICSEARCH_PASSWORD }}'

+ 37 - 0
loki/loki-stack/charts/filebeat/examples/security/values.yaml

@@ -0,0 +1,37 @@
+filebeatConfig:
+  filebeat.yml: |
+    filebeat.inputs:
+    - type: container
+      paths:
+        - /var/log/containers/*.log
+      processors:
+      - add_kubernetes_metadata:
+          host: ${NODE_NAME}
+          matchers:
+          - logs_path:
+              logs_path: "/var/log/containers/"
+
+    output.elasticsearch:
+      username: '${ELASTICSEARCH_USERNAME}'
+      password: '${ELASTICSEARCH_PASSWORD}'
+      protocol: https
+      hosts: ["security-master:9200"]
+      ssl.certificate_authorities:
+        - /usr/share/filebeat/config/certs/elastic-certificate.pem
+
+secretMounts:
+  - name: elastic-certificate-pem
+    secretName: elastic-certificate-pem
+    path: /usr/share/filebeat/config/certs
+
+extraEnvs:
+  - name: 'ELASTICSEARCH_USERNAME'
+    valueFrom:
+      secretKeyRef:
+        name: elastic-credentials
+        key: username
+  - name: 'ELASTICSEARCH_PASSWORD'
+    valueFrom:
+      secretKeyRef:
+        name: elastic-credentials
+        key: password

+ 2 - 0
loki/loki-stack/charts/filebeat/templates/NOTES.txt

@@ -0,0 +1,2 @@
+1. Watch all containers come up.
+  $ kubectl get pods --namespace={{ .Release.Namespace }} -l app={{ template "filebeat.fullname" . }} -w

+ 32 - 0
loki/loki-stack/charts/filebeat/templates/_helpers.tpl

@@ -0,0 +1,32 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "filebeat.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).
+*/}}
+{{- define "filebeat.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Use the fullname if the serviceAccount value is not set
+*/}}
+{{- define "filebeat.serviceAccount" -}}
+{{- if .Values.serviceAccount }}
+{{- .Values.serviceAccount -}}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}

+ 22 - 0
loki/loki-stack/charts/filebeat/templates/clusterrole.yaml

@@ -0,0 +1,22 @@
+{{- if .Values.managedServiceAccount }}
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRole
+metadata:
+  name: {{ template "filebeat.serviceAccount" . }}-cluster-role
+  labels:
+    app: "{{ template "filebeat.fullname" . }}"
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+    heritage: {{ .Release.Service | quote }}
+    release: {{ .Release.Name | quote }}
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - namespaces
+  - nodes
+  - pods
+  verbs:
+  - get
+  - list
+  - watch
+{{- end -}}

+ 19 - 0
loki/loki-stack/charts/filebeat/templates/clusterrolebinding.yaml

@@ -0,0 +1,19 @@
+{{- if .Values.managedServiceAccount }}
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+  name: {{ template "filebeat.serviceAccount" . }}-cluster-role-binding
+  labels:
+    app: "{{ template "filebeat.fullname" . }}"
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+    heritage: {{ .Release.Service | quote }}
+    release: {{ .Release.Name | quote }}
+roleRef:
+  kind: ClusterRole
+  name: {{ template "filebeat.serviceAccount" . }}-cluster-role
+  apiGroup: rbac.authorization.k8s.io
+subjects:
+- kind: ServiceAccount
+  name: {{ template "filebeat.serviceAccount" . }}
+  namespace: {{ .Release.Namespace }}
+{{- end -}}

+ 17 - 0
loki/loki-stack/charts/filebeat/templates/configmap.yaml

@@ -0,0 +1,17 @@
+{{- if .Values.filebeatConfig }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ template "filebeat.fullname" . }}-config
+  labels:
+    app: "{{ template "filebeat.fullname" . }}"
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+    heritage: {{ .Release.Service | quote }}
+    release: {{ .Release.Name | quote }}
+data:
+{{- range $path, $config := .Values.filebeatConfig }}
+  {{ $path }}: |
+{{ $config | indent 4 -}}
+{{- end -}}
+{{- end -}}

+ 171 - 0
loki/loki-stack/charts/filebeat/templates/daemonset.yaml

@@ -0,0 +1,171 @@
+---
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+  name: {{ template "filebeat.fullname" . }}
+  labels:
+    app: "{{ template "filebeat.fullname" . }}"
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+    heritage: {{ .Release.Service | quote }}
+    release: {{ .Release.Name | quote }}
+    {{- range $key, $value := .Values.labels }}
+    {{ $key }}: {{ $value | quote }}
+    {{- end }}
+spec:
+  selector:
+    matchLabels:
+      app: "{{ template "filebeat.fullname" . }}"
+      release: {{ .Release.Name | quote }}
+  updateStrategy:
+    type: {{ .Values.updateStrategy }}
+  template:
+    metadata:
+      annotations:
+        {{- range $key, $value := .Values.podAnnotations }}
+        {{ $key }}: {{ $value | quote }}
+        {{- end }}
+        {{/* This forces a restart if the configmap has changed */}}
+        {{- if .Values.filebeatConfig }}
+        configChecksum: {{ include (print .Template.BasePath "/configmap.yaml") . | sha256sum | trunc 63 }}
+        {{- end }}
+      name: "{{ template "filebeat.fullname" . }}"
+      labels:
+        app: "{{ template "filebeat.fullname" . }}"
+        chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+        heritage: {{ .Release.Service | quote }}
+        release: {{ .Release.Name | quote }}
+        {{- range $key, $value := .Values.labels }}
+        {{ $key }}: {{ $value | quote }}
+        {{- end }}
+    spec:
+      {{- with .Values.tolerations }}
+      tolerations: {{ toYaml . | nindent 6 }}
+      {{- end }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector: {{ toYaml . | nindent 8 }}
+      {{- end }}
+      {{- if .Values.priorityClassName }}
+      priorityClassName: {{ .Values.priorityClassName  }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity: {{ toYaml . | nindent 8 -}}
+      {{- end }}
+      serviceAccountName: {{ template "filebeat.serviceAccount" . }}
+      terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }}
+      {{- if .Values.hostNetworking }}
+      hostNetwork: true
+      dnsPolicy: ClusterFirstWithHostNet
+      {{- end }}
+      volumes:
+      {{- range .Values.secretMounts }}
+      - name: {{ .name }}
+        secret:
+          secretName: {{ .secretName }}
+      {{- end }}
+      {{- if .Values.filebeatConfig }}
+      - name: filebeat-config
+        configMap:
+          defaultMode: 0600
+          name: {{ template "filebeat.fullname" . }}-config
+      {{- end }}
+      - name: data
+        hostPath:
+          path: {{ .Values.hostPathRoot }}/{{ template "filebeat.fullname" . }}-{{ .Release.Namespace }}-data
+          type: DirectoryOrCreate
+      - name: varlibdockercontainers
+        hostPath:
+          path: /var/lib/docker/containers
+      - name: varlog
+        hostPath:
+          path: /var/log
+      - name: varrundockersock
+        hostPath:
+          path: /var/run/docker.sock
+      {{- if .Values.extraVolumes }}
+{{ toYaml .Values.extraVolumes | indent 6 }}
+      {{- end }}
+      {{- if .Values.imagePullSecrets }}
+      imagePullSecrets:
+{{ toYaml .Values.imagePullSecrets | indent 8 }}
+      {{- end }}
+      {{- if .Values.extraInitContainers }}
+      initContainers:
+      # All the other beats accept a string here while
+      # filebeat accepts a valid yaml array. We're keeping
+      # this as a backwards compatible change, while adding
+      # also a way to pass a string as other templates to
+      # make these implementations consistent.
+      # https://github.com/elastic/helm-charts/issues/490
+      {{- if eq "string" (printf "%T" .Values.extraInitContainers) }}
+{{ tpl .Values.extraInitContainers . | indent 8 }}
+      {{- else }}
+{{ toYaml .Values.extraInitContainers | indent 8 }}
+      {{- end }}
+      {{- end }}
+      containers:
+      - name: "filebeat"
+        image: "{{ .Values.image }}:{{ .Values.imageTag }}"
+        imagePullPolicy: "{{ .Values.imagePullPolicy }}"
+        args:
+        - "-e"
+        - "-E"
+        - "http.enabled=true"
+        livenessProbe:
+{{ toYaml .Values.livenessProbe | indent 10 }}
+        readinessProbe:
+{{ toYaml .Values.readinessProbe | indent 10 }}
+        resources:
+{{ toYaml .Values.resources | indent 10 }}
+        env:
+        - name: POD_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        - name: NODE_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: spec.nodeName
+{{- if .Values.extraEnvs }}
+{{ toYaml .Values.extraEnvs | indent 8 }}
+{{- end }}
+{{- if .Values.envFrom }}
+        envFrom:
+{{ toYaml .Values.envFrom | indent 10 }}
+{{- end }}
+{{- if .Values.podSecurityContext }}
+        securityContext:
+{{ toYaml .Values.podSecurityContext | indent 10 }}
+{{- end }}
+        volumeMounts:
+        {{- range .Values.secretMounts }}
+        - name: {{ .name }}
+          mountPath: {{ .path }}
+          {{- if .subPath }}
+          subPath: {{ .subPath }}
+          {{- end }}
+        {{- end }}
+        {{- range $path, $config := .Values.filebeatConfig }}
+        - name: filebeat-config
+          mountPath: /usr/share/filebeat/{{ $path }}
+          readOnly: true
+          subPath: {{ $path }}
+        {{- end }}
+        - name: data
+          mountPath: /usr/share/filebeat/data
+        - name: varlibdockercontainers
+          mountPath: /var/lib/docker/containers
+          readOnly: true
+        - name: varlog
+          mountPath: /var/log
+          readOnly: true
+        # Necessary when using autodiscovery; avoid mounting it otherwise
+        # See: https://www.elastic.co/guide/en/beats/filebeat/7.8/configuration-autodiscover.html
+        - name: varrundockersock
+          mountPath: /var/run/docker.sock
+          readOnly: true
+        {{- if .Values.extraVolumeMounts }}
+{{ toYaml .Values.extraVolumeMounts | indent 8 }}
+        {{- end }}
+      {{- if .Values.extraContainers }}
+{{ tpl .Values.extraContainers . | indent 6 }}
+      {{- end }}

+ 15 - 0
loki/loki-stack/charts/filebeat/templates/serviceaccount.yaml

@@ -0,0 +1,15 @@
+{{- if .Values.managedServiceAccount }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ template "filebeat.serviceAccount" . }}
+  annotations:
+    {{- with .Values.serviceAccountAnnotations }}
+    {{- toYaml . | nindent 4 }}
+    {{- end }}
+  labels:
+    app: "{{ template "filebeat.fullname" . }}"
+    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
+    heritage: {{ .Release.Service | quote }}
+    release: {{ .Release.Name | quote }}
+{{- end -}}

+ 142 - 0
loki/loki-stack/charts/filebeat/values.yaml

@@ -0,0 +1,142 @@
+---
+# Allows you to add any config files in /usr/share/filebeat
+# such as filebeat.yml
+filebeatConfig:
+  filebeat.yml: |
+    filebeat.inputs:
+    - type: container
+      paths:
+        - /var/log/containers/*.log
+      processors:
+      - add_kubernetes_metadata:
+          host: ${NODE_NAME}
+          matchers:
+          - logs_path:
+              logs_path: "/var/log/containers/"
+
+    output.elasticsearch:
+      host: '${NODE_NAME}'
+      hosts: '${ELASTICSEARCH_HOSTS:elasticsearch-master:9200}'
+
+# Extra environment variables to append to the DaemonSet pod spec.
+# This will be appended to the current 'env:' key. You can use any of the kubernetes env
+# syntax here
+extraEnvs: []
+#  - name: MY_ENVIRONMENT_VAR
+#    value: the_value_goes_here
+
+extraVolumeMounts: []
+  # - name: extras
+  #   mountPath: /usr/share/extras
+  #   readOnly: true
+
+extraVolumes: []
+  # - name: extras
+  #   emptyDir: {}
+
+extraContainers: ""
+# - name: dummy-init
+#   image: busybox
+#   command: ['echo', 'hey']
+
+extraInitContainers: []
+# - name: dummy-init
+#   image: busybox
+#   command: ['echo', 'hey']
+
+envFrom: []
+# - configMapRef:
+#     name: configmap-name
+
+# Root directory where Filebeat will write data to in order to persist registry data across pod restarts (file position and other metadata).
+hostPathRoot: /var/lib
+hostNetworking: false
+image: "docker.elastic.co/beats/filebeat"
+imageTag: "7.8.1"
+imagePullPolicy: "IfNotPresent"
+imagePullSecrets: []
+
+livenessProbe:
+  exec:
+    command:
+      - sh
+      - -c
+      - |
+        #!/usr/bin/env bash -e
+        curl --fail 127.0.0.1:5066
+  failureThreshold: 3
+  initialDelaySeconds: 10
+  periodSeconds: 10
+  timeoutSeconds: 5
+
+readinessProbe:
+  exec:
+    command:
+      - sh
+      - -c
+      - |
+        #!/usr/bin/env bash -e
+        filebeat test output
+  failureThreshold: 3
+  initialDelaySeconds: 10
+  periodSeconds: 10
+  timeoutSeconds: 5
+
+# Whether this chart should self-manage its service account, role, and associated role binding.
+managedServiceAccount: true
+
+# additionals labels
+labels: {}
+
+podAnnotations: {}
+  # iam.amazonaws.com/role: es-cluster
+
+# Various pod security context settings. Bear in mind that many of these have an impact on Filebeat functioning properly.
+#
+# - User that the container will execute as. Typically necessary to run as root (0) in order to properly collect host container logs.
+# - Whether to execute the Filebeat containers as privileged containers. Typically not necessarily unless running within environments such as OpenShift.
+podSecurityContext:
+  runAsUser: 0
+  privileged: false
+
+resources:
+  requests:
+    cpu: "100m"
+    memory: "100Mi"
+  limits:
+    cpu: "1000m"
+    memory: "200Mi"
+
+# Custom service account override that the pod will use
+serviceAccount: ""
+
+# Annotations to add to the ServiceAccount that is created if the serviceAccount value isn't set.
+serviceAccountAnnotations: {}
+  # eks.amazonaws.com/role-arn: arn:aws:iam::111111111111:role/k8s.clustername.namespace.serviceaccount
+
+# A list of secrets and their paths to mount inside the pod
+# This is useful for mounting certificates for security other sensitive values
+secretMounts: []
+#  - name: filebeat-certificates
+#    secretName: filebeat-certificates
+#    path: /usr/share/filebeat/certs
+
+# How long to wait for Filebeat pods to stop gracefully
+terminationGracePeriod: 30
+
+tolerations: []
+
+nodeSelector: {}
+
+affinity: {}
+
+# This is the PriorityClass settings as defined in
+# https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+priorityClassName: ""
+
+updateStrategy: RollingUpdate
+
+# Override various naming aspects of this chart
+# Only edit these if you know what you're doing
+nameOverride: ""
+fullnameOverride: ""

+ 22 - 0
loki/loki-stack/charts/fluent-bit/.helmignore

@@ -0,0 +1,22 @@
+# 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
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/

+ 14 - 0
loki/loki-stack/charts/fluent-bit/Chart.yaml

@@ -0,0 +1,14 @@
+apiVersion: v1
+appVersion: v2.1.0
+description: Uses fluent-bit Loki go plugin for gathering logs and sending them to
+  Loki
+home: https://grafana.com/loki
+icon: https://raw.githubusercontent.com/grafana/loki/master/docs/sources/logo.png
+kubeVersion: ^1.10.0-0
+maintainers:
+- email: lokiproject@googlegroups.com
+  name: Loki Maintainers
+name: fluent-bit
+sources:
+- https://github.com/grafana/loki
+version: 2.2.0

+ 124 - 0
loki/loki-stack/charts/fluent-bit/README.md

@@ -0,0 +1,124 @@
+# Fluent Bit Loki chart
+
+This chart install the Fluent Bit application to ship logs to Loki. It defines daemonset on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
+
+## Get Repo Info
+
+```console
+helm repo add grafana https://grafana.github.io/helm-charts
+helm repo update
+```
+
+_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._
+
+## Installing the Chart
+
+> If you don't have `Helm` installed locally, or `Tiller` installed in your Kubernetes cluster, read the [Using Helm](https://docs.helm.sh/using_helm/) documentation to get started.
+To install the chart with the release name `my-release` using our helm repository:
+
+```bash
+helm repo add grafana https://grafana.github.io/helm-charts
+helm upgrade --install my-release grafana/fluent-bit \
+    --set loki.serviceName=loki.default.svc.cluster.local
+```
+
+If you deploy Loki with a custom namespace or service name, you must change the value above for `loki.serviceName` to the appropriate value.
+
+The command deploys Fluent Bit on the Kubernetes cluster with the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
+
+To configure the chart to send to [Grafana Cloud](https://grafana.com/products/cloud) use:
+
+```bash
+helm upgrade --install my-release grafana/fluent-bit \
+    --set loki.serviceName=logs-us-west1.grafana.net,loki.servicePort=80,loki.serviceScheme=https \
+    --set loki.user=2830,loki.password=1234
+```
+
+> **Tip**: List all releases using `helm list`
+
+To install a custom tag use the following command:
+
+```bash
+helm upgrade --install my-release grafana/fluent-bit \
+    --set image.tag=<custom tag>
+```
+
+The full list of available tags on [docker hub](https://cloud.docker.com/u/grafana/repository/docker/grafana/fluent-bit-plugin-loki).
+
+Alternatively you can install the full [Loki stack](../loki-stack) (Loki + Fluent Bit) using:
+
+```bash
+helm upgrade --install my-release grafana/loki-stack \
+    --set fluent-bit.enabled=true,promtail.enabled=false
+```
+
+This will automatically configured the `loki.serviceName` configuration field to the newly created Loki instance.
+
+## RBAC
+
+By default, `rbac.create` is set to true. This enable RBAC support in Fluent Bit and must be true if RBAC is enabled in your cluster.
+
+The chart will take care of creating the required service accounts and roles for Fluent Bit.
+
+If you have RBAC disabled, or to put it another way, ABAC enabled, you should set this value to `false`.
+
+## Uninstalling the Chart
+
+To uninstall/delete the `my-release` deployment:
+
+```bash
+helm delete my-release
+```
+
+The command removes all the Kubernetes components associated with the chart and deletes the release.
+
+## Configuration
+
+The following tables lists the configurable parameters of the Fluent Bit chart and their default values.
+
+For more details, read the [Fluent Bit documentation](../../../cmd/fluent-bit/README.md)
+
+| Parameter                | Description                                                                                        | Default                          |
+|--------------------------|----------------------------------------------------------------------------------------------------|----------------------------------|
+| `loki.serviceName`       | The address of the Loki service.                                                                   | `"${RELEASE}-loki"`              |
+| `loki.servicePort`       | The port of the Loki service.                                                                      | `3100`                           |
+| `loki.serviceScheme`     | The scheme of the Loki service.                                                                    | `http`                           |
+| `loki.user`              | The http basic auth username to access the Loki service.                                           |                                  |
+| `loki.password`          | The http basic auth password to access the Loki service.                                           |                                  |
+| `config.port`            | the Fluent Bit port to listen. (This is mainly used to serve metrics)                              | `2020`                           |
+| `config.tenantID`        | The tenantID used by default to push logs to Loki                                                  | `''`                             |
+| `config.batchWait`       | Time to wait before send a log batch to Loki, full or not. (unit: secs)                            | `1`                              |
+| `config.batchSize`       | Log batch size to send a log batch to Loki. (unit: bytes)                                          | `10240` (10KiB)                  |
+| `config.loglevel`        | the Fluent Bit log level (debug,info,warn,error).                                                  | `warn`                           |
+| `config.lineFormat`      | The line format to use to send a record (json/key_value)                                           | `json`                           |
+| `config.k8sLoggingParser`| Allow Kubernetes Pods to suggest a pre-defined Parser. See [Official Fluent Bit documentation](https://docs.fluentbit.io/manual/filter/kubernetes#kubernetes-annotations).                                                                                      | `Off`                           |
+| `config.k8sLoggingExclude`| Allow Kubernetes Pods to exclude their logs from the log processor. See [Official Fluent Bit documentation](https://docs.fluentbit.io/manual/pipeline/filters/kubernetes)                                                                                             | `Off`
+| `config.memBufLimit`     | Override the default  Mem_Buf_Limit [Official Fluent Bit documentation](https://docs.fluentbit.io/manual/administration/backpressure#mem_buf_limit) | `5MB`
+| `config.removeKeys`      | The list of key to remove from each record                                                         | `[removeKeys,stream]`            |
+| `config.labels`          | A set of labels to send for every log                                                              | `'{job="fluent-bit"}'`           |
+| `config.autoKubernetesLabels` | If set to true, it will add all Kubernetes labels to Loki labels                                   | `false`                          |
+| `config.labelMap`        | Mapping of labels from a record. See [Fluent Bit documentation](../../../cmd/fluent-bit/README.md) |                                  |
+| `config.parsers`         | Definition of extras fluent bit parsers. See [Official Fluent Bit documentation](https://docs.fluentbit.io/manual/filter/parser). The format is a sequence of mappings where each key is the same as the one in the [PARSER] section of parsers.conf file       | `[]`                            |
+| `config.extraOutputs`    | Definition of extras fluent bit outputs. See [Official Fluent Bit documentation](https://docs.fluentbit.io/manual/pipeline/outputs/). The format is a sequence of mappings where each key is the same as the one in the [OUTPUT]                                | `[]`                            |
+| `affinity`               | [affinity][affinity] settings for pod assignment                                                   | `{}`                             |
+| `annotations`            | Annotations to add to Kubernetes resources.                                                        | `{}`                             |
+| `deploymentStrategy`     | The deployment strategy to use with the daemonset                                                  | `RollingUpdate`                  |
+| `image.repository`       | The Fluent Bit docker image repository                                                             | `grafana/fluent-bit-plugin-loki` |
+| `image.tag`              | The Fluent Bit docker image tag                                                                    | `0.1`                            |
+| `image.pullPolicy`       | The Fluent Bit docker image pull policy                                                            | `IfNotPresent`                   |
+| `nodeSelector`           | Fluent Bit [node labels][nodeSelector] for pod assignment                                          | `{}`                             |
+| `podLabels`              | additional Fluent Bit pod labels                                                                   | `{}`                             |
+| `podAnnotations`         | additional Fluent Bit pod annotations                                                              | `Prometheus discovery`           |
+| `rbac.create`            | Activate support for RBAC                                                                          | `true`                           |
+| `resources`              | Resource requests/limit                                                                            |                                  |
+| `tolerations`            | [Toleration][toleration] labels for pod assignment                                                 | `no schedule on master nodes`    |
+| `volumes`                | [Volume]([volumes]) to mount                                                                       | `host containers log`            |
+| `volumeMounts`           | Volume mount mapping                                                                               |                                  |
+| `serviceMonitor.enabled` | Create a [Prometheus Operator](operator) serviceMonitor resource for Fluent Bit                    | `false`                          |
+
+
+[toleration]: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+[nodeSelector]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+[affinity]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+[volumes]: https://kubernetes.io/docs/concepts/storage/volumes/
+[operator]: https://github.com/coreos/prometheus-operator

+ 3 - 0
loki/loki-stack/charts/fluent-bit/templates/NOTES.txt

@@ -0,0 +1,3 @@
+Verify the application is working by running these commands:
+  kubectl --namespace {{ .Release.Namespace }} port-forward daemonset/{{ include "fluent-bit-loki.fullname" . }} {{ .Values.config.port }}
+  curl http://127.0.0.1:{{ .Values.config.port }}/api/v1/metrics/prometheus

+ 66 - 0
loki/loki-stack/charts/fluent-bit/templates/_helpers.tpl

@@ -0,0 +1,66 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "fluent-bit-loki.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 "fluent-bit-loki.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 "fluent-bit-loki.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create the name of the service account
+*/}}
+{{- define "fluent-bit-loki.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "fluent-bit-loki.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+The service name to connect to Loki. Defaults to the same logic as "loki.fullname"
+*/}}
+{{- define "loki.serviceName" -}}
+{{- if .Values.loki.serviceName -}}
+{{- .Values.loki.serviceName -}}
+{{- else if .Values.loki.fullnameOverride -}}
+{{- .Values.loki.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default "loki" .Values.loki.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{- define "helm-toolkit.utils.joinListWithComma" -}}
+{{- $local := dict "first" true -}}
+{{- range $k, $v := . -}}{{- if not $local.first -}},{{- end -}}{{- $v -}}{{- $_ := set $local "first" false -}}{{- end -}}
+{{- end -}}

+ 17 - 0
loki/loki-stack/charts/fluent-bit/templates/clusterrole.yaml

@@ -0,0 +1,17 @@
+{{- if .Values.rbac.create }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+  name: {{ template "fluent-bit-loki.fullname" . }}-clusterrole
+rules:
+- apiGroups: [""] # "" indicates the core API group
+  resources:
+  - namespaces
+  - pods
+  verbs: ["get", "watch", "list"]
+{{- end }}

+ 19 - 0
loki/loki-stack/charts/fluent-bit/templates/clusterrolebinding.yaml

@@ -0,0 +1,19 @@
+{{- if .Values.rbac.create }}
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}-clusterrolebinding
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ template "fluent-bit-loki.serviceAccountName" . }}
+    namespace: {{ .Release.Namespace }}
+roleRef:
+  kind: ClusterRole
+  name: {{ template "fluent-bit-loki.fullname" . }}-clusterrole
+  apiGroup: rbac.authorization.k8s.io
+{{- end }}

+ 73 - 0
loki/loki-stack/charts/fluent-bit/templates/configmap.yaml

@@ -0,0 +1,73 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+data:
+  fluent-bit.conf: |-
+    [SERVICE]
+        HTTP_Server    On
+        HTTP_Listen    0.0.0.0
+        HTTP_PORT      {{ .Values.config.port }}
+        Flush          1
+        Daemon         Off
+        Log_Level      {{ .Values.config.loglevel }}
+        Parsers_File   parsers.conf
+    [INPUT]
+        Name           tail
+        Tag            kube.*
+        Path           /var/log/containers/*.log
+        Parser         docker
+        DB             /run/fluent-bit/flb_kube.db
+        Mem_Buf_Limit  {{ .Values.config.memBufLimit }}
+    [FILTER]
+        Name           kubernetes
+        Match          kube.*
+        Kube_URL       https://kubernetes.default.svc:443
+        Merge_Log On
+        K8S-Logging.Exclude {{ .Values.config.k8sLoggingExclude }}
+        K8S-Logging.Parser {{ .Values.config.k8sLoggingParser }}
+    [Output]
+        Name grafana-loki
+        Match *
+        {{- if and .Values.loki.user .Values.loki.password }}
+        Url {{ .Values.loki.serviceScheme }}://{{ .Values.loki.user }}:{{ .Values.loki.password }}@{{ include "loki.serviceName" . }}:{{ .Values.loki.servicePort }}{{ .Values.loki.servicePath }}
+          {{- else }}
+        Url {{ .Values.loki.serviceScheme }}://{{ include "loki.serviceName" . }}:{{ .Values.loki.servicePort }}{{ .Values.loki.servicePath }}
+        {{- end }}
+        TenantID {{ .Values.config.tenantID }}
+        BatchWait {{ .Values.config.batchWait }}
+        BatchSize {{ int .Values.config.batchSize }}
+        Labels {{ .Values.config.labels }}
+        RemoveKeys {{ include "helm-toolkit.utils.joinListWithComma" .Values.config.removeKeys }}
+        AutoKubernetesLabels {{ .Values.config.autoKubernetesLabels }}
+        LabelMapPath /fluent-bit/etc/labelmap.json
+        LineFormat {{ .Values.config.lineFormat }}
+        LogLevel {{ .Values.config.loglevel }}
+    {{- range $extraOutput := .Values.config.extraOutputs }}
+    [OUTPUT]
+    {{- range $key,$value := $extraOutput }}
+        {{ $key }} {{ $value }}
+    {{- end }}
+    {{- end }}
+  parsers.conf: |-
+    [PARSER]
+        Name        docker
+        Format      json
+        Time_Key    time
+        Time_Format %Y-%m-%dT%H:%M:%S.%L
+    {{- range $parser:= .Values.config.parsers }}
+    [PARSER]
+    {{- range $key,$value := $parser }}
+        {{ $key }} {{ $value }}
+    {{- end }}
+    {{- end }}
+
+  labelmap.json: |-
+    {{- .Values.config.labelMap | toPrettyJson | nindent 4}}
+

+ 80 - 0
loki/loki-stack/charts/fluent-bit/templates/daemonset.yaml

@@ -0,0 +1,80 @@
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+  annotations:
+    {{- toYaml .Values.annotations | nindent 4 }}
+spec:
+  selector:
+    matchLabels:
+      app: {{ template "fluent-bit-loki.name" . }}
+      release: {{ .Release.Name }}
+  updateStrategy:
+    type: {{ .Values.deploymentStrategy }}
+  {{- if ne .Values.deploymentStrategy "RollingUpdate" }}
+    rollingUpdate: null
+  {{- end }}
+  template:
+    metadata:
+      labels:
+        app: {{ template "fluent-bit-loki.name" . }}
+        release: {{ .Release.Name }}
+        {{- with .Values.podLabels }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}
+      annotations:
+        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+        {{- with .Values.podAnnotations }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}
+    spec:
+      serviceAccountName: {{ template "fluent-bit-loki.serviceAccountName" . }}
+      {{- if .Values.priorityClassName }}
+      priorityClassName: {{ .Values.priorityClassName }}
+      {{- end }}
+      {{- if .Values.image.pullSecrets }}
+      imagePullSecrets:
+      {{- range .Values.image.pullSecrets }}
+        - name: {{ . }}
+      {{- end }}
+      {{- end }}
+      containers:
+        - name: fluent-bit-loki
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          volumeMounts:
+            - name: config
+              mountPath: /fluent-bit/etc
+            - name: run
+              mountPath: /run/fluent-bit
+            {{- with .Values.volumeMounts }}
+            {{- toYaml . | nindent 12 }}
+            {{- end }}
+          ports:
+            - containerPort: {{ .Values.config.port }}
+              name: http-metrics
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      affinity:
+        {{- toYaml .Values.affinity | nindent 8 }}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      terminationGracePeriodSeconds: 10
+      volumes:
+        - name: config
+          configMap:
+            name: {{ template "fluent-bit-loki.fullname" . }}
+        - name: run
+          hostPath:
+            path: /run/fluent-bit
+        {{- with .Values.volumes }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}

+ 34 - 0
loki/loki-stack/charts/fluent-bit/templates/podsecuritypolicy.yaml

@@ -0,0 +1,34 @@
+{{- if .Values.rbac.pspEnabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+spec:
+  privileged: false
+  allowPrivilegeEscalation: false
+  volumes:
+    - 'secret'
+    - 'configMap'
+    - 'hostPath'
+    - 'projected'
+    - 'downwardAPI'
+  hostNetwork: false
+  hostIPC: false
+  hostPID: false
+  runAsUser:
+    rule: 'RunAsAny'
+  seLinux:
+    rule: 'RunAsAny'
+  supplementalGroups:
+    rule: 'RunAsAny'
+  fsGroup:
+    rule: 'RunAsAny'
+  readOnlyRootFilesystem: true
+  requiredDropCapabilities:
+    - ALL
+{{- end }}

+ 19 - 0
loki/loki-stack/charts/fluent-bit/templates/role.yaml

@@ -0,0 +1,19 @@
+{{- if .Values.rbac.create }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+{{- if .Values.rbac.pspEnabled }}
+rules:
+- apiGroups:      ['extensions']
+  resources:      ['podsecuritypolicies']
+  verbs:          ['use']
+  resourceNames:  [{{ template "fluent-bit-loki.fullname" . }}]
+{{- end }}
+{{- end }}

+ 19 - 0
loki/loki-stack/charts/fluent-bit/templates/rolebinding.yaml

@@ -0,0 +1,19 @@
+{{- if .Values.rbac.create }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ template "fluent-bit-loki.fullname" . }}
+subjects:
+- kind: ServiceAccount
+  name: {{ template "fluent-bit-loki.serviceAccountName" . }}
+{{- end }}

+ 22 - 0
loki/loki-stack/charts/fluent-bit/templates/service-headless.yaml

@@ -0,0 +1,22 @@
+{{- if .Values.serviceMonitor.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}-headless
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+spec:
+  clusterIP: None
+  ports:
+    - port: {{ .Values.config.port }}
+      protocol: TCP
+      name: http-metrics
+      targetPort: http-metrics
+  selector:
+    app: {{ template "fluent-bit-loki.name" . }}
+    release: {{ .Release.Name }}
+{{- end }}

+ 12 - 0
loki/loki-stack/charts/fluent-bit/templates/serviceaccount.yaml

@@ -0,0 +1,12 @@
+{{- if .Values.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    heritage: {{ .Release.Service }}
+    release: {{ .Release.Name }}
+  name: {{ template "fluent-bit-loki.serviceAccountName" . }}
+  namespace: {{ .Release.Namespace }}
+{{- end }}

+ 35 - 0
loki/loki-stack/charts/fluent-bit/templates/servicemonitor.yaml

@@ -0,0 +1,35 @@
+{{- if .Values.serviceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+  name: {{ template "fluent-bit-loki.fullname" . }}
+  labels:
+    app: {{ template "fluent-bit-loki.name" . }}
+    chart: {{ template "fluent-bit-loki.chart" . }}
+    release: {{ .Release.Name }}
+    heritage: {{ .Release.Service }}
+    {{- if .Values.serviceMonitor.additionalLabels }}
+{{ toYaml .Values.serviceMonitor.additionalLabels | indent 4 }}
+    {{- end }}
+  {{- if .Values.serviceMonitor.annotations }}
+  annotations:
+{{ toYaml .Values.serviceMonitor.annotations | indent 4 }}
+  {{- end }}
+spec:
+  selector:
+    matchLabels:
+      app: {{ template "fluent-bit-loki.name" . }}
+      release: {{ .Release.Name | quote }}
+  namespaceSelector:
+    matchNames:
+      - {{ .Release.Namespace | quote }}
+  endpoints:
+  - port: http-metrics
+    path: /api/v1/metrics/prometheus
+    {{- if .Values.serviceMonitor.interval }}
+    interval: {{ .Values.serviceMonitor.interval }}
+    {{- end }}
+    {{- if .Values.serviceMonitor.scrapeTimeout }}
+    scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }}
+    {{- end }}
+{{- end }}

+ 120 - 0
loki/loki-stack/charts/fluent-bit/values.yaml

@@ -0,0 +1,120 @@
+---
+loki:
+  serviceName: ""  # Defaults to "${RELEASE}-loki" if not set
+  servicePort: 3100
+  serviceScheme: http
+  servicePath: /api/prom/push
+  # user: user
+  # password: pass
+config:
+  port: 2020
+  tenantID: '""'
+  batchWait: 1
+  batchSize: 1048576
+  loglevel: warn
+  lineFormat: json
+  k8sLoggingExclude: "Off"
+  k8sLoggingParser: "Off"
+  memBufLimit: "5MB"
+  removeKeys:
+    - kubernetes
+    - stream
+  autoKubernetesLabels: false
+  labels: '{job="fluent-bit"}'
+  labelMap:
+    kubernetes:
+      namespace_name: namespace
+      labels:
+        app: app
+        release: release
+      host: node
+      container_name: container
+      pod_name: instance
+    stream: stream
+  # parsers: # Allow to define custom parsers. The key here is the same as the one in the [PARSER] section of parsers.conf file.
+  #  - Name: json
+  #    Format: json
+  #    Time_Key: time
+  #    Time_Format: "%d/%b/%Y:%H:%M:%S %z"
+
+  # extraOutputs: # Allow to define extra outputs in addition to the one automatically created
+  #   - Name: stdout
+  #     Format: json
+  #     json_date_format: time
+
+affinity: {}
+
+annotations: {}
+
+deploymentStrategy: RollingUpdate
+
+image:
+  repository: grafana/fluent-bit-plugin-loki
+  tag: 2.1.0-amd64
+  pullPolicy: IfNotPresent
+  ## Optionally specify an array of imagePullSecrets.
+  ## Secrets must be present in the namespace.
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+  # pullSecrets:
+  #   - myRegistrKeySecretName
+
+nameOverride: fluent-bit-loki
+
+## Node labels for pod assignment
+## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+nodeSelector: {}
+
+## Pod Labels
+podLabels: {}
+
+podAnnotations:
+  prometheus.io/scrape: "true"
+  prometheus.io/port: "2020"
+  prometheus.io/path: /api/v1/metrics/prometheus
+
+## Assign a PriorityClassName to pods if set
+# priorityClassName:
+
+rbac:
+  create: true
+  pspEnabled: true
+
+resources:
+  limits:
+    memory: 100Mi
+  requests:
+    cpu: 100m
+    memory: 100Mi
+
+serviceAccount:
+  create: true
+  name:
+
+## Tolerations for pod assignment
+## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+tolerations:
+- key: node-role.kubernetes.io/master
+  effect: NoSchedule
+
+# Extra volumes to scrape logs from
+volumes:
+- name: varlog
+  hostPath:
+    path: /var/log
+- name: varlibdockercontainers
+  hostPath:
+    path: /var/lib/docker/containers
+
+volumeMounts:
+- name: varlog
+  mountPath: /var/log
+- name: varlibdockercontainers
+  mountPath: /var/lib/docker/containers
+  readOnly: true
+
+serviceMonitor:
+  enabled: false
+  interval: ""
+  additionalLabels: {}
+  annotations: {}
+  # scrapeTimeout: 10s

+ 23 - 0
loki/loki-stack/charts/grafana/.helmignore

@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*~
+# Various IDEs
+.vscode
+.project
+.idea/
+*.tmproj
+OWNERS

+ 17 - 0
loki/loki-stack/charts/grafana/Chart.yaml

@@ -0,0 +1,17 @@
+apiVersion: v1
+appVersion: 7.2.1
+description: The leading tool for querying and visualizing time series and metrics.
+home: https://grafana.net
+icon: https://raw.githubusercontent.com/grafana/grafana/master/public/img/logo_transparent_400x.png
+kubeVersion: ^1.8.0-0
+maintainers:
+- email: zanhsieh@gmail.com
+  name: zanhsieh
+- email: rluckie@cisco.com
+  name: rtluckie
+- email: maor.friedman@redhat.com
+  name: maorfr
+name: grafana
+sources:
+- https://github.com/grafana/grafana
+version: 5.7.10

+ 497 - 0
loki/loki-stack/charts/grafana/README.md

@@ -0,0 +1,497 @@
+# Grafana Helm Chart
+
+* Installs the web dashboarding system [Grafana](http://grafana.org/)
+
+## Get Repo Info
+
+```console
+helm repo add grafana https://grafana.github.io/helm-charts
+helm repo update
+```
+
+_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._
+
+## Installing the Chart
+
+To install the chart with the release name `my-release`:
+
+```console
+helm install --name my-release grafana/grafana
+```
+
+## Uninstalling the Chart
+
+To uninstall/delete the my-release deployment:
+
+```console
+helm delete my-release
+```
+
+The command removes all the Kubernetes components associated with the chart and deletes the release.
+
+## Upgrading an existing Release to a new major version
+
+A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an
+incompatible breaking change needing manual actions.
+
+### To 4.0.0 (And 3.12.1)
+
+This version requires Helm >= 2.12.0.
+
+### To 5.0.0
+
+You have to add --force to your helm upgrade command as the labels of the chart have changed.
+
+## Configuration
+
+| Parameter                                 | Description                                   | Default                                                 |
+|-------------------------------------------|-----------------------------------------------|---------------------------------------------------------|
+| `replicas`                                | Number of nodes                               | `1`                                                     |
+| `podDisruptionBudget.minAvailable`        | Pod disruption minimum available              | `nil`                                                   |
+| `podDisruptionBudget.maxUnavailable`      | Pod disruption maximum unavailable            | `nil`                                                   |
+| `deploymentStrategy`                      | Deployment strategy                           | `{ "type": "RollingUpdate" }`                           |
+| `livenessProbe`                           | Liveness Probe settings                       | `{ "httpGet": { "path": "/api/health", "port": 3000 } "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10 }` |
+| `readinessProbe`                          | Readiness Probe settings                      | `{ "httpGet": { "path": "/api/health", "port": 3000 } }`|
+| `securityContext`                         | Deployment securityContext                    | `{"runAsUser": 472, "runAsGroup": 472, "fsGroup": 472}`  |
+| `priorityClassName`                       | Name of Priority Class to assign pods         | `nil`                                                   |
+| `image.repository`                        | Image repository                              | `grafana/grafana`                                       |
+| `image.tag`                               | Image tag (`Must be >= 5.0.0`)                | `7.0.3`                                                 |
+| `image.sha`                               | Image sha (optional)                          | `17cbd08b9515fda889ca959e9d72ee6f3327c8f1844a3336dfd952134f38e2fe` |
+| `image.pullPolicy`                        | Image pull policy                             | `IfNotPresent`                                          |
+| `image.pullSecrets`                       | Image pull secrets                            | `{}`                                                    |
+| `service.type`                            | Kubernetes service type                       | `ClusterIP`                                             |
+| `service.port`                            | Kubernetes port where service is exposed      | `80`                                                    |
+| `service.portName`                        | Name of the port on the service               | `service`                                               |
+| `service.targetPort`                      | Internal service is port                      | `3000`                                                  |
+| `service.nodePort`                        | Kubernetes service nodePort                   | `nil`                                                   |
+| `service.annotations`                     | Service annotations                           | `{}`                                                    |
+| `service.labels`                          | Custom labels                                 | `{}`                                                    |
+| `service.clusterIP`                       | internal cluster service IP                   | `nil`                                                   |
+| `service.loadBalancerIP`                  | IP address to assign to load balancer (if supported) | `nil`                                            |
+| `service.loadBalancerSourceRanges`        | list of IP CIDRs allowed access to lb (if supported) | `[]`                                             |
+| `service.externalIPs`                     | service external IP addresses                 | `[]`                                                    |
+| `extraExposePorts`                        | Additional service ports for sidecar containers| `[]`                                                   |
+| `hostAliases`                             | adds rules to the pod's /etc/hosts            | `[]`                                                    |
+| `ingress.enabled`                         | Enables Ingress                               | `false`                                                 |
+| `ingress.annotations`                     | Ingress annotations (values are templated)    | `{}`                                                    |
+| `ingress.labels`                          | Custom labels                                 | `{}`                                                    |
+| `ingress.path`                            | Ingress accepted path                         | `/`                                                     |
+| `ingress.hosts`                           | Ingress accepted hostnames                    | `["chart-example.local"]`                                                    |
+| `ingress.extraPaths`                      | Ingress extra paths to prepend to every host configuration. Useful when configuring [custom actions with AWS ALB Ingress Controller](https://kubernetes-sigs.github.io/aws-alb-ingress-controller/guide/ingress/annotation/#actions). | `[]`                                                    |
+| `ingress.tls`                             | Ingress TLS configuration                     | `[]`                                                    |
+| `resources`                               | CPU/Memory resource requests/limits           | `{}`                                                    |
+| `nodeSelector`                            | Node labels for pod assignment                | `{}`                                                    |
+| `tolerations`                             | Toleration labels for pod assignment          | `[]`                                                    |
+| `affinity`                                | Affinity settings for pod assignment          | `{}`                                                    |
+| `extraInitContainers`                     | Init containers to add to the grafana pod     | `{}`                                                    |
+| `extraContainers`                         | Sidecar containers to add to the grafana pod  | `{}`                                                    |
+| `extraContainerVolumes`                   | Volumes that can be mounted in sidecar containers | `[]`                                                |
+| `schedulerName`                           | Name of the k8s scheduler (other than default) | `nil`                                                  |
+| `persistence.enabled`                     | Use persistent volume to store data           | `false`                                                 |
+| `persistence.type`                        | Type of persistence (`pvc` or `statefulset`)  | `pvc`                                                   |
+| `persistence.size`                        | Size of persistent volume claim               | `10Gi`                                                  |
+| `persistence.existingClaim`               | Use an existing PVC to persist data           | `nil`                                                   |
+| `persistence.storageClassName`            | Type of persistent volume claim               | `nil`                                                   |
+| `persistence.accessModes`                 | Persistence access modes                      | `[ReadWriteOnce]`                                       |
+| `persistence.annotations`                 | PersistentVolumeClaim annotations             | `{}`                                                    |
+| `persistence.finalizers`                  | PersistentVolumeClaim finalizers              | `[ "kubernetes.io/pvc-protection" ]`                    |
+| `persistence.subPath`                     | Mount a sub dir of the persistent volume      | `nil`                                                   |
+| `initChownData.enabled`                   | If false, don't reset data ownership at startup | true                                                  |
+| `initChownData.image.repository`          | init-chown-data container image repository    | `busybox`                                               |
+| `initChownData.image.tag`                 | init-chown-data container image tag           | `1.31.1`                                                |
+| `initChownData.image.sha`                 | init-chown-data container image sha (optional)| `""`                                                    |
+| `initChownData.image.pullPolicy`          | init-chown-data container image pull policy   | `IfNotPresent`                                          |
+| `initChownData.resources`                 | init-chown-data pod resource requests & limits | `{}`                                                   |
+| `schedulerName`                           | Alternate scheduler name                      | `nil`                                                   |
+| `env`                                     | Extra environment variables passed to pods    | `{}`                                                    |
+| `envValueFrom`                            | Environment variables from alternate sources. See the API docs on [EnvVarSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core) for format details.  | `{}` |
+| `envFromSecret`                           | Name of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `""` |
+| `envRenderSecret`                         | Sensible environment variables passed to pods and stored as secret | `{}`                               |
+| `extraSecretMounts`                       | Additional grafana server secret mounts       | `[]`                                                    |
+| `extraVolumeMounts`                       | Additional grafana server volume mounts       | `[]`                                                    |
+| `extraConfigmapMounts`                    | Additional grafana server configMap volume mounts | `[]`                                                |
+| `extraEmptyDirMounts`                     | Additional grafana server emptyDir volume mounts | `[]`                                                 |
+| `plugins`                                 | Plugins to be loaded along with Grafana       | `[]`                                                    |
+| `datasources`                             | Configure grafana datasources (passed through tpl) | `{}`                                               |
+| `notifiers`                               | Configure grafana notifiers                   | `{}`                                                    |
+| `dashboardProviders`                      | Configure grafana dashboard providers         | `{}`                                                    |
+| `dashboards`                              | Dashboards to import                          | `{}`                                                    |
+| `dashboardsConfigMaps`                    | ConfigMaps reference that contains dashboards | `{}`                                                    |
+| `grafana.ini`                             | Grafana's primary configuration               | `{}`                                                    |
+| `ldap.enabled`                            | Enable LDAP authentication                    | `false`                                                 |
+| `ldap.existingSecret`                     | The name of an existing secret containing the `ldap.toml` file, this must have the key `ldap-toml`. | `""` |
+| `ldap.config`                             | Grafana's LDAP configuration                  | `""`                                                    |
+| `annotations`                             | Deployment annotations                        | `{}`                                                    |
+| `labels`                                  | Deployment labels                             | `{}`                                                    |
+| `podAnnotations`                          | Pod annotations                               | `{}`                                                    |
+| `podLabels`                               | Pod labels                                    | `{}`                                                    |
+| `podPortName`                             | Name of the grafana port on the pod           | `grafana`                                               |
+| `sidecar.image.repository`                | Sidecar image repository                      | `kiwigrid/k8s-sidecar`                                  |
+| `sidecar.image.tag`                       | Sidecar image tag                             | `0.1.151`                                               |
+| `sidecar.image.sha`                       | Sidecar image sha (optional)                  | `""`                                                    |
+| `sidecar.imagePullPolicy`                 | Sidecar image pull policy                     | `IfNotPresent`                                          |
+| `sidecar.resources`                       | Sidecar resources                             | `{}`                                                    |
+| `sidecar.enableUniqueFilenames`           | Sets the kiwigrid/k8s-sidecar UNIQUE_FILENAMES environment variable | `false`                           |
+| `sidecar.dashboards.enabled`              | Enables the cluster wide search for dashboards and adds/updates/deletes them in grafana | `false`       |
+| `sidecar.dashboards.SCProvider`           | Enables creation of sidecar provider          | `true`                                                  |
+| `sidecar.dashboards.provider.name`        | Unique name of the grafana provider           | `sidecarProvider`                                       |
+| `sidecar.dashboards.provider.orgid`       | Id of the organisation, to which the dashboards should be added | `1`                                   |
+| `sidecar.dashboards.provider.folder`      | Logical folder in which grafana groups dashboards | `""`                                                |
+| `sidecar.dashboards.provider.disableDelete` | Activate to avoid the deletion of imported dashboards | `false`                                       |
+| `sidecar.dashboards.provider.allowUiUpdates` | Allow updating provisioned dashboards from the UI | `false`                                          |
+| `sidecar.dashboards.provider.type`        | Provider type                                 | `file`                                                  |
+| `sidecar.dashboards.provider.foldersFromFilesStructure`        | Allow Grafana to replicate dashboard structure from filesystem.                                 | `false`                                                  |
+| `sidecar.dashboards.watchMethod`          | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` |
+| `sidecar.skipTlsVerify`                   | Set to true to skip tls verification for kube api calls | `nil`                                         |
+| `sidecar.dashboards.label`                | Label that config maps with dashboards should have to be added | `grafana_dashboard`                                |
+| `sidecar.dashboards.folder`               | Folder in the pod that should hold the collected dashboards (unless `sidecar.dashboards.defaultFolderName` is set). This path will be mounted. | `/tmp/dashboards`    |
+| `sidecar.dashboards.defaultFolderName`    | The default folder name, it will create a subfolder under the `sidecar.dashboards.folder` and put dashboards in there instead | `nil`                                |
+| `sidecar.dashboards.searchNamespace`      | If specified, the sidecar will search for dashboard config-maps inside this namespace. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces | `nil`                                |
+| `sidecar.datasources.enabled`             | Enables the cluster wide search for datasources and adds/updates/deletes them in grafana |`false`       |
+| `sidecar.datasources.label`               | Label that config maps with datasources should have to be added | `grafana_datasource`                               |
+| `sidecar.datasources.searchNamespace`     | If specified, the sidecar will search for datasources config-maps inside this namespace. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces | `nil`                               |
+| `sidecar.notifiers.enabled`               | Enables the cluster wide search for notifiers and adds/updates/deletes them in grafana |`false`       |
+| `sidecar.notifiers.label`                 | Label that config maps with notifiers should have to be added | `grafana_notifier`                               |
+| `sidecar.notifiers.searchNamespace`       | If specified, the sidecar will search for notifiers config-maps (or secrets) inside this namespace. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces | `nil`                               |
+| `smtp.existingSecret`                     | The name of an existing secret containing the SMTP credentials. | `""`                                  |
+| `smtp.userKey`                            | The key in the existing SMTP secret containing the username. | `"user"`                                 |
+| `smtp.passwordKey`                        | The key in the existing SMTP secret containing the password. | `"password"`                             |
+| `admin.existingSecret`                    | The name of an existing secret containing the admin credentials. | `""`                                 |
+| `admin.userKey`                           | The key in the existing admin secret containing the username. | `"admin-user"`                          |
+| `admin.passwordKey`                       | The key in the existing admin secret containing the password. | `"admin-password"`                      |
+| `serviceAccount.annotations`              | ServiceAccount annotations                    |                                                         |
+| `serviceAccount.create`                   | Create service account                        | `true`                                                  |
+| `serviceAccount.name`                     | Service account name to use, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `` |
+| `serviceAccount.nameTest`                 | Service account name to use for test, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `nil` |
+| `rbac.create`                             | Create and use RBAC resources                 | `true`                                                  |
+| `rbac.namespaced`                         | Creates Role and Rolebinding instead of the default ClusterRole and ClusteRoleBindings for the grafana instance  | `false` |
+| `rbac.pspEnabled`                         | Create PodSecurityPolicy (with `rbac.create`, grant roles permissions as well) | `true`                 |
+| `rbac.pspUseAppArmor`                     | Enforce AppArmor in created PodSecurityPolicy (requires `rbac.pspEnabled`)  | `true`                    |
+| `rbac.extraRoleRules`                     | Additional rules to add to the Role           | []                                                      |
+| `rbac.extraClusterRoleRules`              | Additional rules to add to the ClusterRole    | []                                                      |
+| `command`                     | Define command to be executed by grafana container at startup  | `nil`                                              |
+| `testFramework.enabled`                   | Whether to create test-related resources      | `true`                                                  |
+| `testFramework.image`                     | `test-framework` image repository.            | `bats/bats`                                        |
+| `testFramework.tag`                       | `test-framework` image tag.                   | `v1.1.0`                                                 |
+| `testFramework.imagePullPolicy`           | `test-framework` image pull policy.           | `IfNotPresent`                                             |
+| `testFramework.securityContext`           | `test-framework` securityContext              | `{}`                                                    |
+| `downloadDashboards.env`                  | Environment variables to be passed to the `download-dashboards` container | `{}`                        |
+| `downloadDashboards.resources`            | Resources of `download-dashboards` container  | `{}`                                                    |
+| `downloadDashboardsImage.repository`      | Curl docker image repo                        | `curlimages/curl`                                       |
+| `downloadDashboardsImage.tag`             | Curl docker image tag                         | `7.70.0`                                                |
+| `downloadDashboardsImage.sha`             | Curl docker image sha (optional)              | `""`                                                    |
+| `downloadDashboardsImage.pullPolicy`      | Curl docker image pull policy                 | `IfNotPresent`                                          |
+| `namespaceOverride`                       | Override the deployment namespace             | `""` (`Release.Namespace`)                              |
+| `serviceMonitor.enabled`                  | Use servicemonitor from prometheus operator   | `false`                                                 |
+| `serviceMonitor.namespace`                | Namespace this servicemonitor is installed in |                                                         |
+| `serviceMonitor.interval`                 | How frequently Prometheus should scrape       | `1m`                                                    |
+| `serviceMonitor.path`                     | Path to scrape                                | `/metrics`                                              |
+| `serviceMonitor.labels`                   | Labels for the servicemonitor passed to Prometheus Operator      |  `{}`                                |
+| `serviceMonitor.scrapeTimeout`            | Timeout after which the scrape is ended       | `30s`                                                   |
+| `serviceMonitor.relabelings`              | MetricRelabelConfigs to apply to samples before ingestion.  | `[]`                                      |
+| `revisionHistoryLimit`                    | Number of old ReplicaSets to retain           | `10`                                                    |
+| `imageRenderer.enabled`                    | Enable the image-renderer deployment & service                                     | `false`                          |
+| `imageRenderer.image.repository`           | image-renderer Image repository                                                    | `grafana/grafana-image-renderer` |
+| `imageRenderer.image.tag`                  | image-renderer Image tag                                                           | `latest`                         |
+| `imageRenderer.image.sha`                  | image-renderer Image sha (optional)                                                | `""`                             |
+| `imageRenderer.image.pullPolicy`           | image-renderer ImagePullPolicy                                                     | `Always`                         |
+| `imageRenderer.env`                        | extra env-vars for image-renderer                                                  | `{}`                             |
+| `imageRenderer.securityContext`            | image-renderer deployment securityContext                                          | `{}`                             |
+| `imageRenderer.hostAliases`                | image-renderer deployment Host Aliases                                             | `[]`                             |
+| `imageRenderer.priorityClassName`          | image-renderer deployment priority class                                           | `''`                             |
+| `imageRenderer.service.portName`           | image-renderer service port name                                                   | `'http'`                         |
+| `imageRenderer.service.port`               | image-renderer service port used by both service and deployment                    | `8081`                           |
+| `imageRenderer.podPortName`                | name of the image-renderer port on the pod                                         | `http`                           |
+| `imageRenderer.revisionHistoryLimit`       | number of image-renderer replica sets to keep                                      | `10`                             |
+| `imageRenderer.networkPolicy.limitIngress` | Enable a NetworkPolicy to limit inbound traffic from only the created grafana pods  | `true`                           |
+| `imageRenderer.networkPolicy.limitEgress`  | Enable a NetworkPolicy to limit outbound traffic to only the created grafana pods   | `false`                          |
+| `imageRenderer.resources`                  | Set resource limits for image-renderer pdos                                        | `{}`                             |
+
+### Example ingress with path
+
+With grafana 6.3 and above
+```yaml
+grafana.ini:
+  server:
+    domain: monitoring.example.com
+    root_url: "%(protocol)s://%(domain)s/grafana"
+    serve_from_sub_path: true
+ingress:
+  enabled: true
+  hosts:
+    - "monitoring.example.com"
+  path: "/grafana"
+```
+
+### Example of extraVolumeMounts
+
+```yaml
+- extraVolumeMounts:
+  - name: plugins
+    mountPath: /var/lib/grafana/plugins
+    subPath: configs/grafana/plugins
+    existingClaim: existing-grafana-claim
+    readOnly: false
+```
+
+## Import dashboards
+
+There are a few methods to import dashboards to Grafana. Below are some examples and explanations as to how to use each method:
+
+```yaml
+dashboards:
+  default:
+    some-dashboard:
+      json: |
+        {
+          "annotations":
+
+          ...
+          # Complete json file here
+          ...
+
+          "title": "Some Dashboard",
+          "uid": "abcd1234",
+          "version": 1
+        }
+    custom-dashboard:
+      # This is a path to a file inside the dashboards directory inside the chart directory
+      file: dashboards/custom-dashboard.json
+    prometheus-stats:
+      # Ref: https://grafana.com/dashboards/2
+      gnetId: 2
+      revision: 2
+      datasource: Prometheus
+    local-dashboard:
+      url: https://raw.githubusercontent.com/user/repository/master/dashboards/dashboard.json
+```
+
+## BASE64 dashboards
+
+Dashboards could be stored on a server that does not return JSON directly and instead of it returns a Base64 encoded file (e.g. Gerrit)
+A new parameter has been added to the url use case so if you specify a b64content value equals to true after the url entry a Base64 decoding is applied before save the file to disk.
+If this entry is not set or is equals to false not decoding is applied to the file before saving it to disk.
+
+### Gerrit use case
+
+Gerrit API for download files has the following schema: <https://yourgerritserver/a/{project-name}/branches/{branch-id}/files/{file-id}/content> where {project-name} and
+{file-id} usually has '/' in their values and so they MUST be replaced by %2F so if project-name is user/repo, branch-id is master and file-id is equals to dir1/dir2/dashboard
+the url value is <https://yourgerritserver/a/user%2Frepo/branches/master/files/dir1%2Fdir2%2Fdashboard/content>
+
+## Sidecar for dashboards
+
+If the parameter `sidecar.dashboards.enabled` is set, a sidecar container is deployed in the grafana
+pod. This container watches all configmaps (or secrets) in the cluster and filters out the ones with
+a label as defined in `sidecar.dashboards.label`. The files defined in those configmaps are written
+to a folder and accessed by grafana. Changes to the configmaps are monitored and the imported
+dashboards are deleted/updated.
+
+A recommendation is to use one configmap per dashboard, as a reduction of multiple dashboards inside
+one configmap is currently not properly mirrored in grafana.
+
+Example dashboard config:
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: sample-grafana-dashboard
+  labels:
+     grafana_dashboard: "1"
+data:
+  k8s-dashboard.json: |-
+  [...]
+```
+
+## Sidecar for datasources
+
+If the parameter `sidecar.datasources.enabled` is set, an init container is deployed in the grafana
+pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and
+filters out the ones with a label as defined in `sidecar.datasources.label`. The files defined in
+those secrets are written to a folder and accessed by grafana on startup. Using these yaml files,
+the data sources in grafana can be imported. The secrets must be created before `helm install` so
+that the datasources init container can list the secrets.
+
+Secrets are recommended over configmaps for this usecase because datasources usually contain private
+data like usernames and passwords. Secrets are the more appropriate cluster resource to manage those.
+
+Example datasource config adapted from [Grafana](http://docs.grafana.org/administration/provisioning/#example-datasource-config-file):
+
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+  name: sample-grafana-datasource
+  labels:
+     grafana_datasource: "1"
+type: Opaque
+stringData:
+  datasource.yaml: |-
+    # config file version
+    apiVersion: 1
+
+    # list of datasources that should be deleted from the database
+    deleteDatasources:
+      - name: Graphite
+        orgId: 1
+
+    # list of datasources to insert/update depending
+    # whats available in the database
+    datasources:
+      # <string, required> name of the datasource. Required
+    - name: Graphite
+      # <string, required> datasource type. Required
+      type: graphite
+      # <string, required> access mode. proxy or direct (Server or Browser in the UI). Required
+      access: proxy
+      # <int> org id. will default to orgId 1 if not specified
+      orgId: 1
+      # <string> url
+      url: http://localhost:8080
+      # <string> database password, if used
+      password:
+      # <string> database user, if used
+      user:
+      # <string> database name, if used
+      database:
+      # <bool> enable/disable basic auth
+      basicAuth:
+      # <string> basic auth username
+      basicAuthUser:
+      # <string> basic auth password
+      basicAuthPassword:
+      # <bool> enable/disable with credentials headers
+      withCredentials:
+      # <bool> mark as default datasource. Max one per org
+      isDefault:
+      # <map> fields that will be converted to json and stored in json_data
+      jsonData:
+         graphiteVersion: "1.1"
+         tlsAuth: true
+         tlsAuthWithCACert: true
+      # <string> json object of data that will be encrypted.
+      secureJsonData:
+        tlsCACert: "..."
+        tlsClientCert: "..."
+        tlsClientKey: "..."
+      version: 1
+      # <bool> allow users to edit datasources from the UI.
+      editable: false
+
+```
+
+## Sidecar for notifiers
+
+If the parameter `sidecar.notifiers.enabled` is set, an init container is deployed in the grafana
+pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and
+filters out the ones with a label as defined in `sidecar.notifiers.label`. The files defined in
+those secrets are written to a folder and accessed by grafana on startup. Using these yaml files,
+the notification channels in grafana can be imported. The secrets must be created before
+`helm install` so that the notifiers init container can list the secrets.
+
+Secrets are recommended over configmaps for this usecase because alert notification channels usually contain
+private data like SMTP usernames and passwords. Secrets are the more appropriate cluster resource to manage those.
+
+Example datasource config adapted from [Grafana](https://grafana.com/docs/grafana/latest/administration/provisioning/#alert-notification-channels):
+
+```yaml
+notifiers:
+  - name: notification-channel-1
+    type: slack
+    uid: notifier1
+    # either
+    org_id: 2
+    # or
+    org_name: Main Org.
+    is_default: true
+    send_reminder: true
+    frequency: 1h
+    disable_resolve_message: false
+    # See `Supported Settings` section for settings supporter for each
+    # alert notification type.
+    settings:
+      recipient: 'XXX'
+      token: 'xoxb'
+      uploadImage: true
+      url: https://slack.com
+
+delete_notifiers:
+  - name: notification-channel-1
+    uid: notifier1
+    org_id: 2
+  - name: notification-channel-2
+    # default org_id: 1
+```
+
+## How to serve Grafana with a path prefix (/grafana)
+
+In order to serve Grafana with a prefix (e.g., <http://example.com/grafana>), add the following to your values.yaml.
+
+```yaml
+ingress:
+  enabled: true
+  annotations:
+    kubernetes.io/ingress.class: "nginx"
+    nginx.ingress.kubernetes.io/rewrite-target: /$1
+    nginx.ingress.kubernetes.io/use-regex: "true"
+
+  path: /grafana/?(.*)
+  hosts:
+    - k8s.example.dev
+
+grafana.ini:
+  server:
+    root_url: http://localhost:3000/grafana # this host can be localhost
+```
+
+## How to securely reference secrets in grafana.ini
+
+This example uses Grafana uses [file providers](https://grafana.com/docs/grafana/latest/administration/configuration/#file-provider) for secret values and the `extraSecretMounts` configuration flag (Additional grafana server secret mounts) to mount the secrets.
+
+In grafana.ini:
+
+```yaml
+grafana.ini:
+  [auth.generic_oauth]
+  enabled = true
+  client_id = $__file{/etc/secrets/auth_generic_oauth/client_id}
+  client_secret = $__file{/etc/secrets/auth_generic_oauth/client_secret}
+```
+
+Existing secret, or created along with helm:
+
+```yaml
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: auth-generic-oauth-secret
+type: Opaque
+stringData:
+  client_id: <value>
+  client_secret: <value>
+```
+
+Include in the `extraSecretMounts` configuration flag:
+
+```yaml
+- extraSecretMounts:
+  - name: auth-generic-oauth-secret-mount
+     secretName: auth-generic-oauth-secret
+     defaultMode: 0440
+     mountPath: /etc/secrets/auth_generic_oauth
+     readOnly: true
+```
+
+## Image Renderer Plug-In
+
+This chart supports enabling [remote image rendering](https://github.com/grafana/grafana-image-renderer/blob/master/docs/remote_rendering_using_docker.md)
+
+```yaml
+imageRenderer:
+  enabled: true
+```
+
+### Image Renderer NetworkPolicy
+
+By default the image-renderer pods will have a network policy which only allows ingress traffic from the created grafana instance

+ 1 - 0
loki/loki-stack/charts/grafana/ci/default-values.yaml

@@ -0,0 +1 @@
+# Leave this file empty to ensure that CI runs builds against the default configuration in values.yaml.

+ 53 - 0
loki/loki-stack/charts/grafana/ci/with-dashboard-json-values.yaml

@@ -0,0 +1,53 @@
+dashboards:
+  my-provider:
+    my-awesome-dashboard:
+      # An empty but valid dashboard
+      json: |
+        {
+          "__inputs": [],
+          "__requires": [
+            {
+              "type": "grafana",
+              "id": "grafana",
+              "name": "Grafana",
+              "version": "6.3.5"
+            }
+          ],
+          "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,
+          "id": null,
+          "links": [],
+          "panels": [],
+          "schemaVersion": 19,
+          "style": "dark",
+          "tags": [],
+          "templating": {
+            "list": []
+          },
+          "time": {
+            "from": "now-6h",
+            "to": "now"
+          },
+          "timepicker": {
+            "refresh_intervals": ["5s"]
+          },
+          "timezone": "",
+          "title": "Dummy Dashboard",
+          "uid": "IdcYQooWk",
+          "version": 1
+        }
+      datasource: Prometheus

+ 19 - 0
loki/loki-stack/charts/grafana/ci/with-dashboard-values.yaml

@@ -0,0 +1,19 @@
+dashboards:
+  my-provider:
+    my-awesome-dashboard:
+      gnetId: 10000
+      revision: 1
+      datasource: Prometheus
+dashboardProviders:
+  dashboardproviders.yaml:
+    apiVersion: 1
+    providers:
+    - name: 'my-provider'
+      orgId: 1
+      folder: ''
+      type: file
+      updateIntervalSeconds: 10
+      disableDeletion: true
+      editable: true
+      options:
+        path: /var/lib/grafana/dashboards/my-provider

+ 19 - 0
loki/loki-stack/charts/grafana/ci/with-image-renderer-values.yaml

@@ -0,0 +1,19 @@
+podLabels:
+  customLableA: Aaaaa
+imageRenderer:
+  enabled: true
+  env:
+    RENDERING_ARGS: --disable-gpu,--window-size=1280x758
+    RENDERING_MODE: clustered
+  podLabels:
+    customLableB: Bbbbb
+  networkPolicy:
+    limitIngress: true
+    limitEgress: true
+  resources:
+    limits:
+      cpu: 1000m
+      memory: 1000Mi
+    requests:
+      cpu: 500m
+      memory: 50Mi

+ 1 - 0
loki/loki-stack/charts/grafana/dashboards/custom-dashboard.json

@@ -0,0 +1 @@
+{}

+ 54 - 0
loki/loki-stack/charts/grafana/templates/NOTES.txt

@@ -0,0 +1,54 @@
+1. Get your '{{ .Values.adminUser }}' user password by running:
+
+   kubectl get secret --namespace {{ template "grafana.namespace" . }} {{ template "grafana.fullname" . }} -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
+
+2. The Grafana server can be accessed via port {{ .Values.service.port }} on the following DNS name from within your cluster:
+
+   {{ template "grafana.fullname" . }}.{{ template "grafana.namespace" . }}.svc.cluster.local
+{{ if .Values.ingress.enabled }}
+   If you bind grafana to 80, please update values in values.yaml and reinstall:
+   ```
+   securityContext:
+     runAsUser: 0
+     runAsGroup: 0
+     fsGroup: 0
+
+   command:
+   - "setcap"
+   - "'cap_net_bind_service=+ep'"
+   - "/usr/sbin/grafana-server &&"
+   - "sh"
+   - "/run.sh"
+   ```
+   Details refer to https://grafana.com/docs/installation/configuration/#http-port.
+   Or grafana would always crash.
+
+   From outside the cluster, the server URL(s) are:
+{{- range .Values.ingress.hosts }}
+     http://{{ . }}
+{{- end }}
+{{ else }}
+   Get the Grafana URL to visit by running these commands in the same shell:
+{{ if contains "NodePort" .Values.service.type -}}
+     export NODE_PORT=$(kubectl get --namespace {{ template "grafana.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "grafana.fullname" . }})
+     export NODE_IP=$(kubectl get nodes --namespace {{ template "grafana.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
+     echo http://$NODE_IP:$NODE_PORT
+{{ else if contains "LoadBalancer" .Values.service.type -}}
+   NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+        You can watch the status of by running 'kubectl get svc --namespace {{ template "grafana.namespace" . }} -w {{ template "grafana.fullname" . }}'
+     export SERVICE_IP=$(kubectl get svc --namespace {{ template "grafana.namespace" . }} {{ template "grafana.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+     http://$SERVICE_IP:{{ .Values.service.port -}}
+{{ else if contains "ClusterIP"  .Values.service.type }}
+     export POD_NAME=$(kubectl get pods --namespace {{ template "grafana.namespace" . }} -l "app.kubernetes.io/name={{ template "grafana.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+     kubectl --namespace {{ template "grafana.namespace" . }} port-forward $POD_NAME 3000
+{{- end }}
+{{- end }}
+
+3. Login with the password from step 1 and the username: {{ .Values.adminUser }}
+
+{{- if not .Values.persistence.enabled }}
+#################################################################################
+######   WARNING: Persistence is disabled!!! You will lose your data when   #####
+######            the Grafana pod is terminated.                            #####
+#################################################################################
+{{- end }}

+ 102 - 0
loki/loki-stack/charts/grafana/templates/_helpers.tpl

@@ -0,0 +1,102 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "grafana.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 "grafana.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 "grafana.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create the name of the service account
+*/}}
+{{- define "grafana.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (include "grafana.fullname" .) .Values.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{- define "grafana.serviceAccountNameTest" -}}
+{{- if .Values.serviceAccount.create -}}
+    {{ default (print (include "grafana.fullname" .) "-test") .Values.serviceAccount.nameTest }}
+{{- else -}}
+    {{ default "default" .Values.serviceAccount.nameTest }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Allow the release namespace to be overridden for multi-namespace deployments in combined charts
+*/}}
+{{- define "grafana.namespace" -}}
+  {{- if .Values.namespaceOverride -}}
+    {{- .Values.namespaceOverride -}}
+  {{- else -}}
+    {{- .Release.Namespace -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "grafana.labels" -}}
+helm.sh/chart: {{ include "grafana.chart" . }}
+{{ include "grafana.selectorLabels" . }}
+{{- if or .Chart.AppVersion .Values.image.tag }}
+app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels
+*/}}
+{{- define "grafana.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "grafana.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "grafana.imageRenderer.labels" -}}
+helm.sh/chart: {{ include "grafana.chart" . }}
+{{ include "grafana.imageRenderer.selectorLabels" . }}
+{{- if or .Chart.AppVersion .Values.image.tag }}
+app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Selector labels ImageRenderer
+*/}}
+{{- define "grafana.imageRenderer.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "grafana.name" . }}-image-renderer
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}

+ 459 - 0
loki/loki-stack/charts/grafana/templates/_pod.tpl

@@ -0,0 +1,459 @@
+
+{{- define "grafana.pod" -}}
+{{- if .Values.schedulerName }}
+schedulerName: "{{ .Values.schedulerName }}"
+{{- end }}
+serviceAccountName: {{ template "grafana.serviceAccountName" . }}
+{{- if .Values.securityContext }}
+securityContext:
+{{ toYaml .Values.securityContext | indent 2 }}
+{{- end }}
+{{- if .Values.hostAliases }}
+hostAliases:
+{{ toYaml .Values.hostAliases | indent 2 }}
+{{- end }}
+{{- if .Values.priorityClassName }}
+priorityClassName: {{ .Values.priorityClassName }}
+{{- end }}
+{{- if ( or .Values.persistence.enabled .Values.dashboards .Values.sidecar.datasources.enabled .Values.sidecar.notifiers.enabled .Values.extraInitContainers) }}
+initContainers:
+{{- end }}
+{{- if ( and .Values.persistence.enabled .Values.initChownData.enabled ) }}
+  - name: init-chown-data
+    {{- if .Values.initChownData.image.sha }}
+    image: "{{ .Values.initChownData.image.repository }}:{{ .Values.initChownData.image.tag }}@sha256:{{ .Values.initChownData.image.sha }}"
+    {{- else }}
+    image: "{{ .Values.initChownData.image.repository }}:{{ .Values.initChownData.image.tag }}"
+    {{- end }}
+    imagePullPolicy: {{ .Values.initChownData.image.pullPolicy }}
+    securityContext:
+      runAsUser: 0
+    command: ["chown", "-R", "{{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.runAsGroup }}", "/var/lib/grafana"]
+    resources:
+{{ toYaml .Values.initChownData.resources | indent 6 }}
+    volumeMounts:
+      - name: storage
+        mountPath: "/var/lib/grafana"
+{{- if .Values.persistence.subPath }}
+        subPath: {{ .Values.persistence.subPath }}
+{{- end }}
+{{- end }}
+{{- if .Values.dashboards }}
+  - name: download-dashboards
+    {{- if .Values.downloadDashboardsImage.sha }}
+    image: "{{ .Values.downloadDashboardsImage.repository }}:{{ .Values.downloadDashboardsImage.tag }}@sha256:{{ .Values.downloadDashboardsImage.sha }}"
+    {{- else }}
+    image: "{{ .Values.downloadDashboardsImage.repository }}:{{ .Values.downloadDashboardsImage.tag }}"
+    {{- end }}
+    imagePullPolicy: {{ .Values.downloadDashboardsImage.pullPolicy }}
+    command: ["/bin/sh"]
+    args: [ "-c", "mkdir -p /var/lib/grafana/dashboards/default && /bin/sh /etc/grafana/download_dashboards.sh" ]
+    resources:
+{{ toYaml .Values.downloadDashboards.resources | indent 6 }}
+    env:
+{{- range $key, $value := .Values.downloadDashboards.env }}
+      - name: "{{ $key }}"
+        value: "{{ $value }}"
+{{- end }}
+    volumeMounts:
+      - name: config
+        mountPath: "/etc/grafana/download_dashboards.sh"
+        subPath: download_dashboards.sh
+      - name: storage
+        mountPath: "/var/lib/grafana"
+{{- if .Values.persistence.subPath }}
+        subPath: {{ .Values.persistence.subPath }}
+{{- end }}
+    {{- range .Values.extraSecretMounts }}
+      - name: {{ .name }}
+        mountPath: {{ .mountPath }}
+        readOnly: {{ .readOnly }}
+    {{- end }}
+{{- end }}
+{{- if .Values.sidecar.datasources.enabled }}
+  - name: {{ template "grafana.name" . }}-sc-datasources
+    {{- if .Values.sidecar.image.sha }}
+    image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+    {{- else }}
+    image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+    {{- end }}
+    imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+    env:
+      - name: METHOD
+        value: LIST
+      - name: LABEL
+        value: "{{ .Values.sidecar.datasources.label }}"
+      - name: FOLDER
+        value: "/etc/grafana/provisioning/datasources"
+      - name: RESOURCE
+        value: "both"
+      {{- if .Values.sidecar.enableUniqueFilenames }}
+      - name: UNIQUE_FILENAMES
+        value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+      {{- end }}
+      {{- if .Values.sidecar.datasources.searchNamespace }}
+      - name: NAMESPACE
+        value: "{{ .Values.sidecar.datasources.searchNamespace }}"
+      {{- end }}
+      {{- if .Values.sidecar.skipTlsVerify }}
+      - name: SKIP_TLS_VERIFY
+        value: "{{ .Values.sidecar.skipTlsVerify }}"
+      {{- end }}
+    resources:
+{{ toYaml .Values.sidecar.resources | indent 6 }}
+    volumeMounts:
+      - name: sc-datasources-volume
+        mountPath: "/etc/grafana/provisioning/datasources"
+{{- end}}
+{{- if .Values.sidecar.notifiers.enabled }}
+  - name: {{ template "grafana.name" . }}-sc-notifiers
+    {{- if .Values.sidecar.image.sha }}
+    image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+    {{- else }}
+    image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+    {{- end }}
+    imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+    env:
+      - name: METHOD
+        value: LIST
+      - name: LABEL
+        value: "{{ .Values.sidecar.notifiers.label }}"
+      - name: FOLDER
+        value: "/etc/grafana/provisioning/notifiers"
+      - name: RESOURCE
+        value: "both"
+      {{- if .Values.sidecar.enableUniqueFilenames }}
+      - name: UNIQUE_FILENAMES
+        value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+      {{- end }}
+      {{- if .Values.sidecar.notifiers.searchNamespace }}
+      - name: NAMESPACE
+        value: "{{ .Values.sidecar.notifiers.searchNamespace }}"
+      {{- end }}
+      {{- if .Values.sidecar.skipTlsVerify }}
+      - name: SKIP_TLS_VERIFY
+        value: "{{ .Values.sidecar.skipTlsVerify }}"
+      {{- end }}
+    resources:
+{{ toYaml .Values.sidecar.resources | indent 6 }}
+    volumeMounts:
+      - name: sc-notifiers-volume
+        mountPath: "/etc/grafana/provisioning/notifiers"
+{{- end}}
+{{- if .Values.extraInitContainers }}
+{{ toYaml .Values.extraInitContainers | indent 2 }}
+{{- end }}
+{{- if .Values.image.pullSecrets }}
+imagePullSecrets:
+{{- range .Values.image.pullSecrets }}
+  - name: {{ . }}
+{{- end}}
+{{- end }}
+containers:
+{{- if .Values.sidecar.dashboards.enabled }}
+  - name: {{ template "grafana.name" . }}-sc-dashboard
+    {{- if .Values.sidecar.image.sha }}
+    image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}"
+    {{- else }}
+    image: "{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}"
+    {{- end }}
+    imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }}
+    env:
+      - name: METHOD
+        value: {{ .Values.sidecar.dashboards.watchMethod }}
+      - name: LABEL
+        value: "{{ .Values.sidecar.dashboards.label }}"
+      - name: FOLDER
+        value: "{{ .Values.sidecar.dashboards.folder }}{{- with .Values.sidecar.dashboards.defaultFolderName }}/{{ . }}{{- end }}"
+      - name: RESOURCE
+        value: "both"
+      {{- if .Values.sidecar.enableUniqueFilenames }}
+      - name: UNIQUE_FILENAMES
+        value: "{{ .Values.sidecar.enableUniqueFilenames }}"
+      {{- end }}
+      {{- if .Values.sidecar.dashboards.searchNamespace }}
+      - name: NAMESPACE
+        value: "{{ .Values.sidecar.dashboards.searchNamespace }}"
+      {{- end }}
+      {{- if .Values.sidecar.skipTlsVerify }}
+      - name: SKIP_TLS_VERIFY
+        value: "{{ .Values.sidecar.skipTlsVerify }}"
+      {{- end }}
+    resources:
+{{ toYaml .Values.sidecar.resources | indent 6 }}
+    volumeMounts:
+      - name: sc-dashboard-volume
+        mountPath: {{ .Values.sidecar.dashboards.folder | quote }}
+{{- end}}
+  - name: {{ .Chart.Name }}
+    {{- if .Values.image.sha }}
+    image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}@sha256:{{ .Values.image.sha }}"
+    {{- else }}
+    image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+    {{- end }}
+    imagePullPolicy: {{ .Values.image.pullPolicy }}
+  {{- if .Values.command }}
+    command:
+    {{- range .Values.command }}
+      - {{ . }}
+    {{- end }}
+  {{- end}}
+    volumeMounts:
+      - name: config
+        mountPath: "/etc/grafana/grafana.ini"
+        subPath: grafana.ini
+      {{- if .Values.ldap.enabled }}
+      - name: ldap
+        mountPath: "/etc/grafana/ldap.toml"
+        subPath: ldap.toml
+      {{- end }}
+      {{- range .Values.extraConfigmapMounts }}
+      - name: {{ .name }}
+        mountPath: {{ .mountPath }}
+        subPath: {{ .subPath | default "" }}
+        readOnly: {{ .readOnly }}
+      {{- end }}
+      - name: storage
+        mountPath: "/var/lib/grafana"
+{{- if .Values.persistence.subPath }}
+        subPath: {{ .Values.persistence.subPath }}
+{{- end }}
+{{- if .Values.dashboards }}
+{{- range $provider, $dashboards := .Values.dashboards }}
+{{- range $key, $value := $dashboards }}
+{{- if (or (hasKey $value "json") (hasKey $value "file")) }}
+      - name: dashboards-{{ $provider }}
+        mountPath: "/var/lib/grafana/dashboards/{{ $provider }}/{{ $key }}.json"
+        subPath: "{{ $key }}.json"
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end -}}
+{{- if .Values.dashboardsConfigMaps }}
+{{- range (keys .Values.dashboardsConfigMaps | sortAlpha) }}
+      - name: dashboards-{{ . }}
+        mountPath: "/var/lib/grafana/dashboards/{{ . }}"
+{{- end }}
+{{- end }}
+{{- if .Values.datasources }}
+      - name: config
+        mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml"
+        subPath: datasources.yaml
+{{- end }}
+{{- if .Values.notifiers }}
+      - name: config
+        mountPath: "/etc/grafana/provisioning/notifiers/notifiers.yaml"
+        subPath: notifiers.yaml
+{{- end }}
+{{- if .Values.dashboardProviders }}
+      - name: config
+        mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml"
+        subPath: dashboardproviders.yaml
+{{- end }}
+{{- if .Values.sidecar.dashboards.enabled }}
+      - name: sc-dashboard-volume
+        mountPath: {{ .Values.sidecar.dashboards.folder | quote }}
+{{ if .Values.sidecar.dashboards.SCProvider }}
+      - name: sc-dashboard-provider
+        mountPath: "/etc/grafana/provisioning/dashboards/sc-dashboardproviders.yaml"
+        subPath: provider.yaml
+{{- end}}
+{{- end}}
+{{- if .Values.sidecar.datasources.enabled }}
+      - name: sc-datasources-volume
+        mountPath: "/etc/grafana/provisioning/datasources"
+{{- end}}
+{{- if .Values.sidecar.notifiers.enabled }}
+      - name: sc-notifiers-volume
+        mountPath: "/etc/grafana/provisioning/notifiers"
+{{- end}}
+    {{- range .Values.extraSecretMounts }}
+      - name: {{ .name }}
+        mountPath: {{ .mountPath }}
+        readOnly: {{ .readOnly }}
+        subPath: {{ .subPath | default "" }}
+    {{- end }}
+    {{- range .Values.extraVolumeMounts }}
+      - name: {{ .name }}
+        mountPath: {{ .mountPath }}
+        subPath: {{ .subPath | default "" }}
+        readOnly: {{ .readOnly }}
+    {{- end }}
+    {{- range .Values.extraEmptyDirMounts }}
+      - name: {{ .name }}
+        mountPath: {{ .mountPath }}
+    {{- end }}
+    ports:
+      - name: {{ .Values.service.portName }}
+        containerPort: {{ .Values.service.port }}
+        protocol: TCP
+      - name: {{ .Values.podPortName }}
+        containerPort: 3000
+        protocol: TCP
+    env:
+      {{- if not .Values.env.GF_SECURITY_ADMIN_USER }}
+      - name: GF_SECURITY_ADMIN_USER
+        valueFrom:
+          secretKeyRef:
+            name: {{ .Values.admin.existingSecret | default (include "grafana.fullname" .) }}
+            key: {{ .Values.admin.userKey | default "admin-user" }}
+      {{- end }}
+      {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) }}
+      - name: GF_SECURITY_ADMIN_PASSWORD
+        valueFrom:
+          secretKeyRef:
+            name: {{ .Values.admin.existingSecret | default (include "grafana.fullname" .) }}
+            key: {{ .Values.admin.passwordKey | default "admin-password" }}
+      {{- end }}
+      {{- if .Values.plugins }}
+      - name: GF_INSTALL_PLUGINS
+        valueFrom:
+          configMapKeyRef:
+            name: {{ template "grafana.fullname" . }}
+            key: plugins
+      {{- end }}
+      {{- if .Values.smtp.existingSecret }}
+      - name: GF_SMTP_USER
+        valueFrom:
+          secretKeyRef:
+            name: {{ .Values.smtp.existingSecret }}
+            key: {{ .Values.smtp.userKey | default "user" }}
+      - name: GF_SMTP_PASSWORD
+        valueFrom:
+          secretKeyRef:
+            name: {{ .Values.smtp.existingSecret }}
+            key: {{ .Values.smtp.passwordKey | default "password" }}
+      {{- end }}
+      {{ if .Values.imageRenderer.enabled }}
+      - name: GF_RENDERING_SERVER_URL
+        value: http://{{ template "grafana.fullname" . }}-image-renderer.{{ template "grafana.namespace" . }}:{{ .Values.imageRenderer.service.port }}/render
+      - name: GF_RENDERING_CALLBACK_URL
+        value: http://{{ template "grafana.fullname" . }}.{{ template "grafana.namespace" . }}:{{ .Values.service.port }}/
+      {{ end }}
+    {{- range $key, $value := .Values.envValueFrom }}
+      - name: {{ $key | quote }}
+        valueFrom:
+{{ toYaml $value | indent 10 }}
+    {{- end }}
+{{- range $key, $value := .Values.env }}
+      - name: "{{ tpl $key $ }}"
+        value: "{{ tpl (print $value) $ }}"
+{{- end }}
+    {{- if .Values.envFromSecret }}
+    envFrom:
+      - secretRef:
+          name: {{ tpl .Values.envFromSecret . }}
+    {{- end }}
+    {{- if .Values.envRenderSecret }}
+    envFrom:
+      - secretRef:
+          name: {{ template "grafana.fullname" . }}-env
+    {{- end }}
+    livenessProbe:
+{{ toYaml .Values.livenessProbe | indent 6 }}
+    readinessProbe:
+{{ toYaml .Values.readinessProbe | indent 6 }}
+    resources:
+{{ toYaml .Values.resources | indent 6 }}
+{{- with .Values.extraContainers }}
+{{ tpl . $ | indent 2 }}
+{{- end }}
+{{- with .Values.nodeSelector }}
+nodeSelector:
+{{ toYaml . | indent 2 }}
+{{- end }}
+{{- with .Values.affinity }}
+affinity:
+{{ toYaml . | indent 2 }}
+{{- end }}
+{{- with .Values.tolerations }}
+tolerations:
+{{ toYaml . | indent 2 }}
+{{- end }}
+volumes:
+  - name: config
+    configMap:
+      name: {{ template "grafana.fullname" . }}
+{{- range .Values.extraConfigmapMounts }}
+  - name: {{ .name }}
+    configMap:
+      name: {{ .configMap }}
+{{- end }}
+  {{- if .Values.dashboards }}
+    {{- range (keys .Values.dashboards | sortAlpha) }}
+  - name: dashboards-{{ . }}
+    configMap:
+      name: {{ template "grafana.fullname" $ }}-dashboards-{{ . }}
+    {{- end }}
+  {{- end }}
+  {{- if .Values.dashboardsConfigMaps }}
+    {{ $root := . }}
+    {{- range $provider, $name := .Values.dashboardsConfigMaps }}
+  - name: dashboards-{{ $provider }}
+    configMap:
+      name: {{ tpl $name $root }}
+    {{- end }}
+  {{- end }}
+  {{- if .Values.ldap.enabled }}
+  - name: ldap
+    secret:
+      {{- if .Values.ldap.existingSecret }}
+      secretName: {{ .Values.ldap.existingSecret }}
+      {{- else }}
+      secretName: {{ template "grafana.fullname" . }}
+      {{- end }}
+      items:
+        - key: ldap-toml
+          path: ldap.toml
+  {{- end }}
+{{- if and .Values.persistence.enabled (eq .Values.persistence.type "pvc") }}
+  - name: storage
+    persistentVolumeClaim:
+      claimName: {{ .Values.persistence.existingClaim | default (include "grafana.fullname" .) }}
+{{- else if and .Values.persistence.enabled (eq .Values.persistence.type "statefulset") }}
+# nothing
+{{- else }}
+  - name: storage
+    emptyDir: {}
+{{- end -}}
+{{- if .Values.sidecar.dashboards.enabled }}
+  - name: sc-dashboard-volume
+    emptyDir: {}
+{{- if .Values.sidecar.dashboards.SCProvider }}
+  - name: sc-dashboard-provider
+    configMap:
+      name: {{ template "grafana.fullname" . }}-config-dashboards
+{{- end }}
+{{- end }}
+{{- if .Values.sidecar.datasources.enabled }}
+  - name: sc-datasources-volume
+    emptyDir: {}
+{{- end -}}
+{{- if .Values.sidecar.notifiers.enabled }}
+  - name: sc-notifiers-volume
+    emptyDir: {}
+{{- end -}}
+{{- range .Values.extraSecretMounts }}
+{{- if .secretName }}
+  - name: {{ .name }}
+    secret:
+      secretName: {{ .secretName }}
+      defaultMode: {{ .defaultMode }}
+{{- else if .projected }}
+  - name: {{ .name }}
+    projected: {{- toYaml .projected | nindent 6 }}
+{{- end }}
+{{- end }}
+{{- range .Values.extraVolumeMounts }}
+  - name: {{ .name }}
+    persistentVolumeClaim:
+      claimName: {{ .existingClaim }}
+{{- end }}
+{{- range .Values.extraEmptyDirMounts }}
+  - name: {{ .name }}
+    emptyDir: {}
+{{- end -}}
+{{- if .Values.extraContainerVolumes }}
+{{ toYaml .Values.extraContainerVolumes | indent 2 }}
+{{- end }}
+{{- end }}

+ 25 - 0
loki/loki-stack/charts/grafana/templates/clusterrole.yaml

@@ -0,0 +1,25 @@
+{{- if and .Values.rbac.create (not .Values.rbac.namespaced) }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+  name: {{ template "grafana.fullname" . }}-clusterrole
+{{- if or .Values.sidecar.dashboards.enabled (or .Values.sidecar.datasources.enabled .Values.rbac.extraClusterRoleRules) }}
+rules:
+{{- if or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled }}
+- apiGroups: [""] # "" indicates the core API group
+  resources: ["configmaps", "secrets"]
+  verbs: ["get", "watch", "list"]
+{{- end}}
+{{- with .Values.rbac.extraClusterRoleRules }}
+{{ toYaml . | indent 0 }}
+{{- end}}
+{{- else }}
+rules: []
+{{- end}}
+{{- end}}

+ 20 - 0
loki/loki-stack/charts/grafana/templates/clusterrolebinding.yaml

@@ -0,0 +1,20 @@
+{{- if and .Values.rbac.create (not .Values.rbac.namespaced) }}
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "grafana.fullname" . }}-clusterrolebinding
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ template "grafana.serviceAccountName" . }}
+    namespace: {{ template "grafana.namespace" . }}
+roleRef:
+  kind: ClusterRole
+  name: {{ template "grafana.fullname" . }}-clusterrole
+  apiGroup: rbac.authorization.k8s.io
+{{- end -}}

+ 26 - 0
loki/loki-stack/charts/grafana/templates/configmap-dashboard-provider.yaml

@@ -0,0 +1,26 @@
+{{- if .Values.sidecar.dashboards.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+  name: {{ template "grafana.fullname" . }}-config-dashboards
+  namespace: {{ template "grafana.namespace" . }}
+data:
+  provider.yaml: |-
+    apiVersion: 1
+    providers:
+    - name: '{{ .Values.sidecar.dashboards.provider.name }}'
+      orgId: {{ .Values.sidecar.dashboards.provider.orgid }}
+      folder: '{{ .Values.sidecar.dashboards.provider.folder }}'
+      type: {{ .Values.sidecar.dashboards.provider.type }}
+      disableDeletion: {{ .Values.sidecar.dashboards.provider.disableDelete }}
+      allowUiUpdates: {{ .Values.sidecar.dashboards.provider.allowUiUpdates }}
+      options:
+        foldersFromFilesStructure: {{ .Values.sidecar.dashboards.provider.foldersFromFilesStructure }}
+        path: {{ .Values.sidecar.dashboards.folder }}{{- with .Values.sidecar.dashboards.defaultFolderName }}/{{ . }}{{- end }}
+{{- end}}

+ 69 - 0
loki/loki-stack/charts/grafana/templates/configmap.yaml

@@ -0,0 +1,69 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+data:
+{{- if .Values.plugins }}
+  plugins: {{ join "," .Values.plugins }}
+{{- end }}
+  grafana.ini: |
+{{- range $key, $value := index .Values "grafana.ini" }}
+    [{{ $key }}]
+    {{- range $elem, $elemVal := $value }}
+    {{ $elem }} = {{ $elemVal }}
+    {{- end }}
+{{- end }}
+
+{{- if .Values.datasources }}
+{{ $root := . }}
+  {{- range $key, $value := .Values.datasources }}
+  {{ $key }}: |
+{{ tpl (toYaml $value | indent 4) $root }}
+  {{- end -}}
+{{- end -}}
+
+{{- if .Values.notifiers }}
+  {{- range $key, $value := .Values.notifiers }}
+  {{ $key }}: |
+{{ toYaml $value | indent 4 }}
+  {{- end -}}
+{{- end -}}
+
+{{- if .Values.dashboardProviders }}
+  {{- range $key, $value := .Values.dashboardProviders }}
+  {{ $key }}: |
+{{ toYaml $value | indent 4 }}
+  {{- end -}}
+{{- end -}}
+
+{{- if .Values.dashboards  }}
+  download_dashboards.sh: |
+    #!/usr/bin/env sh
+    set -euf
+    {{- if .Values.dashboardProviders }}
+      {{- range $key, $value := .Values.dashboardProviders }}
+        {{- range $value.providers }}
+    mkdir -p {{ .options.path }}
+        {{- end }}
+      {{- end }}
+    {{- end }}
+
+  {{- range $provider, $dashboards := .Values.dashboards }}
+    {{- range $key, $value := $dashboards }}
+      {{- if (or (hasKey $value "gnetId") (hasKey $value "url")) }}
+    curl -skf \
+    --connect-timeout 60 \
+    --max-time 60 \
+      {{- if not $value.b64content }}
+    -H "Accept: application/json" \
+    -H "Content-Type: application/json;charset=UTF-8" \
+      {{ end }}
+    {{- if $value.url -}}"{{ $value.url }}"{{- else -}}"https://grafana.com/api/dashboards/{{ $value.gnetId }}/revisions/{{- if $value.revision -}}{{ $value.revision }}{{- else -}}1{{- end -}}/download"{{- end -}}{{ if $value.datasource }} | sed '/-- .* --/! s/"datasource":.*,/"datasource": "{{ $value.datasource }}",/g'{{ end }}{{- if $value.b64content -}} | base64 -d {{- end -}} \
+    > "/var/lib/grafana/dashboards/{{ $provider }}/{{ $key }}.json"
+      {{- end -}}
+    {{- end }}
+  {{- end }}
+{{- end }}

+ 35 - 0
loki/loki-stack/charts/grafana/templates/dashboards-json-configmap.yaml

@@ -0,0 +1,35 @@
+{{- if .Values.dashboards }}
+{{ $files := .Files }}
+{{- range $provider, $dashboards := .Values.dashboards }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ template "grafana.fullname" $ }}-dashboards-{{ $provider }}
+  namespace: {{ template "grafana.namespace" $ }}
+  labels:
+    {{- include "grafana.labels" $ | nindent 4 }}
+    dashboard-provider: {{ $provider }}
+{{- if $dashboards }}
+data:
+{{- $dashboardFound := false }}
+{{- range $key, $value := $dashboards }}
+{{- if (or (hasKey $value "json") (hasKey $value "file")) }}
+{{- $dashboardFound = true }}
+{{ print $key | indent 2 }}.json:
+{{- if hasKey $value "json" }}
+    |-
+{{ $value.json | indent 6 }}
+{{- end }}
+{{- if hasKey $value "file" }}
+{{ toYaml ( $files.Get $value.file ) | indent 4}}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- if not $dashboardFound }}
+  {}
+{{- end }}
+{{- end }}
+---
+{{- end }}
+
+{{- end }}

+ 48 - 0
loki/loki-stack/charts/grafana/templates/deployment.yaml

@@ -0,0 +1,48 @@
+{{ if (or (not .Values.persistence.enabled) (eq .Values.persistence.type "pvc")) }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.labels }}
+{{ toYaml .Values.labels | indent 4 }}
+{{- end }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
+  selector:
+    matchLabels:
+      {{- include "grafana.selectorLabels" . | nindent 6 }}
+{{- with .Values.deploymentStrategy }}
+  strategy:
+{{ toYaml . | trim | indent 4 }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+        {{- include "grafana.selectorLabels" . | nindent 8 }}
+{{- with .Values.podLabels }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+      annotations:
+        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+        checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }}
+        checksum/sc-dashboard-provider-config: {{ include (print $.Template.BasePath "/configmap-dashboard-provider.yaml") . | sha256sum }}
+{{- if or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret)) }}
+        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
+{{- end }}
+{{- if .Values.envRenderSecret }}
+        checksum/secret-env: {{ include (print $.Template.BasePath "/secret-env.yaml") . | sha256sum }}
+{{- end }}
+{{- with .Values.podAnnotations }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+    spec:
+      {{- include "grafana.pod" . | nindent 6 }}
+{{- end }}

+ 18 - 0
loki/loki-stack/charts/grafana/templates/headless-service.yaml

@@ -0,0 +1,18 @@
+{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "statefulset")}}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ template "grafana.fullname" . }}-headless
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+  clusterIP: None
+  selector:
+    {{- include "grafana.selectorLabels" . | nindent 4 }}
+  type: ClusterIP
+{{- end }}

+ 112 - 0
loki/loki-stack/charts/grafana/templates/image-renderer-deployment.yaml

@@ -0,0 +1,112 @@
+{{ if .Values.imageRenderer.enabled }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ template "grafana.fullname" . }}-image-renderer
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.imageRenderer.labels" . | nindent 4 }}
+{{- if .Values.imageRenderer.labels }}
+{{ toYaml .Values.imageRenderer.labels | indent 4 }}
+{{- end }}
+{{- with .Values.imageRenderer.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+  replicas: {{ .Values.imageRenderer.replicas }}
+  revisionHistoryLimit: {{ .Values.imageRenderer.revisionHistoryLimit }}
+  selector:
+    matchLabels:
+      {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
+{{- with .Values.imageRenderer.deploymentStrategy }}
+  strategy:
+{{ toYaml . | trim | indent 4 }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+        {{- include "grafana.imageRenderer.selectorLabels" . | nindent 8 }}
+{{- with .Values.imageRenderer.podLabels }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+      annotations:
+        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+{{- with .Values.imageRenderer.podAnnotations }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+    spec:
+
+      {{- if .Values.imageRenderer.schedulerName }}
+      schedulerName: "{{ .Values.imageRenderer.schedulerName }}"
+      {{- end }}
+      {{- if .Values.imageRenderer.securityContext }}
+      securityContext:
+      {{ toYaml .Values.imageRenderer.securityContext | indent 2 }}
+      {{- end }}
+      {{- if .Values.imageRenderer.hostAliases }}
+      hostAliases:
+      {{ toYaml .Values.imageRenderer.hostAliases | indent 2 }}
+      {{- end }}
+      {{- if .Values.imageRenderer.priorityClassName }}
+      priorityClassName: {{ .Values.imageRenderer.priorityClassName }}
+      {{- end }}
+      {{- if .Values.imageRenderer.image.pullSecrets }}
+      imagePullSecrets:
+      {{- range .Values.imageRenderer.image.pullSecrets }}
+        - name: {{ . }}
+      {{- end}}
+      {{- end }}
+      containers:
+        - name: {{ .Chart.Name }}-image-renderer
+          {{- if .Values.imageRenderer.image.sha }}
+          image: "{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}@sha256:{{ .Values.imageRenderer.image.sha }}"
+          {{- else }}
+          image: "{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}"
+          {{- end }}
+          imagePullPolicy: {{ .Values.imageRenderer.image.pullPolicy }}
+        {{- if .Values.imageRenderer.command }}
+          command:
+          {{- range .Values.imageRenderer.command }}
+            - {{ . }}
+          {{- end }}
+        {{- end}}
+          ports:
+            - name: {{ .Values.imageRenderer.service.portName }}
+              containerPort: {{ .Values.imageRenderer.service.port }}
+              protocol: TCP
+          env:
+            - name: HTTP_PORT
+              value: {{ .Values.imageRenderer.service.port | quote }}
+          {{- range $key, $value := .Values.imageRenderer.env }}
+            - name: {{ $key | quote }}
+              value: {{ $value | quote }}
+          {{- end }}
+          securityContext:
+            capabilities:
+              drop: ['all']
+            allowPrivilegeEscalation: false
+            readOnlyRootFilesystem: true
+          volumeMounts:
+            - mountPath: /tmp
+              name: image-renderer-tmpfs
+      {{- with .Values.imageRenderer.resources }}
+          resources:
+{{ toYaml . | indent 12 }}
+      {{- end }}
+      {{- with .Values.imageRenderer.nodeSelector }}
+      nodeSelector:
+{{ toYaml . | indent 8 }}
+      {{- end }}
+      {{- with .Values.imageRenderer.affinity }}
+      affinity:
+{{ toYaml . | indent 8 }}
+      {{- end }}
+      {{- with .Values.imageRenderer.tolerations }}
+      tolerations:
+{{ toYaml . | indent 8 }}
+      {{- end }}
+      volumes:
+        - name: image-renderer-tmpfs
+          emptyDir: {}
+{{- end }}

+ 76 - 0
loki/loki-stack/charts/grafana/templates/image-renderer-network-policy.yaml

@@ -0,0 +1,76 @@
+{{- if and (.Values.imageRenderer.enabled) (.Values.imageRenderer.networkPolicy.limitIngress) }}
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ template "grafana.fullname" . }}-image-renderer-ingress
+  namespace: {{ template "grafana.namespace" . }}
+  annotations:
+    comment: Limit image-renderer ingress traffic from grafana
+spec:
+  podSelector:
+    matchLabels:
+      {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
+      {{- if .Values.imageRenderer.podLabels }}
+        {{ toYaml .Values.imageRenderer.podLabels | nindent 6 }}
+      {{- end }}
+
+  policyTypes:
+    - Ingress
+  ingress:
+    - ports:
+        - port: {{ .Values.imageRenderer.service.port }}
+          protocol: TCP
+      from:
+        - namespaceSelector:
+            matchLabels:
+              name: {{ template "grafana.namespace" . }}
+          podSelector:
+            matchLabels:
+              {{- include "grafana.selectorLabels" . | nindent 14 }}
+              {{- if .Values.podLabels }}
+                {{ toYaml .Values.podLabels | nindent 14 }}
+              {{- end }}
+{{ end }}
+
+{{- if and (.Values.imageRenderer.enabled) (.Values.imageRenderer.networkPolicy.limitEgress) }}
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ template "grafana.fullname" . }}-image-renderer-egress
+  namespace: {{ template "grafana.namespace" . }}
+  annotations:
+    comment: Limit image-renderer egress traffic to grafana
+spec:
+  podSelector:
+    matchLabels:
+      {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }}
+      {{- if .Values.imageRenderer.podLabels }}
+        {{ toYaml .Values.imageRenderer.podLabels | nindent 6 }}
+      {{- end }}
+
+  policyTypes:
+    - Egress
+  egress:
+    # allow dns resolution
+    - ports:
+        - port: 53
+          protocol: UDP
+        - port: 53
+          protocol: TCP
+    # talk only to grafana
+    - ports:
+        - port: {{ .Values.service.port }}
+          protocol: TCP
+      to:
+        - namespaceSelector:
+            matchLabels:
+              name: {{ template "grafana.namespace" . }}
+          podSelector:
+            matchLabels:
+              {{- include "grafana.selectorLabels" . | nindent 14 }}
+              {{- if .Values.podLabels }}
+                {{ toYaml .Values.podLabels | nindent 14 }}
+              {{- end }}
+{{ end }}

+ 28 - 0
loki/loki-stack/charts/grafana/templates/image-renderer-service.yaml

@@ -0,0 +1,28 @@
+{{ if .Values.imageRenderer.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ template "grafana.fullname" . }}-image-renderer
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.imageRenderer.labels" . | nindent 4 }}
+{{- if .Values.imageRenderer.service.labels }}
+{{ toYaml .Values.imageRenderer.service.labels | indent 4 }}
+{{- end }}
+{{- with .Values.imageRenderer.service.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+  type: ClusterIP
+  {{- if .Values.imageRenderer.service.clusterIP }}
+  clusterIP: {{ .Values.imageRenderer.service.clusterIP }}
+  {{end}}
+  ports:
+    - name: {{ .Values.imageRenderer.service.portName }}
+      port: {{ .Values.imageRenderer.service.port }}
+      protocol: TCP
+      targetPort: {{ .Values.imageRenderer.service.targetPort }}
+  selector:
+    {{- include "grafana.imageRenderer.selectorLabels" . | nindent 4 }}
+{{ end }}

+ 55 - 0
loki/loki-stack/charts/grafana/templates/ingress.yaml

@@ -0,0 +1,55 @@
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "grafana.fullname" . -}}
+{{- $servicePort := .Values.service.port -}}
+{{- $ingressPath := .Values.ingress.path -}}
+{{- $extraPaths := .Values.ingress.extraPaths -}}
+{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }}
+apiVersion: networking.k8s.io/v1beta1
+{{ else }}
+apiVersion: extensions/v1beta1
+{{ end -}}
+kind: Ingress
+metadata:
+  name: {{ $fullName }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.ingress.labels }}
+{{ toYaml .Values.ingress.labels | indent 4 }}
+{{- end }}
+  {{- if .Values.ingress.annotations }}
+  annotations:
+    {{- range $key, $value := .Values.ingress.annotations }}
+    {{ $key }}: {{ tpl $value $ | quote }}
+    {{- end }}
+  {{- end }}
+spec:
+{{- if .Values.ingress.tls }}
+  tls:
+{{ toYaml .Values.ingress.tls | indent 4 }}
+{{- end }}
+  rules:
+  {{- if .Values.ingress.hosts  }}
+  {{- range .Values.ingress.hosts }}
+    - host: {{ . }}
+      http:
+        paths:
+{{ if $extraPaths }}
+{{ toYaml $extraPaths | indent 10 }}
+{{- end }}
+          - path: {{ $ingressPath }}
+            backend:
+              serviceName: {{ $fullName }}
+              servicePort: {{ $servicePort }}
+  {{- end }}
+  {{- else }}
+    - http:
+        paths:
+          - backend:
+              serviceName: {{ $fullName }}
+              servicePort: {{ $servicePort }}
+          {{- if $ingressPath }}
+            path: {{ $ingressPath }}
+            {{- end }}
+  {{- end -}}
+{{- end }}

+ 22 - 0
loki/loki-stack/charts/grafana/templates/poddisruptionbudget.yaml

@@ -0,0 +1,22 @@
+{{- if .Values.podDisruptionBudget }}
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.labels }}
+{{ toYaml .Values.labels | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.podDisruptionBudget.minAvailable }}
+  minAvailable: {{ .Values.podDisruptionBudget.minAvailable }}
+{{- end }}
+{{- if .Values.podDisruptionBudget.maxUnavailable }}
+  maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }}
+{{- end }}
+  selector:
+    matchLabels:
+      {{- include "grafana.selectorLabels" . | nindent 6 }}
+{{- end }}

+ 52 - 0
loki/loki-stack/charts/grafana/templates/podsecuritypolicy.yaml

@@ -0,0 +1,52 @@
+{{- if .Values.rbac.pspEnabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+  annotations:
+    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
+    seccomp.security.alpha.kubernetes.io/defaultProfileName:  'docker/default'
+    {{- if .Values.rbac.pspUseAppArmor }}
+    apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
+    apparmor.security.beta.kubernetes.io/defaultProfileName:  'runtime/default'
+    {{- end }}
+spec:
+  privileged: false
+  allowPrivilegeEscalation: false
+  requiredDropCapabilities:
+    # Default set from Docker, without DAC_OVERRIDE or CHOWN
+    - FOWNER
+    - FSETID
+    - KILL
+    - SETGID
+    - SETUID
+    - SETPCAP
+    - NET_BIND_SERVICE
+    - NET_RAW
+    - SYS_CHROOT
+    - MKNOD
+    - AUDIT_WRITE
+    - SETFCAP
+  volumes:
+    - 'configMap'
+    - 'emptyDir'
+    - 'projected'
+    - 'secret'
+    - 'downwardAPI'
+    - 'persistentVolumeClaim'
+  hostNetwork: false
+  hostIPC: false
+  hostPID: false
+  runAsUser:
+    rule: 'RunAsAny'
+  seLinux:
+    rule: 'RunAsAny'
+  supplementalGroups:
+    rule: 'RunAsAny'
+  fsGroup:
+    rule: 'RunAsAny'
+  readOnlyRootFilesystem: false
+{{- end }}

+ 28 - 0
loki/loki-stack/charts/grafana/templates/pvc.yaml

@@ -0,0 +1,28 @@
+{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "pvc")}}
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+  {{- with .Values.persistence.annotations  }}
+  annotations:
+{{ toYaml . | indent 4 }}
+  {{- end }}
+  {{- with .Values.persistence.finalizers  }}
+  finalizers:
+{{ toYaml . | indent 4 }}
+  {{- end }}
+spec:
+  accessModes:
+    {{- range .Values.persistence.accessModes }}
+    - {{ . | quote }}
+    {{- end }}
+  resources:
+    requests:
+      storage: {{ .Values.persistence.size | quote }}
+  {{- if .Values.persistence.storageClassName }}
+  storageClassName: {{ .Values.persistence.storageClassName }}
+  {{- end -}}
+{{- end -}}

+ 32 - 0
loki/loki-stack/charts/grafana/templates/role.yaml

@@ -0,0 +1,32 @@
+{{- if .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: Role
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+{{- if or .Values.rbac.pspEnabled (and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled (or .Values.sidecar.datasources.enabled .Values.rbac.extraRoleRules))) }}
+rules:
+{{- if .Values.rbac.pspEnabled }}
+- apiGroups:      ['extensions']
+  resources:      ['podsecuritypolicies']
+  verbs:          ['use']
+  resourceNames:  [{{ template "grafana.fullname" . }}]
+{{- end }}
+{{- if and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled) }}
+- apiGroups: [""] # "" indicates the core API group
+  resources: ["configmaps", "secrets"]
+  verbs: ["get", "watch", "list"]
+{{- end }}
+{{- with .Values.rbac.extraRoleRules }}
+{{ toYaml . | indent 0 }}
+{{- end}}
+{{- else }}
+rules: []
+{{- end }}
+{{- end }}

+ 21 - 0
loki/loki-stack/charts/grafana/templates/rolebinding.yaml

@@ -0,0 +1,21 @@
+{{- if .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: RoleBinding
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ template "grafana.fullname" . }}
+subjects:
+- kind: ServiceAccount
+  name: {{ template "grafana.serviceAccountName" . }}
+  namespace: {{ template "grafana.namespace" . }}
+{{- end -}}

+ 14 - 0
loki/loki-stack/charts/grafana/templates/secret-env.yaml

@@ -0,0 +1,14 @@
+{{- if .Values.envRenderSecret }}
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ template "grafana.fullname" . }}-env
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+type: Opaque
+data:
+{{- range $key, $val := .Values.envRenderSecret }}
+  {{ $key }}: {{ $val | b64enc | quote }}
+{{- end -}}
+{{- end }}

+ 22 - 0
loki/loki-stack/charts/grafana/templates/secret.yaml

@@ -0,0 +1,22 @@
+{{- if or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret)) }}
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+type: Opaque
+data:
+  {{- if and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) }}
+  admin-user: {{ .Values.adminUser | b64enc | quote }}
+  {{- if .Values.adminPassword }}
+  admin-password: {{ .Values.adminPassword | b64enc | quote }}
+  {{- else }}
+  admin-password: {{ randAlphaNum 40 | b64enc | quote }}
+  {{- end }}
+  {{- end }}
+  {{- if not .Values.ldap.existingSecret }}
+  ldap-toml: {{ .Values.ldap.config | b64enc | quote }}
+  {{- end }}
+{{- end }}

+ 50 - 0
loki/loki-stack/charts/grafana/templates/service.yaml

@@ -0,0 +1,50 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- if .Values.service.labels }}
+{{ toYaml .Values.service.labels | indent 4 }}
+{{- end }}
+{{- with .Values.service.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+{{- if (or (eq .Values.service.type "ClusterIP") (empty .Values.service.type)) }}
+  type: ClusterIP
+  {{- if .Values.service.clusterIP }}
+  clusterIP: {{ .Values.service.clusterIP }}
+  {{end}}
+{{- else if eq .Values.service.type "LoadBalancer" }}
+  type: {{ .Values.service.type }}
+  {{- if .Values.service.loadBalancerIP }}
+  loadBalancerIP: {{ .Values.service.loadBalancerIP }}
+  {{- end }}
+  {{- if .Values.service.loadBalancerSourceRanges }}
+  loadBalancerSourceRanges:
+{{ toYaml .Values.service.loadBalancerSourceRanges | indent 4 }}
+  {{- end -}}
+{{- else }}
+  type: {{ .Values.service.type }}
+{{- end }}
+{{- if .Values.service.externalIPs }}
+  externalIPs:
+{{ toYaml .Values.service.externalIPs | indent 4 }}
+{{- end }}
+  ports:
+    - name: {{ .Values.service.portName }}
+      port: {{ .Values.service.port }}
+      protocol: TCP
+      targetPort: {{ .Values.service.targetPort }}
+{{ if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }}
+      nodePort: {{.Values.service.nodePort}}
+{{ end }}
+  {{- if .Values.extraExposePorts }}
+  {{- tpl (toYaml .Values.extraExposePorts) . | indent 4 }}
+  {{- end }}
+  selector:
+    {{- include "grafana.selectorLabels" . | nindent 4 }}
+

+ 13 - 0
loki/loki-stack/charts/grafana/templates/serviceaccount.yaml

@@ -0,0 +1,13 @@
+{{- if .Values.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.serviceAccount.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+  name: {{ template "grafana.serviceAccountName" . }}
+  namespace: {{ template "grafana.namespace" . }}
+{{- end }}

+ 36 - 0
loki/loki-stack/charts/grafana/templates/servicemonitor.yaml

@@ -0,0 +1,36 @@
+{{- if .Values.serviceMonitor.enabled }}
+---
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  {{- if .Values.serviceMonitor.namespace }}
+  namespace: {{ .Values.serviceMonitor.namespace }}
+  {{- end }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+    {{- if .Values.serviceMonitor.labels }}
+    {{- toYaml .Values.serviceMonitor.labels | nindent 4 }}
+    {{- end }}
+spec:
+  endpoints:
+  - interval: {{ .Values.serviceMonitor.interval }}
+    {{- if .Values.serviceMonitor.scrapeTimeout }}
+    scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }}
+    {{- end }}
+    honorLabels: true
+    port: {{ .Values.service.portName }}
+    path: {{ .Values.serviceMonitor.path }}
+    {{- if .Values.serviceMonitor.relabelings }}
+    relabelings:
+    {{- toYaml .Values.serviceMonitor.relabelings | nindent 4 }}
+    {{- end }}
+  jobLabel: "{{ .Release.Name }}"
+  selector:
+    matchLabels:
+      app: {{ template "grafana.name" . }}
+      release: "{{ .Release.Name }}"
+  namespaceSelector:
+    matchNames:
+      - {{ .Release.Namespace }}
+{{- end }}

+ 47 - 0
loki/loki-stack/charts/grafana/templates/statefulset.yaml

@@ -0,0 +1,47 @@
+{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "statefulset")}}
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ template "grafana.fullname" . }}
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+{{- with .Values.annotations }}
+  annotations:
+{{ toYaml . | indent 4 }}
+{{- end }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      {{- include "grafana.selectorLabels" . | nindent 6 }}
+  serviceName: {{ template "grafana.fullname" . }}-headless
+  template:
+    metadata:
+      labels:
+        {{- include "grafana.selectorLabels" . | nindent 8 }}
+{{- with .Values.podLabels }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+      annotations:
+        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+        checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }}
+        checksum/sc-dashboard-provider-config: {{ include (print $.Template.BasePath "/configmap-dashboard-provider.yaml") . | sha256sum }}
+  {{- if or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret)) }}
+        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
+{{- end }}
+{{- with .Values.podAnnotations }}
+{{ toYaml . | indent 8 }}
+{{- end }}
+    spec:
+      {{- include "grafana.pod" . | nindent 6 }}
+  volumeClaimTemplates:
+  - metadata:
+      name: storage
+    spec:
+      accessModes: {{ .Values.persistence.accessModes }}
+      storageClassName: {{ .Values.persistence.storageClassName }}
+      resources:
+        requests:
+          storage: {{ .Values.persistence.size }} 
+{{- end }}

+ 17 - 0
loki/loki-stack/charts/grafana/templates/tests/test-configmap.yaml

@@ -0,0 +1,17 @@
+{{- if .Values.testFramework.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ template "grafana.fullname" . }}-test
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+data:
+  run.sh: |-
+    @test "Test Health" {
+      url="http://{{ template "grafana.fullname" . }}/api/health"
+
+      code=$(wget --server-response --spider --timeout 10 --tries 1 ${url} 2>&1 | awk '/^  HTTP/{print $2}')
+      [ "$code" == "200" ]
+    }
+{{- end }}

+ 29 - 0
loki/loki-stack/charts/grafana/templates/tests/test-podsecuritypolicy.yaml

@@ -0,0 +1,29 @@
+{{- if and .Values.testFramework.enabled .Values.rbac.pspEnabled }}
+apiVersion: policy/v1beta1
+kind: PodSecurityPolicy
+metadata:
+  name: {{ template "grafana.fullname" . }}-test
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+spec:
+  allowPrivilegeEscalation: true
+  privileged: false
+  hostNetwork: false
+  hostIPC: false
+  hostPID: false
+  fsGroup:
+    rule: RunAsAny
+  seLinux:
+    rule: RunAsAny
+  supplementalGroups:
+    rule: RunAsAny
+  runAsUser:
+    rule: RunAsAny
+  volumes:
+  - configMap
+  - downwardAPI
+  - emptyDir
+  - projected
+  - secret
+{{- end }}

+ 14 - 0
loki/loki-stack/charts/grafana/templates/tests/test-role.yaml

@@ -0,0 +1,14 @@
+{{- if and .Values.testFramework.enabled .Values.rbac.pspEnabled -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ template "grafana.fullname" . }}-test
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+rules:
+- apiGroups:      ['policy']
+  resources:      ['podsecuritypolicies']
+  verbs:          ['use']
+  resourceNames:  [{{ template "grafana.fullname" . }}-test]
+{{- end }}

+ 17 - 0
loki/loki-stack/charts/grafana/templates/tests/test-rolebinding.yaml

@@ -0,0 +1,17 @@
+{{- if and .Values.testFramework.enabled .Values.rbac.pspEnabled -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ template "grafana.fullname" . }}-test
+  namespace: {{ template "grafana.namespace" . }}
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ template "grafana.fullname" . }}-test
+subjects:
+- kind: ServiceAccount
+  name: {{ template "grafana.serviceAccountNameTest" . }}
+  namespace: {{ template "grafana.namespace" . }}
+{{- end }}

+ 9 - 0
loki/loki-stack/charts/grafana/templates/tests/test-serviceaccount.yaml

@@ -0,0 +1,9 @@
+{{- if and .Values.testFramework.enabled .Values.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+  name: {{ template "grafana.serviceAccountNameTest" . }}
+  namespace: {{ template "grafana.namespace" . }}
+{{- end }}

+ 48 - 0
loki/loki-stack/charts/grafana/templates/tests/test.yaml

@@ -0,0 +1,48 @@
+{{- if .Values.testFramework.enabled }}
+apiVersion: v1
+kind: Pod
+metadata:
+  name: {{ template "grafana.fullname" . }}-test
+  labels:
+    {{- include "grafana.labels" . | nindent 4 }}
+  annotations:
+    "helm.sh/hook": test-success
+  namespace: {{ template "grafana.namespace" . }}
+spec:
+  serviceAccountName: {{ template "grafana.serviceAccountNameTest" . }}
+  {{- if .Values.testFramework.securityContext }}
+  securityContext: {{ toYaml .Values.testFramework.securityContext | nindent 4 }}
+  {{- end }}
+  {{- if .Values.image.pullSecrets }}
+  imagePullSecrets:
+  {{- range .Values.image.pullSecrets }}
+    - name: {{ . }}
+  {{- end}}
+  {{- end }}
+  {{- with .Values.nodeSelector }}
+  nodeSelector:
+{{ toYaml . | indent 4 }}
+  {{- end }}
+  {{- with .Values.affinity }}
+  affinity:
+{{ toYaml . | indent 4 }}
+  {{- end }}
+  {{- with .Values.tolerations }}
+  tolerations:
+{{ toYaml . | indent 4 }}
+  {{- end }}
+  containers:
+    - name: {{ .Release.Name }}-test
+      image: "{{ .Values.testFramework.image}}:{{ .Values.testFramework.tag }}"
+      imagePullPolicy: "{{ .Values.testFramework.imagePullPolicy}}"
+      command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"]
+      volumeMounts:
+        - mountPath: /tests
+          name: tests
+          readOnly: true
+  volumes:
+  - name: tests
+    configMap:
+      name: {{ template "grafana.fullname" . }}-test
+  restartPolicy: Never
+{{- end }}

+ 643 - 0
loki/loki-stack/charts/grafana/values.yaml

@@ -0,0 +1,643 @@
+rbac:
+  create: true
+  pspEnabled: true
+  pspUseAppArmor: true
+  namespaced: false
+  extraRoleRules: []
+  # - apiGroups: []
+  #   resources: []
+  #   verbs: []
+  extraClusterRoleRules: []
+  # - apiGroups: []
+  #   resources: []
+  #   verbs: []
+serviceAccount:
+  create: true
+  name:
+  nameTest:
+#  annotations:
+#    eks.amazonaws.com/role-arn: arn:aws:iam::123456789000:role/iam-role-name-here
+
+replicas: 1
+
+## See `kubectl explain poddisruptionbudget.spec` for more
+## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/
+podDisruptionBudget: {}
+#  minAvailable: 1
+#  maxUnavailable: 1
+
+## See `kubectl explain deployment.spec.strategy` for more
+## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy
+deploymentStrategy:
+  type: RollingUpdate
+
+readinessProbe:
+  httpGet:
+    path: /api/health
+    port: 3000
+
+livenessProbe:
+  httpGet:
+    path: /api/health
+    port: 3000
+  initialDelaySeconds: 60
+  timeoutSeconds: 30
+  failureThreshold: 10
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+# schedulerName: "default-scheduler"
+
+image:
+  repository: registry.cn-beijing.aliyuncs.com/dotbalo/grafana
+  tag: 7.2.1
+  sha: ""
+  pullPolicy: IfNotPresent
+
+  ## Optionally specify an array of imagePullSecrets.
+  ## Secrets must be manually created in the namespace.
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+  ##
+  # pullSecrets:
+  #   - myRegistrKeySecretName
+
+testFramework:
+  enabled: true
+  image: "bats/bats"
+  tag: "v1.1.0"
+  imagePullPolicy: IfNotPresent
+  securityContext: {}
+
+securityContext:
+  runAsUser: 472
+  runAsGroup: 472
+  fsGroup: 472
+
+
+extraConfigmapMounts: []
+  # - name: certs-configmap
+  #   mountPath: /etc/grafana/ssl/
+  #   subPath: certificates.crt # (optional)
+  #   configMap: certs-configmap
+  #   readOnly: true
+
+
+extraEmptyDirMounts: []
+  # - name: provisioning-notifiers
+  #   mountPath: /etc/grafana/provisioning/notifiers
+
+
+## Assign a PriorityClassName to pods if set
+# priorityClassName:
+
+downloadDashboardsImage:
+  repository: curlimages/curl
+  tag: 7.70.0
+  sha: ""
+  pullPolicy: IfNotPresent
+
+downloadDashboards:
+  env: {}
+  resources: {}
+
+## Pod Annotations
+# podAnnotations: {}
+
+## Pod Labels
+# podLabels: {}
+
+podPortName: grafana
+
+## Deployment annotations
+# annotations: {}
+
+## Expose the grafana service to be accessed from outside the cluster (LoadBalancer service).
+## or access it from within the cluster (ClusterIP service). Set the service type and the port to serve it.
+## ref: http://kubernetes.io/docs/user-guide/services/
+##
+service:
+  type: ClusterIP
+  port: 80
+  targetPort: 3000
+    # targetPort: 4181 To be used with a proxy extraContainer
+  annotations: {}
+  labels: {}
+  portName: service
+
+serviceMonitor:
+  ## If true, a ServiceMonitor CRD is created for a prometheus operator
+  ## https://github.com/coreos/prometheus-operator
+  ##
+  enabled: false
+  path: /metrics
+  #  namespace: monitoring  (defaults to use the namespace this chart is deployed to)
+  labels: {}
+  interval: 1m
+  scrapeTimeout: 30s
+  relabelings: []
+
+extraExposePorts: []
+ # - name: keycloak
+ #   port: 8080
+ #   targetPort: 8080
+ #   type: ClusterIP
+
+# overrides pod.spec.hostAliases in the grafana deployment's pods
+hostAliases: []
+  # - ip: "1.2.3.4"
+  #   hostnames:
+  #     - "my.host.com"
+
+ingress:
+  enabled: false
+  # Values can be templated
+  annotations: {}
+    # kubernetes.io/ingress.class: nginx
+    # kubernetes.io/tls-acme: "true"
+  labels: {}
+  path: /
+  hosts:
+    - chart-example.local
+  ## Extra paths to prepend to every host configuration. This is useful when working with annotation based services.
+  extraPaths: []
+  # - path: /*
+  #   backend:
+  #     serviceName: ssl-redirect
+  #     servicePort: use-annotation
+  tls: []
+  #  - secretName: chart-example-tls
+  #    hosts:
+  #      - chart-example.local
+
+resources: {}
+#  limits:
+#    cpu: 100m
+#    memory: 128Mi
+#  requests:
+#    cpu: 100m
+#    memory: 128Mi
+
+## Node labels for pod assignment
+## ref: https://kubernetes.io/docs/user-guide/node-selection/
+#
+nodeSelector: {}
+
+## Tolerations for pod assignment
+## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+##
+tolerations: []
+
+## Affinity for pod assignment
+## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+##
+affinity: {}
+
+extraInitContainers: []
+
+## Enable an Specify container in extraContainers. This is meant to allow adding an authentication proxy to a grafana pod
+extraContainers: |
+# - name: proxy
+#   image: quay.io/gambol99/keycloak-proxy:latest
+#   args:
+#   - -provider=github
+#   - -client-id=
+#   - -client-secret=
+#   - -github-org=<ORG_NAME>
+#   - -email-domain=*
+#   - -cookie-secret=
+#   - -http-address=http://0.0.0.0:4181
+#   - -upstream-url=http://127.0.0.1:3000
+#   ports:
+#     - name: proxy-web
+#       containerPort: 4181
+
+## Volumes that can be used in init containers that will not be mounted to deployment pods
+extraContainerVolumes: []
+#  - name: volume-from-secret
+#    secret:
+#      secretName: secret-to-mount
+#  - name: empty-dir-volume
+#    emptyDir: {}
+
+## Enable persistence using Persistent Volume Claims
+## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
+##
+persistence:
+  type: pvc
+  enabled: false
+  # storageClassName: default
+  accessModes:
+    - ReadWriteOnce
+  size: 10Gi
+  # annotations: {}
+  finalizers:
+    - kubernetes.io/pvc-protection
+  # subPath: ""
+  # existingClaim:
+
+initChownData:
+  ## If false, data ownership will not be reset at startup
+  ## This allows the prometheus-server to be run with an arbitrary user
+  ##
+  enabled: true
+
+  ## initChownData container image
+  ##
+  image:
+    repository: busybox
+    tag: "1.31.1"
+    sha: ""
+    pullPolicy: IfNotPresent
+
+  ## initChownData resource requests and limits
+  ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/
+  ##
+  resources: {}
+  #  limits:
+  #    cpu: 100m
+  #    memory: 128Mi
+  #  requests:
+  #    cpu: 100m
+  #    memory: 128Mi
+
+
+# Administrator credentials when not using an existing secret (see below)
+adminUser: admin
+# adminPassword: strongpassword
+
+# Use an existing secret for the admin user.
+admin:
+  existingSecret: ""
+  userKey: admin-user
+  passwordKey: admin-password
+
+## Define command to be executed at startup by grafana container
+## Needed if using `vault-env` to manage secrets (ref: https://banzaicloud.com/blog/inject-secrets-into-pods-vault/)
+## Default is "run.sh" as defined in grafana's Dockerfile
+# command:
+# - "sh"
+# - "/run.sh"
+
+## Use an alternate scheduler, e.g. "stork".
+## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
+##
+# schedulerName:
+
+## Extra environment variables that will be pass onto deployment pods
+##
+## to provide grafana with access to CloudWatch on AWS EKS:
+## 1. create an iam role of type "Web identity" with provider oidc.eks.* (note the provider for later)
+## 2. edit the "Trust relationships" of the role, add a line inside the StringEquals clause using the
+## same oidc eks provider as noted before (same as the existing line)
+## also, replace NAMESPACE and prometheus-operator-grafana with the service account namespace and name
+##
+##  "oidc.eks.us-east-1.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:sub": "system:serviceaccount:NAMESPACE:prometheus-operator-grafana",
+##
+## 3. attach a policy to the role, you can use a built in policy called CloudWatchReadOnlyAccess
+## 4. use the following env: (replace 123456789000 and iam-role-name-here with your aws account number and role name)
+##
+## env:
+##   AWS_ROLE_ARN: arn:aws:iam::123456789000:role/iam-role-name-here
+##   AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
+##   AWS_REGION: us-east-1
+##
+## 5. uncomment the EKS section in extraSecretMounts: below
+## 6. uncomment the annotation section in the serviceAccount: above
+## make sure to replace arn:aws:iam::123456789000:role/iam-role-name-here with your role arn
+
+env: {}
+
+## "valueFrom" environment variable references that will be added to deployment pods
+## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core
+## Renders in container spec as:
+##   env:
+##     ...
+##     - name: <key>
+##       valueFrom:
+##         <value rendered as YAML>
+envValueFrom: {}
+
+## The name of a secret in the same kubernetes namespace which contain values to be added to the environment
+## This can be useful for auth tokens, etc. Value is templated.
+envFromSecret: ""
+
+## Sensible environment variables that will be rendered as new secret object
+## This can be useful for auth tokens, etc
+envRenderSecret: {}
+
+## Additional grafana server secret mounts
+# Defines additional mounts with secrets. Secrets must be manually created in the namespace.
+extraSecretMounts: []
+  # - name: secret-files
+  #   mountPath: /etc/secrets
+  #   secretName: grafana-secret-files
+  #   readOnly: true
+  #   subPath: ""
+  #
+  # for AWS EKS (cloudwatch) use the following (see also instruction in env: above)
+  # - name: aws-iam-token
+  #   mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
+  #   readOnly: true
+  #   projected:
+  #     defaultMode: 420
+  #     sources:
+  #       - serviceAccountToken:
+  #           audience: sts.amazonaws.com
+  #           expirationSeconds: 86400
+  #           path: token
+
+## Additional grafana server volume mounts
+# Defines additional volume mounts.
+extraVolumeMounts: []
+  # - name: extra-volume
+  #   mountPath: /mnt/volume
+  #   readOnly: true
+  #   existingClaim: volume-claim
+
+## Pass the plugins you want installed as a list.
+##
+plugins: []
+  # - digrich-bubblechart-panel
+  # - grafana-clock-panel
+
+## Configure grafana datasources
+## ref: http://docs.grafana.org/administration/provisioning/#datasources
+##
+datasources: {}
+#  datasources.yaml:
+#    apiVersion: 1
+#    datasources:
+#    - name: Prometheus
+#      type: prometheus
+#      url: http://prometheus-prometheus-server
+#      access: proxy
+#      isDefault: true
+#    - name: CloudWatch
+#        type: cloudwatch
+#        access: proxy
+#        uid: cloudwatch
+#        editable: false
+#        jsonData:
+#          authType: credentials
+#          defaultRegion: us-east-1
+
+## Configure notifiers
+## ref: http://docs.grafana.org/administration/provisioning/#alert-notification-channels
+##
+notifiers: {}
+#  notifiers.yaml:
+#    notifiers:
+#    - name: email-notifier
+#      type: email
+#      uid: email1
+#      # either:
+#      org_id: 1
+#      # or
+#      org_name: Main Org.
+#      is_default: true
+#      settings:
+#        addresses: an_email_address@example.com
+#    delete_notifiers:
+
+## Configure grafana dashboard providers
+## ref: http://docs.grafana.org/administration/provisioning/#dashboards
+##
+## `path` must be /var/lib/grafana/dashboards/<provider_name>
+##
+dashboardProviders: {}
+#  dashboardproviders.yaml:
+#    apiVersion: 1
+#    providers:
+#    - name: 'default'
+#      orgId: 1
+#      folder: ''
+#      type: file
+#      disableDeletion: false
+#      editable: true
+#      options:
+#        path: /var/lib/grafana/dashboards/default
+
+## Configure grafana dashboard to import
+## NOTE: To use dashboards you must also enable/configure dashboardProviders
+## ref: https://grafana.com/dashboards
+##
+## dashboards per provider, use provider name as key.
+##
+dashboards: {}
+  # default:
+  #   some-dashboard:
+  #     json: |
+  #       $RAW_JSON
+  #   custom-dashboard:
+  #     file: dashboards/custom-dashboard.json
+  #   prometheus-stats:
+  #     gnetId: 2
+  #     revision: 2
+  #     datasource: Prometheus
+  #   local-dashboard:
+  #     url: https://example.com/repository/test.json
+  #   local-dashboard-base64:
+  #     url: https://example.com/repository/test-b64.json
+  #     b64content: true
+
+## Reference to external ConfigMap per provider. Use provider name as key and ConfigMap name as value.
+## A provider dashboards must be defined either by external ConfigMaps or in values.yaml, not in both.
+## ConfigMap data example:
+##
+## data:
+##   example-dashboard.json: |
+##     RAW_JSON
+##
+dashboardsConfigMaps: {}
+#  default: ""
+
+## Grafana's primary configuration
+## NOTE: values in map will be converted to ini format
+## ref: http://docs.grafana.org/installation/configuration/
+##
+grafana.ini:
+  paths:
+    data: /var/lib/grafana/data
+    logs: /var/log/grafana
+    plugins: /var/lib/grafana/plugins
+    provisioning: /etc/grafana/provisioning
+  analytics:
+    check_for_updates: true
+  log:
+    mode: console
+  grafana_net:
+    url: https://grafana.net
+## grafana Authentication can be enabled with the following values on grafana.ini
+ # server:
+      # The full public facing url you use in browser, used for redirects and emails
+ #    root_url:
+ # https://grafana.com/docs/grafana/latest/auth/github/#enable-github-in-grafana
+ # auth.github:
+ #    enabled: false
+ #    allow_sign_up: false
+ #    scopes: user:email,read:org
+ #    auth_url: https://github.com/login/oauth/authorize
+ #    token_url: https://github.com/login/oauth/access_token
+ #    api_url: https://api.github.com/user
+ #    team_ids:
+ #    allowed_organizations:
+ #    client_id:
+ #    client_secret:
+## LDAP Authentication can be enabled with the following values on grafana.ini
+## NOTE: Grafana will fail to start if the value for ldap.toml is invalid
+  # auth.ldap:
+  #   enabled: true
+  #   allow_sign_up: true
+  #   config_file: /etc/grafana/ldap.toml
+
+## Grafana's LDAP configuration
+## Templated by the template in _helpers.tpl
+## NOTE: To enable the grafana.ini must be configured with auth.ldap.enabled
+## ref: http://docs.grafana.org/installation/configuration/#auth-ldap
+## ref: http://docs.grafana.org/installation/ldap/#configuration
+ldap:
+  enabled: false
+  # `existingSecret` is a reference to an existing secret containing the ldap configuration
+  # for Grafana in a key `ldap-toml`.
+  existingSecret: ""
+  # `config` is the content of `ldap.toml` that will be stored in the created secret
+  config: ""
+  # config: |-
+  #   verbose_logging = true
+
+  #   [[servers]]
+  #   host = "my-ldap-server"
+  #   port = 636
+  #   use_ssl = true
+  #   start_tls = false
+  #   ssl_skip_verify = false
+  #   bind_dn = "uid=%s,ou=users,dc=myorg,dc=com"
+
+## Grafana's SMTP configuration
+## NOTE: To enable, grafana.ini must be configured with smtp.enabled
+## ref: http://docs.grafana.org/installation/configuration/#smtp
+smtp:
+  # `existingSecret` is a reference to an existing secret containing the smtp configuration
+  # for Grafana.
+  existingSecret: ""
+  userKey: "user"
+  passwordKey: "password"
+
+## Sidecars that collect the configmaps with specified label and stores the included files them into the respective folders
+## Requires at least Grafana 5 to work and can't be used together with parameters dashboardProviders, datasources and dashboards
+sidecar:
+  image:
+    repository: kiwigrid/k8s-sidecar
+    tag: 0.1.209
+    sha: ""
+  imagePullPolicy: IfNotPresent
+  resources: {}
+#   limits:
+#     cpu: 100m
+#     memory: 100Mi
+#   requests:
+#     cpu: 50m
+#     memory: 50Mi
+  # skipTlsVerify Set to true to skip tls verification for kube api calls
+  # skipTlsVerify: true
+  enableUniqueFilenames: false
+  dashboards:
+    enabled: false
+    SCProvider: true
+    # label that the configmaps with dashboards are marked with
+    label: grafana_dashboard
+    # folder in the pod that should hold the collected dashboards (unless `defaultFolderName` is set)
+    folder: /tmp/dashboards
+    # The default folder name, it will create a subfolder under the `folder` and put dashboards in there instead
+    defaultFolderName: null
+    # If specified, the sidecar will search for dashboard config-maps inside this namespace.
+    # Otherwise the namespace in which the sidecar is running will be used.
+    # It's also possible to specify ALL to search in all namespaces
+    searchNamespace: null
+    # provider configuration that lets grafana manage the dashboards
+    provider:
+      # name of the provider, should be unique
+      name: sidecarProvider
+      # orgid as configured in grafana
+      orgid: 1
+      # folder in which the dashboards should be imported in grafana
+      folder: ''
+      # type of the provider
+      type: file
+      # disableDelete to activate a import-only behaviour
+      disableDelete: false
+      # allow updating provisioned dashboards from the UI
+      allowUiUpdates: false
+      # allow Grafana to replicate dashboard structure from filesystem
+      foldersFromFilesStructure: false
+  datasources:
+    enabled: false
+    # label that the configmaps with datasources are marked with
+    label: grafana_datasource
+    # If specified, the sidecar will search for datasource config-maps inside this namespace.
+    # Otherwise the namespace in which the sidecar is running will be used.
+    # It's also possible to specify ALL to search in all namespaces
+    searchNamespace: null
+  notifiers:
+    enabled: false
+    # label that the configmaps with notifiers are marked with
+    label: grafana_notifier
+    # If specified, the sidecar will search for notifier config-maps inside this namespace.
+    # Otherwise the namespace in which the sidecar is running will be used.
+    # It's also possible to specify ALL to search in all namespaces
+    searchNamespace: null
+
+## Override the deployment namespace
+##
+namespaceOverride: ""
+
+## Number of old ReplicaSets to retain
+##
+revisionHistoryLimit: 10
+
+## Add a seperate remote image renderer deployment/service
+imageRenderer:
+  # Enable the image-renderer deployment & service
+  enabled: false
+  replicas: 1
+  image:
+    # image-renderer Image repository
+    repository: grafana/grafana-image-renderer
+    # image-renderer Image tag
+    tag: latest
+    # image-renderer Image sha (optional)
+    sha: ""
+    # image-renderer ImagePullPolicy
+    pullPolicy: Always
+  # extra environment variables
+  env: {}
+    # RENDERING_ARGS: --disable-gpu,--window-size=1280x758
+    # RENDERING_MODE: clustered
+  # image-renderer deployment securityContext
+  securityContext: {}
+  # image-renderer deployment Host Aliases
+  hostAliases: []
+  # image-renderer deployment priority class
+  priorityClassName: ''
+  service:
+    # image-renderer service port name
+    portName: 'http'
+    # image-renderer service port used by both service and deployment
+    port: 8081
+  # name of the image-renderer port on the pod
+  podPortName: http
+  # number of image-renderer replica sets to keep
+  revisionHistoryLimit: 10
+  networkPolicy:
+    # Enable a NetworkPolicy to limit inbound traffic to only the created grafana pods
+    limitIngress: true
+    # Enable a NetworkPolicy to limit outbound traffic to only the created grafana pods
+    limitEgress: false
+  resources: {}
+#   limits:
+#     cpu: 100m
+#     memory: 100Mi
+#   requests:
+#     cpu: 50m
+#     memory: 50Mi

+ 2 - 0
loki/loki-stack/charts/logstash/.helmignore

@@ -0,0 +1,2 @@
+tests/
+.pytest_cache/

+ 12 - 0
loki/loki-stack/charts/logstash/Chart.yaml

@@ -0,0 +1,12 @@
+apiVersion: v1
+appVersion: 7.8.1
+description: Official Elastic helm chart for Logstash
+home: https://github.com/elastic/helm-charts
+icon: https://helm.elastic.co/icons/logstash.png
+maintainers:
+- email: helm-charts@elastic.co
+  name: Elastic
+name: logstash
+sources:
+- https://github.com/elastic/logstash
+version: 7.8.1

+ 1 - 0
loki/loki-stack/charts/logstash/Makefile

@@ -0,0 +1 @@
+include ../helpers/common.mk

+ 208 - 0
loki/loki-stack/charts/logstash/README.md

@@ -0,0 +1,208 @@
+# Logstash Helm Chart
+
+This Helm chart is a lightweight way to configure and run our official
+[Logstash Docker image][].
+
+**Warning**: This functionality is in beta and is subject to change.
+The design and code is less mature than official GA features and is being
+provided as-is with no warranties. Alpha features are not subject to the support
+SLA of official GA features (see [supported configurations][] for more details).
+
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
+
+- [Requirements](#requirements)
+- [Installing](#installing)
+- [Upgrading](#upgrading)
+- [Usage notes](#usage-notes)
+- [Configuration](#configuration)
+- [FAQ](#faq)
+  - [How to install OSS version of Logstash?](#how-to-install-oss-version-of-logstash)
+  - [How to install plugins?](#how-to-install-plugins)
+- [Contributing](#contributing)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+<!-- Use this to update TOC: -->
+<!-- docker run --rm -it -v $(pwd):/usr/src jorgeandrada/doctoc --github -->
+
+
+## Requirements
+
+* [Helm][] >=2.8.0 and <3.0.0
+* Kubernetes >=1.8
+
+See [supported configurations][] for more details.
+
+
+## Installing
+
+This chart is tested with 7.8.1 version.
+
+* Add the Elastic Helm charts repo:
+`helm repo add elastic https://helm.elastic.co`
+
+* Install 7.8.1 release:
+`helm install --name apm-server --version 7.8.1 elastic/logstash`
+
+
+## Upgrading
+
+Please always check [CHANGELOG.md][] and [BREAKING_CHANGES.md][] before
+upgrading to a new chart version.
+
+
+## Usage notes
+
+* This repo includes a number of [examples][] configurations which can be used
+as a reference. They are also used in the automated testing of this chart
+* Automated testing of this chart is currently only run against GKE (Google
+Kubernetes Engine).
+* The chart deploys a StatefulSet and by default will do an automated rolling
+update of your cluster. It does this by waiting for the cluster health to become
+green after each instance is updated. If you prefer to update manually you can
+set `OnDelete` [updateStrategy][].
+* It is important to verify that the JVM heap size in `logstashJavaOpts` and to
+set the CPU/Memory `resources` to something suitable for your cluster.
+* We have designed this chart to be very un-opinionated about how to configure
+Logstash. It exposes ways to set environment variables and mount secrets inside
+of the container. Doing this makes it much easier for this chart to support
+multiple versions with minimal changes.
+* `logstash.yml` configuration files can be set either by a ConfigMap using
+`logstashConfig` in `values.yml` or by environment variables using `extraEnvs`
+in `values.yml` , however Logstash Docker image can't mix both methods as
+defining settings with environment variables causes `logstash.yml` to be
+modified in place while using ConfigMap bind-mount the same file (more details
+in this [note][]).
+* When overriding `logstash.yml`, `http.host: 0.0.0.0` should always be included
+to make default probes work. If restricting HTTP API to 127.0.0.1 is required by
+using `http.host: 127.0.0.1`, default probes should be disabled or overrided
+(see [values.yaml][] for the good syntax).
+
+
+## Configuration
+
+| Parameter                 | Description                                                                                                                                                                                                                          | Default                               |
+|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
+| `antiAffinityTopologyKey` | The [anti-affinity][] topology key]. By default this will prevent multiple Logstash nodes from running on the same Kubernetes node                                                                                                   | `kubernetes.io/hostname`              |
+| `antiAffinity`            | Setting this to hard enforces the [anti-affinity][] rules. If it is set to soft it will be done "best effort". Other values will be ignored                                                                                          | `hard`                                |
+| `envFrom`                 | Templatable string to be passed to the [environment from variables][] which will be appended to the `envFrom:` definition for the container                                                                                          | `[]`                                  |
+| `extraContainers`         | Templatable string of additional containers to be passed to the `tpl` function                                                                                                                                                       | `""`                                  |
+| `extraEnvs`               | Extra [environment variables][] which will be appended to the `env:` definition for the container                                                                                                                                    | `[]`                                  |
+| `extraInitContainers`     | Templatable string of additional `initContainers` to be passed to the `tpl` function                                                                                                                                                 | `""`                                  |
+| `extraPorts`              | An array of extra ports to open on the pod                                                                                                                                                                                           | `[]`                                  |
+| `extraVolumeMounts`       | Templatable string of additional `volumeMounts` to be passed to the `tpl` function                                                                                                                                                   | `""`                                  |
+| `extraVolumes`            | Templatable string of additional `volumes` to be passed to the `tpl` function                                                                                                                                                        | `""`                                  |
+| `fullnameOverride`        | Overrides the full name of the resources. If not set the name will default to " `.Release.Name` - `.Values.nameOverride or .Chart.Name` "                                                                                            | `""`                                  |
+| `httpPort`                | The http port that Kubernetes will use for the healthchecks and the service                                                                                                                                                          | `9600`                                |
+| `imagePullPolicy`         | The Kubernetes [imagePullPolicy][] value                                                                                                                                                                                             | `IfNotPresent`                        |
+| `imagePullSecrets`        | Configuration for [imagePullSecrets][] so that you can use a private registry for your image                                                                                                                                         | `[]`                                  |
+| `imageTag`                | The Logstash Docker image tag                                                                                                                                                                                                        | `7.8.1`                               |
+| `image`                   | The Logstash Docker image                                                                                                                                                                                                            | `docker.elastic.co/logstash/logstash` |
+| `labels`                  | Configurable [labels][] applied to all Logstash pods                                                                                                                                                                                 | `{}`                                  |
+| `lifecycle`               | Allows you to add lifecycle configuration. See [values.yaml][] for an example of the formatting                                                                                                                                      | `{}`                                  |
+| `livenessProbe`           | Configuration fields for the liveness [probe][]                                                                                                                                                                                      | see [values.yaml][]                   |
+| `logstashConfig`          | Allows you to add any config files in `/usr/share/logstash/config/` such as `logstash.yml` and `log4j2.properties` See [values.yaml][] for an example of the formatting                                                              | `{}`                                  |
+| `logstashJavaOpts`        | Java options for Logstash. This is where you should configure the JVM heap size                                                                                                                                                      | `-Xmx1g -Xms1g`                       |
+| `logstashPipeline`        | Allows you to add any pipeline files in `/usr/share/logstash/pipeline/`                                                                                                                                                              | `{}`                                  |
+| `maxUnavailable`          | The [maxUnavailable][] value for the pod disruption budget. By default this will prevent Kubernetes from having more than 1 unhealthy pod in the node group                                                                          | `1`                                   |
+| `nameOverride`            | Overrides the chart name for resources. If not set the name will default to `.Chart.Name`                                                                                                                                            | `""`                                  |
+| `nodeAffinity`            | Value for the [node affinity settings][]                                                                                                                                                                                             | `{}`                                  |
+| `nodeSelector`            | Configurable [nodeSelector][] so that you can target specific nodes for your Logstash cluster                                                                                                                                        | `{}`                                  |
+| `persistence`             | Enables a persistent volume for Logstash data                                                                                                                                                                                        | see [values.yaml][]                   |
+| `podAnnotations`          | Configurable [annotations][] applied to all Logstash pods                                                                                                                                                                            | `{}`                                  |
+| `podManagementPolicy`     | By default Kubernetes [deploys StatefulSets serially][]. This deploys them in parallel so that they can discover each other                                                                                                          | `Parallel`                            |
+| `podSecurityContext`      | Allows you to set the [securityContext][] for the pod                                                                                                                                                                                | see [values.yaml][]                   |
+| `podSecurityPolicy`       | Configuration for create a pod security policy with minimal permissions to run this Helm chart with `create: true` Also can be used to reference an external pod security policy with `name: "externalPodSecurityPolicy"`            | see [values.yaml][]                   |
+| `priorityClassName`       | The name of the [PriorityClass][]. No default is supplied as the PriorityClass must be created first                                                                                                                                 | `""`                                  |
+| `rbac`                    | Configuration for creating a role, role binding and service account as part of this Helm chart with `create: true` Also can be used to reference an external service account with `serviceAccountName: "externalServiceAccountName"` | see [values.yaml][]                   |
+| `readinessProbe`          | Configuration fields for the readiness [probe][]                                                                                                                                                                                     | see [values.yaml][]                   |
+| `replicas`                | Kubernetes replica count for the StatefulSet (i.e. how many pods)                                                                                                                                                                    | `1`                                   |
+| `resources`               | Allows you to set the [resources][] for the StatefulSet                                                                                                                                                                              | see [values.yaml][]                   |
+| `schedulerName`           | Name of the [alternate scheduler][]                                                                                                                                                                                                  | `""`                                  |
+| `secrets`                 | Allows you easily create a secret from as variables or file. For add secrets from file, add suffix `.filepath` to the key of secret key. The value will be encoded to base64. Useful for store certificates and other secrets.       | See [values.yaml][]                   |
+| `secretMounts`            | Allows you easily mount a secret as a file inside the StatefulSet. Useful for mounting certificates and other secrets. See [values.yaml][] for an example                                                                            | `[]`                                  |
+| `securityContext`         | Allows you to set the [securityContext][] for the container                                                                                                                                                                          | see [values.yaml][]                   |
+| `service`                 | Configurable [service][] to expose the Logstash service.                                                                                                                                                                             | see [values.yaml][]                   |
+| `terminationGracePeriod`  | The [terminationGracePeriod][] in seconds used when trying to stop the pod                                                                                                                                                           | `120`                                 |
+| `tolerations`             | Configurable [tolerations][]                                                                                                                                                                                                         | `[]`                                  |
+| `updateStrategy`          | The [updateStrategy][] for the StatefulSet. By default Kubernetes will wait for the cluster to be green after upgrading each pod. Setting this to `OnDelete` will allow you to manually delete each pod during upgrades              | `RollingUpdate`                       |
+| `volumeClaimTemplate`     | Configuration for the [volumeClaimTemplate for StatefulSets][]. You will want to adjust the storage (default `30Gi` ) and the `storageClassName` if you are using a different storage class                                          | see [values.yaml][]                   |
+
+
+## FAQ
+
+### How to install OSS version of Logstash?
+
+Deploying OSS version of Elasticsearch can be done by setting `image` value to
+[Logstash OSS Docker image][]
+
+An example of Logstash deployment using OSS version can be found in
+[examples/oss][].
+
+### How to install plugins?
+
+The recommended way to install plugins into our Docker images is to create a
+[custom Docker image][].
+
+The Dockerfile would look something like:
+
+```
+ARG logstash_version
+FROM docker.elastic.co/logstash/logstash:${logstash_version}
+RUN bin/logstash-plugin install logstash-output-kafka
+```
+
+And then updating the `image` in values to point to your custom image.
+
+There are a couple reasons we recommend this:
+
+1. Tying the availability of Logstash to the download service to install plugins
+is not a great idea or something that we recommend. Especially in Kubernetes
+where it is normal and expected for a container to be moved to another host at
+random times.
+2. Mutating the state of a running Docker image (by installing plugins) goes
+against best practices of containers and immutable infrastructure.
+
+
+## Contributing
+
+Please check [CONTRIBUTING.md][] before any contribution or for any questions
+about our development and testing process.
+
+
+[BREAKING_CHANGES.md]: https://github.com/elastic/helm-charts/blob/master/BREAKING_CHANGES.md
+[CHANGELOG.md]: https://github.com/elastic/helm-charts/blob/master/CHANGELOG.md
+[CONTRIBUTING.md]: https://github.com/elastic/helm-charts/blob/master/CONTRIBUTING.md
+[alternate scheduler]: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/#specify-schedulers-for-pods
+[annotations]: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+[anti-affinity]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+[deploys statefulsets serially]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies
+[custom docker image]: https://www.elastic.co/guide/en/logstash/7.8/docker-config.html#_custom_images
+[environment variables]: https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/#using-environment-variables-inside-of-your-config
+[environment from variables]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables
+[examples]: https://github.com/elastic/helm-charts/tree/7.8/logstash/examples
+[examples/oss]: https://github.com/elastic/helm-charts/tree/7.8/logstash/examples/oss
+[helm]: https://helm.sh
+[imagePullPolicy]: https://kubernetes.io/docs/concepts/containers/images/#updating-images
+[imagePullSecrets]: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#create-a-pod-that-uses-your-secret
+[kubernetes secrets]: https://kubernetes.io/docs/concepts/configuration/secret/
+[labels]: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
+[logstash docker image]: https://www.elastic.co/guide/en/logstash/7.8/docker.html
+[logstash oss docker image]: https://www.docker.elastic.co/r/logstash/logstash-oss
+[maxUnavailable]: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget
+[node affinity settings]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature
+[nodeSelector]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
+[note]: https://www.elastic.co/guide/en/logstash/7.8/docker-config.html#docker-env-config
+[priorityClass]: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
+[probe]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
+[resources]: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
+[updateStrategy]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
+[securityContext]: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
+[service]: https://kubernetes.io/docs/concepts/services-networking/service/
+[supported configurations]: https://github.com/elastic/helm-charts/tree/7.8/README.md#supported-configurations
+[terminationGracePeriod]: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods
+[tolerations]: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+[values.yaml]: https://github.com/elastic/helm-charts/tree/7.8/logstash/values.yaml
+[volumeClaimTemplate for statefulsets]: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#stable-storage

+ 16 - 0
loki/loki-stack/charts/logstash/examples/default/Makefile

@@ -0,0 +1,16 @@
+default: test
+
+include ../../../helpers/examples.mk
+
+RELEASE := helm-logstash-default
+
+install:
+	helm upgrade --wait --timeout=900 --install $(RELEASE) ../../
+
+restart:
+	helm upgrade --set terminationGracePeriod=121 --wait --timeout=900 --install $(RELEASE) ../../
+
+test: install goss
+
+purge:
+	helm del --purge $(RELEASE)

+ 17 - 0
loki/loki-stack/charts/logstash/examples/default/README.md

@@ -0,0 +1,17 @@
+# Default
+
+This example deploy Logstash 7.8.1 using [default values][].
+
+
+## Usage
+
+* Deploy Logstash chart with the default values: `make install`
+
+
+## Testing
+
+You can also run [goss integration tests][] using `make test`
+
+
+[goss integration tests]: https://github.com/elastic/helm-charts/tree/7.8/logstash/examples/default/test/goss.yaml
+[default values]: https://github.com/elastic/helm-charts/tree/7.8/logstash/values.yaml

+ 43 - 0
loki/loki-stack/charts/logstash/examples/default/test/goss.yaml

@@ -0,0 +1,43 @@
+user:
+  logstash:
+    exists: true
+    uid: 1000
+    gid: 1000
+
+http:
+  http://localhost:9600?pretty:
+    status: 200
+    timeout: 2000
+    body:
+      - '"host" : "helm-logstash-default-logstash-0"'
+      - '"version" : "7.8.1"'
+      - '"http_address" : "0.0.0.0:9600"'
+      - '"name" : "helm-logstash-default-logstash-0"'
+      - '"status" : "green"'
+      - '"workers" : 1'
+      - '"batch_size" : 125'
+      - '"batch_delay" : 50'
+
+file:
+  /usr/share/logstash/config/logstash.yml:
+    exists: true
+    mode: "0644"
+    owner: logstash
+    group: root
+    filetype: file
+    contains:
+      - 'http.host: "0.0.0.0"'
+      - 'xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]'
+  /usr/share/logstash/pipeline/logstash.conf:
+    exists: true
+    mode: "0644"
+    owner: logstash
+    group: root
+    filetype: file
+    contains:
+      - 'input {'
+      - 'beats {'
+      - 'port => 5044'
+      - 'output {'
+      - 'stdout {'
+      - 'codec => rubydebug'

+ 17 - 0
loki/loki-stack/charts/logstash/examples/elasticsearch/Makefile

@@ -0,0 +1,17 @@
+default: test
+
+include ../../../helpers/examples.mk
+
+RELEASE := helm-logstash-elasticsearch
+
+install:
+	helm upgrade --wait --timeout=900 --install $(RELEASE) --values ./values.yaml ../../
+
+restart:
+	helm upgrade --set terminationGracePeriod=121 --wait --timeout=900 --install $(RELEASE) ../../
+
+test: install goss
+
+purge:
+	helm del --purge $(RELEASE)
+	kubectl delete $$(kubectl get pvc -l release=$(RELEASE) -o name)

+ 28 - 0
loki/loki-stack/charts/logstash/examples/elasticsearch/README.md

@@ -0,0 +1,28 @@
+# Elasticsearch
+
+This example deploy Logstash 7.8.1 which connects to Elasticsearch (see
+[values][]).
+
+
+## Usage
+
+* Deploy [Elasticsearch Helm chart][].
+
+* Deploy Logstash chart: `make install`
+
+* You can now setup a port forward to query Logstash indices:
+
+  ```
+  kubectl port-forward svc/elasticsearch-master 9200
+  curl localhost:9200/_cat/indices
+  ```
+
+
+## Testing
+
+You can also run [goss integration tests][] using `make test`
+
+
+[elasticsearch helm chart]: https://github.com/elastic/helm-charts/tree/7.8/elasticsearch/examples/default/
+[goss integration tests]: https://github.com/elastic/helm-charts/tree/7.8/logstash/examples/elasticsearch/test/goss.yaml
+[values]: https://github.com/elastic/helm-charts/tree/7.8/logstash/examples/elasticsearch/values.yaml

+ 56 - 0
loki/loki-stack/charts/logstash/examples/elasticsearch/test/goss.yaml

@@ -0,0 +1,56 @@
+mount:
+  /usr/share/logstash/data:
+    exists: true
+  /usr/share/logstash/config/logstash.yml:
+    exists: true
+    opts:
+      - ro
+  /usr/share/logstash/pipeline/uptime.conf:
+    exists: true
+    opts:
+      - ro
+
+user:
+  logstash:
+    exists: true
+    uid: 1000
+    gid: 1000
+
+http:
+  http://localhost:9600?pretty:
+    status: 200
+    timeout: 2000
+    body:
+      - '"host" : "helm-logstash-elasticsearch-logstash-0"'
+      - '"version" : "7.8.1"'
+      - '"http_address" : "0.0.0.0:9600"'
+      - '"name" : "helm-logstash-elasticsearch-logstash-0"'
+      - '"status" : "green"'
+      - '"workers" : 1'
+      - '"batch_size" : 125'
+      - '"batch_delay" : 50'
+  http://elasticsearch-master:9200/_cat/indices:
+    status: 200
+    timeout: 2000
+    body:
+      - 'logstash'
+
+file:
+  /usr/share/logstash/config/logstash.yml:
+    exists: true
+    mode: "0644"
+    owner: root
+    group: logstash
+    filetype: file
+    contains:
+      - 'http.host: 0.0.0.0'
+      - 'xpack.monitoring.enabled: false'
+  /usr/share/logstash/pipeline/uptime.conf:
+    exists: true
+    mode: "0644"
+    owner: root
+    group: logstash
+    filetype: file
+    contains:
+      - 'input { exec { command => "uptime" interval => 30 } }'
+      - 'output { elasticsearch { hosts => ["http://elasticsearch-master:9200"] index => "logstash" } }'

+ 12 - 0
loki/loki-stack/charts/logstash/examples/elasticsearch/values.yaml

@@ -0,0 +1,12 @@
+persistence:
+  enabled: true
+
+logstashConfig:
+  logstash.yml: |
+    http.host: 0.0.0.0
+    xpack.monitoring.enabled: false
+
+logstashPipeline:
+  uptime.conf: |
+    input { exec { command => "uptime" interval => 30 } }
+    output { elasticsearch { hosts => ["http://elasticsearch-master:9200"] index => "logstash" } }

+ 16 - 0
loki/loki-stack/charts/logstash/examples/oss/Makefile

@@ -0,0 +1,16 @@
+default: test
+
+include ../../../helpers/examples.mk
+
+RELEASE := helm-logstash-oss
+
+install:
+	helm upgrade --wait --timeout=900 --install $(RELEASE)  --values ./values.yaml ../../
+
+restart:
+	helm upgrade --set terminationGracePeriod=121 --wait --timeout=900 --install $(RELEASE) ../../
+
+test: install goss
+
+purge:
+	helm del --purge $(RELEASE)

+ 17 - 0
loki/loki-stack/charts/logstash/examples/oss/README.md

@@ -0,0 +1,17 @@
+# OSS
+
+This example deploy Logstash 7.8.1 using [Logstash OSS][] version.
+
+
+## Usage
+
+* Deploy Logstash chart with the default values: `make install`
+
+
+## Testing
+
+You can also run [goss integration tests][] using `make test`
+
+
+[logstash oss]: https://www.elastic.co/downloads/logstash-oss
+[goss integration tests]: https://github.com/elastic/helm-charts/tree/7.8/logstash/examples/oss/test/goss.yaml

+ 42 - 0
loki/loki-stack/charts/logstash/examples/oss/test/goss.yaml

@@ -0,0 +1,42 @@
+user:
+  logstash:
+    exists: true
+    uid: 1000
+    gid: 1000
+
+http:
+  http://localhost:9600?pretty:
+    status: 200
+    timeout: 2000
+    body:
+      - '"host" : "helm-logstash-oss-logstash-0"'
+      - '"version" : "7.8.1"'
+      - '"http_address" : "0.0.0.0:9600"'
+      - '"name" : "helm-logstash-oss-logstash-0"'
+      - '"status" : "green"'
+      - '"workers" : 1'
+      - '"batch_size" : 125'
+      - '"batch_delay" : 50'
+
+file:
+  /usr/share/logstash/config/logstash.yml:
+    exists: true
+    mode: "0644"
+    owner: logstash
+    group: root
+    filetype: file
+    contains:
+      - 'http.host: "0.0.0.0"'
+  /usr/share/logstash/pipeline/logstash.conf:
+    exists: true
+    mode: "0644"
+    owner: logstash
+    group: root
+    filetype: file
+    contains:
+      - 'input {'
+      - 'beats {'
+      - 'port => 5044'
+      - 'output {'
+      - 'stdout {'
+      - 'codec => rubydebug'

+ 2 - 0
loki/loki-stack/charts/logstash/examples/oss/values.yaml

@@ -0,0 +1,2 @@
+---
+image: "docker.elastic.co/logstash/logstash-oss"

+ 14 - 0
loki/loki-stack/charts/logstash/examples/security/Makefile

@@ -0,0 +1,14 @@
+default: test
+
+include ../../../helpers/examples.mk
+
+RELEASE := helm-logstash-security
+
+install:
+	helm upgrade --wait --timeout=900 --install $(RELEASE) --values values.yaml ../../
+
+test: install goss
+
+purge:
+	helm del --purge $(RELEASE)
+	kubectl delete $$(kubectl get pvc -l release=$(RELEASE) -o name)

+ 28 - 0
loki/loki-stack/charts/logstash/examples/security/README.md

@@ -0,0 +1,28 @@
+# Security
+
+This example deploy Logstash 7.8.1 which connects to Elasticsearch using TLS
+(see [values][]).
+
+
+## Usage
+
+* Deploy [Elasticsearch Helm chart with security][].
+
+* Deploy Logstash chart: `make install`
+
+* You can now setup a port forward to query Logstash indices:
+
+  ```
+  kubectl port-forward svc/elasticsearch-master 9200
+  curl localhost:9200/_cat/indices
+  ```
+
+
+## Testing
+
+You can also run [goss integration tests][] using `make test`
+
+
+[elasticsearch helm chart with security]: https://github.com/elastic/helm-charts/tree/master/elasticsearch/examples/security/
+[goss integration tests]: https://github.com/elastic/helm-charts/tree/master/logstash/examples/security/test/goss.yaml
+[values]: https://github.com/elastic/helm-charts/tree/master/logstash/examples/security/values.yaml

Some files were not shown because too many files changed in this diff