Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions bundle/manifests/scylla.scylladb.com_scylladbmonitorings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,11 @@ spec:
maxItems: 1
type: array
exposeOptions:
description: exposeOptions specifies options for exposing
Grafana UI.
description: |-
exposeOptions specifies options for exposing Grafana UI.

Deprecated: This field will be removed in the next version of the API. Support for it will be removed in the future
versions of the operator. We recommend managing your own Ingress or HTTPRoute resources to expose Grafana if needed.
properties:
webInterface:
description: webInterface specifies expose options for
Expand Down Expand Up @@ -1239,8 +1242,11 @@ spec:
instance, if any.
properties:
exposeOptions:
description: exposeOptions specifies options for exposing
Prometheus UI.
description: |-
exposeOptions specifies options for exposing Prometheus UI.

Deprecated: This field will be removed in the next version of the API. Support for it will be removed in the future
versions of the operator. We recommend managing your own Ingress or HTTPRoute resources to expose Prometheus if needed.
properties:
webInterface:
description: webInterface specifies expose options for
Expand Down
12 changes: 10 additions & 2 deletions deploy/operator.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

89 changes: 48 additions & 41 deletions docs/source/management/monitoring/exposing-grafana.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Exposing Grafana

This guide shows how to expose Grafana deployed by `ScyllaDBMonitoring` using an Ingress resource.
This guide shows how to expose Grafana deployed by `ScyllaDBMonitoring` using an `Ingress` resource.

For accessing Grafana service from outside the Kubernetes cluster we recommend using an Ingress, although there are many other ways to do so.
When using Ingress, what matters is to direct your packets to the ingress controller Service/Pods and have the correct TLS SNI field set by the caller when reaching out to the service, so it is routed properly, and your client can successfully validate the grafana serving certificate.
This is easier when you are using a real DNS domain that resolves to your Ingress controller's IP address but most clients and tools allow setting the SNI field manually.
:::{note}
For accessing the Grafana service from outside the Kubernetes cluster we document using an `Ingress`, although there are other options like an `HTTPRoute` from the Gateway API.
Use whatever method fits your use case best.
:::

## Prerequisites

This assumes you have already deployed `ScyllaDBMonitoring` in your cluster. If you haven't done so, please follow the [ScyllaDB Monitoring setup](setup.md) guide first.
This assumes that you have already deployed a `ScyllaDBMonitoring` in your cluster. If you haven't done so, please follow the [ScyllaDB Monitoring setup](setup.md) guide first.

In the example below we're using HAProxy Ingress Controller. You can deploy it in your Kubernetes cluster using the provided
third-party example. If you already have it (or other Ingress Controller) deployed in your cluster, you can skip the below steps.
In the example below we're using the HAProxy Ingress Controller. You can deploy it in your Kubernetes cluster using the provided
third-party example. If you already have it (or another Ingress Controller) deployed in your cluster, you can skip the below steps.

### Install HAProxy Ingress

Expand All @@ -26,65 +27,71 @@ Wait for HAProxy Ingress to roll out:
kubectl -n haproxy-ingress rollout status --timeout=5m deployments.apps/haproxy-ingress
```

## Get Grafana credentials
## Expose Grafana using Ingress

To access Grafana, you first need to collect the serving CA and the credentials.
{{productName}} creates a `ClusterIP` Service named `<scyllaDBMonitoringName>-grafana` for each `ScyllaDBMonitoring`.
Grafana serves TLS using a self-signed certificate that's signed by a CA stored in a Secret named `<scyllaDBMonitoringName>-grafana-serving-ca` by default.

```console
$ GRAFANA_SERVING_CERT="$( kubectl -n scylla get secret/example-grafana-serving-ca --template '{{ index .data "tls.crt" }}' | base64 -d )"
$ GRAFANA_USER="$( kubectl -n scylla get secret/example-grafana-admin-credentials --template '{{ index .data "username" }}' | base64 -d )"
$ GRAFANA_PASSWORD="$( kubectl -n scylla get secret/example-grafana-admin-credentials --template '{{ index .data "password" }}' | base64 -d )"
```
:::{note}
You can use your own serving certificate by setting `ScyllaDBMonitoring`'s `spec.components.grafana.servingCertSecretName` field.
:::

Create the following Ingress resource that will route requests with `test-grafana.test.svc.cluster.local` SNI to the Grafana:

## Connect through Ingress using a resolvable domain
:::{literalinclude} ../../../../examples/monitoring/v1alpha1/grafana-haproxy.ingress.yaml
:language: yaml
:linenos:
:::

In production clusters, the Ingress controller and appropriate DNS records should be set up already. Often there is already a generic wildcard record like `*.app.mydomain` pointing to the Ingress controller's external IP. For custom service domains, it is usually a CNAME pointing to the Ingress controller's A record.
You can apply the above manifest using `kubectl`:

:::{note}
The ScyllaDBMonitoring example creates an Ingress object with `test-grafana.test.svc.cluster.local` DNS domain that you should adjust to your domain. Below examples use `example-grafana.apps.mydomain`.
:::{code-block} shell
:substitutions:
kubectl apply -n scylla --server-side -f=https://raw.githubusercontent.com/{{repository}}/{{revision}}/examples/monitoring/v1alpha1/grafana-haproxy.ingress.yaml
:::

:::{note}
To test a resolvable domain from your machine without creating DNS records, you can adjust `/etc/hosts` or similar.
In production, you should make sure that the Ingress controller properly terminates TLS using certificates issued by a trusted CA,
e.g. using [cert-manager](https://cert-manager.io/docs/) to automatically issue and renew certificates from Let's Encrypt.
:::

```console
$ curl --fail -s -o /dev/null -w '%{http_code}' -L --cacert <( echo "${GRAFANA_SERVING_CERT}" ) "https://example-grafana.apps.mydomain" --user "${GRAFANA_USER}:${GRAFANA_PASSWORD}"
200
```

## Connect through Ingress using an unresolvable domain
## Verify connection

To connect to an Ingress without a resolvable domain you first need to find out your Ingress controller's IP that can be resolved externally. Again, there are many ways to do so beyond the below examples.
### Get Grafana credentials

Unless stated otherwise, we assume your Ingress is running on port 443.
To access Grafana, you need to collect the credentials.

```console
$ INGRESS_PORT=443
GRAFANA_USER="$( kubectl -n scylla get secret/example-grafana-admin-credentials --template '{{ index .data "username" }}' | base64 -d )"
GRAFANA_PASSWORD="$( kubectl -n scylla get secret/example-grafana-admin-credentials --template '{{ index .data "password" }}' | base64 -d )"
```

### Variants
### Get Ingress IP and Port

#### Ingress ExternalIP

When you are running in a real cluster there is usually a cloud LoadBalancer or a bare metal alternative providing you with an externally reachable IP address.
If your cluster supports `LoadBalancer` services, your Ingress should be assigned an external IP address. You can get it by running:

```console
$ INGRESS_IP="$( kubectl -n=haproxy-ingress get service/haproxy-ingress --template='{{ ( index .status.loadBalancer.ingress 0 ).ip }}' )"
INGRESS_IP="$( kubectl -n haproxy-ingress get svc haproxy-ingress --template '{{ index .status.loadBalancer.ingress 0 "ip" }}' )"
INGRESS_PORT="443"
```

#### Ingress NodePort

NodePort is slightly less convenient, but it's available in development clusters as well.
Otherwise, if you're running this locally (e.g. using `minikube` or `kind`), you can port-forward the Ingress controller service to your local machine:

```console
$ INGRESS_IP="$( kubectl get nodes --template='{{ $internal_ip := "" }}{{ $external_ip := "" }}{{ range ( index .items 0 ).status.addresses }}{{ if eq .type "InternalIP" }}{{ $internal_ip = .address }}{{ else if eq .type "ExternalIP" }}{{ $external_ip = .address }}{{ end }}{{ end }}{{ if $external_ip }}{{ $external_ip }}{{ else }}{{ $internal_ip }}{{ end }}' )"
$ INGRESS_PORT="$( kubectl -n=haproxy-ingress get services/haproxy-ingress --template='{{ range .spec.ports }}{{ if eq .port 443 }}{{ .nodePort }}{{ end }}{{ end }}' )"
kubectl -n haproxy-ingress port-forward svc/haproxy-ingress 8443:443 &
INGRESS_IP="127.0.0.1"
INGRESS_PORT="8443"
```

#### Connection
### Test connection

Now, you can verify the connection to the Grafana through the Ingress.

```console
$ curl --fail -s -o /dev/null -w '%{http_code}' -L --cacert <( echo "${GRAFANA_SERVING_CERT}" ) "https://test-grafana.test.svc.cluster.local:${INGRESS_PORT}" --resolve "test-grafana.test.svc.cluster.local:${INGRESS_PORT}:${INGRESS_IP}" --user "${GRAFANA_USER}:${GRAFANA_PASSWORD}"
200
curl --fail -s -o /dev/null -w '%{http_code}' -k \
--resolve "test-grafana.test.svc.cluster.local:${INGRESS_PORT}:${INGRESS_IP}" \
--user "${GRAFANA_USER}:${GRAFANA_PASSWORD}" \
"https://test-grafana.test.svc.cluster.local:${INGRESS_PORT}/"
```

You should see `200` as the output, indicating a successful connection.
24 changes: 24 additions & 0 deletions examples/monitoring/v1alpha1/grafana-haproxy.ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "example-grafana"
namespace: "scylla"
annotations:
haproxy.org/server-ssl: "true" # HA Proxy should use TLS when connecting to the backend.
haproxy.org/server-ca: "default/example-grafana-serving-ca" # HA Proxy should trust the Grafana serving certificate signed by this CA.
spec:
ingressClassName: haproxy
tls:
- hosts:
- "test-grafana.test.svc.cluster.local"
rules:
- host: "test-grafana.test.svc.cluster.local"
http:
paths:
- backend:
service:
name: "example-grafana"
port:
number: 3000
path: /
pathType: Prefix
9 changes: 0 additions & 9 deletions examples/monitoring/v1alpha1/scylladbmonitoring.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,3 @@ spec:
key: scylla-operator.scylladb.com/dedicated
operator: Equal
value: scyllaclusters
grafana:
exposeOptions:
webInterface:
ingress:
ingressClassName: haproxy
dnsDomains:
- example-grafana.test.svc.cluster.local
annotations:
haproxy-ingress.github.io/ssl-passthrough: "true"
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ spec:
maxItems: 1
type: array
exposeOptions:
description: exposeOptions specifies options for exposing Grafana UI.
description: |-
exposeOptions specifies options for exposing Grafana UI.

Deprecated: This field will be removed in the next version of the API. Support for it will be removed in the future
versions of the operator. We recommend managing your own Ingress or HTTPRoute resources to expose Grafana if needed.
properties:
webInterface:
description: webInterface specifies expose options for the user web interface.
Expand Down Expand Up @@ -1167,7 +1171,11 @@ spec:
description: prometheus holds configuration for the prometheus instance, if any.
properties:
exposeOptions:
description: exposeOptions specifies options for exposing Prometheus UI.
description: |-
exposeOptions specifies options for exposing Prometheus UI.

Deprecated: This field will be removed in the next version of the API. Support for it will be removed in the future
versions of the operator. We recommend managing your own Ingress or HTTPRoute resources to expose Prometheus if needed.
properties:
webInterface:
description: webInterface specifies expose options for the user web interface.
Expand Down
8 changes: 8 additions & 0 deletions pkg/api/scylla/v1alpha1/types_monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ type PrometheusSpec struct {
Resources corev1.ResourceRequirements `json:"resources"`

// exposeOptions specifies options for exposing Prometheus UI.
//
// Deprecated: This field will be removed in the next version of the API. Support for it will be removed in the future
// versions of the operator. We recommend managing your own Ingress or HTTPRoute resources to expose Prometheus if needed.
//
// +optional
ExposeOptions *PrometheusExposeOptions `json:"exposeOptions,omitempty"`

Expand All @@ -143,6 +147,10 @@ type GrafanaSpec struct {
Resources corev1.ResourceRequirements `json:"resources"`

// exposeOptions specifies options for exposing Grafana UI.
//
// Deprecated: This field will be removed in the next version of the API. Support for it will be removed in the future
// versions of the operator. We recommend managing your own Ingress or HTTPRoute resources to expose Grafana if needed.
//
// +optional
ExposeOptions *GrafanaExposeOptions `json:"exposeOptions,omitempty"`

Expand Down