diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1dec617..2f9a79e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -72,4 +72,4 @@ jobs: uses: helm/kind-action@v1.12.0 - name: Run chart-testing (install) if: steps.list-changed.outputs.changed == 'true' - run: ct install --target-branch ${{ github.event.repository.default_branch }} --helm-extra-set-args="--set EF_OUTPUT_STDOUT_ENABLE=true" + run: ct install --target-branch ${{ github.event.repository.default_branch }} diff --git a/README.md b/README.md index dec8bd0..6f3fb76 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ Hint, use `kubectl diff` before upgrade to spot potential issues. ```sh helm repo update rm -rf helm_rendered -helm template -n elastiflow -f examples/flow_os_simple_gke/values.yaml --output-dir helm_rendered netobserv elastiflow/netobserv --version netobserv-0.5.0 -kubectl diff -R -f helm_rendered/ +helm template -n elastiflow -f ${PATH_TO_VALUES} --output-dir helm_rendered netobserv netobserv/netobserv --version netobserv-0.5.0 +kubectl diff -R -f helm_rendered ``` ### License Setup @@ -86,7 +86,7 @@ license: Then make sure to use helm's `set` option to configure the license key when installing the chart. For example: ```sh -helm install netobserv elastiflow/netobserv \ +helm install netobserv netobserv/netobserv-flow \ --set license.licenseKey="licensekeygoeshere" ``` diff --git a/charts/netobserv-flow/README.md b/charts/netobserv-flow/README.md index b5b4e0c..203dd69 100644 --- a/charts/netobserv-flow/README.md +++ b/charts/netobserv-flow/README.md @@ -26,9 +26,9 @@ The ElastiFlow Unified Flow Collector receives, decodes, transforms, normalizes, ## Installation ```sh -helm repo add elastiflow https://elastiflow.github.io/helm-chart-netobserv/ +helm repo add netobserv https://elastiflow.github.io/helm-chart-netobserv/ helm repo update -helm install netobserv elastiflow/netobserv +helm install netobserv netobserv/netobserv ``` ## Configuration @@ -45,7 +45,7 @@ license: Then make sure to use helm's `set` option to configure the license key when installing the chart. For example: ```sh -helm install netobserv elastiflow/netobserv \ +helm install netobserv netobserv/netobserv \ --set license.licenseKey="licensekeygoeshere" ``` diff --git a/charts/netobserv-flow/ci/simple-values.yaml b/charts/netobserv-flow/ci/simple-values.yaml new file mode 100644 index 0000000..6088109 --- /dev/null +++ b/charts/netobserv-flow/ci/simple-values.yaml @@ -0,0 +1,5 @@ +env: + - name: EF_LICENSE_ACCEPTED + value: "true" + - name: EF_OUTPUT_STDOUT_ENABLE + value: "false" diff --git a/charts/netobserv-flow/values.yaml b/charts/netobserv-flow/values.yaml index 9396997..c2ca6d6 100644 --- a/charts/netobserv-flow/values.yaml +++ b/charts/netobserv-flow/values.yaml @@ -17,7 +17,7 @@ image: env: - name: EF_LICENSE_ACCEPTED - value: 'true' + value: 'false' # Additional information for available environment variables can be found via # the ElastiFlow documentation: https://docs.elastiflow.com/docs/config_ref diff --git a/examples/flow_os_simple_gke/README.md b/examples/flow_os_simple_gke/README.md deleted file mode 100644 index 7b0645d..0000000 --- a/examples/flow_os_simple_gke/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# NetObserv Flow with OpenSearch - -- [NetObserv Flow with OpenSearch](#netobserv-flow-with-opensearch) - - [Overview](#overview) - - [Install](#install) - - [Access](#access) - - [Hints](#hints) - -## Overview - -This example deploys NetObserv Flow with OpenSearch as the data platform in a GCP GKE cluster. -This example is intended only for demonstration, testing, or proof-of-concept use, since OpenSearch is deployed in a single-node mode. - -Notes on the example deployment: - -- GKE [node auto-provisioning](https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-provisioning) must be enabled. -- Namespace used in the example: `elastiflow` -- A GKE internal load balancer is used for the OpenSearch Dashboard ingress. This example also assumes you can access internal GCP subnets via a VPN. -- Spot instances are used, please tweak affinity and tolerations in the `values.yaml` if needed. - -## Install - -```sh -helm repo add netobserv https://elastiflow.github.io/helm-chart-netobserv/ -helm repo add opensearch https://opensearch-project.github.io/helm-charts/ -helm repo update -helm dependency build elastiflow/netobserv-os -kubectl create namespace elastiflow -helm upgrade -i --wait --timeout 15m -n elastiflow -f examples/flow_os_simple_gke/values.yaml netobserv elastiflow/netobserv-os -``` - -## Access - -First, get the OpenSearch Dashboards address: - -```sh -kubectl get ingress elastiflow-os-dashboards -o=jsonpath='{.status.loadBalancer.ingress[0].ip}' -``` - -Now you can navigate to the obtained IP in your browser (assuming you have access to the private network), using `admin`/`Elast1flow!` as the user/password. Select "global tenant", and explore the data. - -## Hints - -To render and diff Helm templates to Kubernetes manifests, run: - -```sh -rm -rf helm_rendered; helm template -n elastiflow -f examples/flow_os_simple_gke/values.yaml --output-dir helm_rendered netobserv elastiflow/netobserv-os - -# Diff with existing K8s resources -kubectl diff -R -f helm_rendered/ -``` diff --git a/examples/flow_os_simple_gke_gw/README.md b/examples/flow_os_simple_gke_gw/README.md new file mode 100644 index 0000000..c234d9a --- /dev/null +++ b/examples/flow_os_simple_gke_gw/README.md @@ -0,0 +1,80 @@ +# NetObserv Flow with OpenSearch using K8s (GKE) Gateway + +- [NetObserv Flow with OpenSearch using K8s Gateway](#netobserv-flow-with-opensearch-using-k8s-gateway) + - [Overview](#overview) + - [Install](#install) + - [Access Dashboards](#access-dashboards) + - [Hints](#hints) + +## Overview + +This example deploys NetObserv Flow with OpenSearch as the data platform in a GCP GKE cluster with API and OTel gRPC inputs exposed. +This example is intended only for demonstration, testing, or proof-of-concept use, since OpenSearch is deployed in a single-node mode. + +Notes on the example deployment: + +- This example assumes you can access internal GCP subnets via a VPN. +- Namespace used in the example: `elastiflow`. +- GKE [node auto-provisioning](https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-provisioning) must be enabled. +- Gateway API is used to route the traffic to the NetObserv Collector so it must be enabled on the GKE custer - [doc](https://cloud.google.com/kubernetes-engine/docs/how-to/deploying-gateways#enable-gateway). +- TLS: + - GCP Load Balancer (ingress) needs the backend with TLS enabled since OTlp input uses gRPC, that is why a self-signed certificate is used (validity `Not After : Sep 24 10:48:37 2035 GMT`) + - In order to enable gRPC between client and GCP Load Balancer certificate is also required, same self-signed certificate is used. + - HTTP (port `80`) is completely disabled on the GCP Load Balancer that is used for the collector (gRPC, REST) +- A GKE internal load balancer is used for the OpenSearch Dashboard ingress. +- Spot instances are used, please tweak affinity and tolerations in the `values.yaml` if needed. + +## Install + +- Add Helm charts and Deploy + + ```sh + helm repo add netobserv https://elastiflow.github.io/helm-chart-netobserv/ + helm repo add opensearch https://opensearch-project.github.io/helm-charts/ + helm repo update + kubectl create namespace elastiflow + helm upgrade -i --wait --timeout 15m -n elastiflow -f examples/flow_os_simple_gke_gw/values.yaml netobserv netobserv/netobserv-os + ``` + +- Get the GCP Load Balancer IP (API/OTLP endpoints address) by running following command: + + ```sh + kubectl get gtw netobserv-flow -o=jsonpath='{.status.addresses[0].value}' + ``` + +- Test the API/OTLP endpoints work as expected: + + ```sh + export NETOBSERV_LB_ADDR=$(kubectl get gtw netobserv-flow -o=jsonpath='{.status.addresses[0].value}') + curl -k "https://${NETOBSERV_LB_ADDR}/readyz" + # 200 - Ready! + + curl -k "https://${NETOBSERV_LB_ADDR}/api" + # 404 page not found + + grpcurl -insecure ${NETOBSERV_LB_ADDR}:443 list + # grpc.reflection.v1.ServerReflection + # grpc.reflection.v1alpha.ServerReflection + # opentelemetry.proto.collector.trace.v1.TraceService + ``` + +## Access Dashboards + +First, get the OpenSearch Dashboards address: + +```sh +kubectl get ingress elastiflow-os-dashboards -o=jsonpath='{.status.loadBalancer.ingress[0].ip}' +``` + +Now you can navigate to the obtained IP in your browser (assuming you have access to the private network), using `admin`/`Elast1flow!` as the user/password. Select "global tenant", and explore the data. + +## Hints + +To render and diff Helm templates to Kubernetes manifests, run: + +```sh +rm -rf helm_rendered; helm template -n elastiflow -f examples/flow_os_simple_gke_gw/values.yaml --output-dir helm_rendered netobserv netobserv/netobserv-os + +# Diff with existing K8s resources +kubectl diff -R -f helm_rendered/ +``` diff --git a/examples/flow_os_simple_gke/values.yaml b/examples/flow_os_simple_gke_gw/values.yaml similarity index 64% rename from examples/flow_os_simple_gke/values.yaml rename to examples/flow_os_simple_gke_gw/values.yaml index 9d5d55b..4cfc53f 100644 --- a/examples/flow_os_simple_gke/values.yaml +++ b/examples/flow_os_simple_gke_gw/values.yaml @@ -7,6 +7,18 @@ netobserv-flow: value: "true" - name: EF_OUTPUT_OPENSEARCH_INDEX_TEMPLATE_REPLICAS value: "0" + - name: EF_INPUT_OTLP_TRACE_GRPC_ENABLE + value: "true" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_ENABLE + value: "true" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_CERT_FILE + value: "/etc/ssl/netobserv/tls.crt" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_KEY_FILE + value: "/etc/ssl/netobserv/tls.key" + - name: EF_INPUT_OTLP_HEALTH_GRPC_ENABLE + value: "true" + - name: EF_INPUT_OTLP_HEALTH_GRPC_ADDR_PORT + value: "4316" - name: EF_INPUT_FLOW_BENCHMARK_ENABLE value: "false" # `false` is the default, keeping for ease of updating for testing - name: EF_OUTPUT_STDOUT_ENABLE @@ -52,47 +64,122 @@ netobserv-flow: matchExpressions: - key: app.kubernetes.io/name operator: In - values: [opensearch, netobserv] + values: [opensearch] + + ports: + - name: api + containerPort: 8080 + protocol: TCP + - name: otlp-grpc-hlth + containerPort: 4316 + protocol: TCP + - name: otlp-grpc + containerPort: 4317 + protocol: TCP service: - annotations: - cloud.google.com/neg: '{"ingress": true}' - cloud.google.com/app-protocols: '{"api":"HTTP"}' ports: - - port: 8080 + - name: api + port: 8080 targetPort: 8080 + appProtocol: HTTP + - name: otlp-grpc protocol: TCP - name: api - - # TODO: Test ingress - # ingress: - # enabled: true - # annotations: - # kubernetes.io/ingress.class: "gce-internal" - # rules: - # - host: your-store.example - # http: - # paths: - # - path: /products - # backend: - # service: - # name: netobserv - # port: - # name: api + port: 4317 + targetPort: 4317 + appProtocol: HTTP2 + + gateway: + enabled: true + className: gke-l7-rilb + listeners: + - name: https + protocol: HTTPS + port: 443 + tls: + mode: Terminate + certificateRefs: + - kind: Secret + group: "" + name: netobserv-tls + allowedRoutes: + kinds: + - kind: HTTPRoute + + httpRoutes: + - name: main + rules: + - backendRefs: + - name: '{{ include "netobserv.fullname" $ }}' + port: 8080 + - matches: + - headers: + - name: "content-type" + value: "application/grpc" + backendRefs: + - name: '{{ include "netobserv.fullname" $ }}' + port: 4317 outputOpenSearch: enable: true - addresses: opensearch-cluster-master.elastiflow.svc.gke-main-a.us-east1:9200 + addresses: opensearch-cluster-master.elastiflow.svc:9200 password: Elast1flow! # Insecure tls: enable: true skipVerification: true - dashboards: provision: true - dashboards_url: http://elastiflow-os-dashboards.elastiflow.svc.gke-main-a.us-east1:5601 + dashboards_url: http://elastiflow-os-dashboards.elastiflow.svc:5601 + + extraVolumes: + - name: netobserv-tls + secret: + secretName: netobserv-tls + extraVolumeMounts: + - name: netobserv-tls + mountPath: /etc/ssl/netobserv/ extraObjects: + # Needed by GKE Gateway controller to tweak healthchecks + - | + apiVersion: networking.gke.io/v1 + kind: HealthCheckPolicy + metadata: + name: '{{ include "netobserv.fullname" . }}-api' + labels: + {{- include "netobserv.labels" . | nindent 4 }} + spec: + default: + healthyThreshold: 2 + unhealthyThreshold: 3 + config: + type: HTTP + httpHealthCheck: + portSpecification: USE_FIXED_PORT + port: 8080 + requestPath: /readyz + # Attach to a Service in the cluster. + targetRef: + group: "" + kind: Service + name: '{{ include "netobserv.fullname" . }}' + # Needed by GKE Gateway controller to disable logging + - | + apiVersion: networking.gke.io/v1 + kind: GCPBackendPolicy + metadata: + name: '{{ include "netobserv.fullname" . }}' + labels: + {{- include "netobserv.labels" . | nindent 4 }} + spec: + default: + logging: + enabled: false + # Attach to a Service in the cluster. + targetRef: + group: "" + kind: Service + name: '{{ include "netobserv.fullname" . }}' - | apiVersion: v1 kind: Secret @@ -127,8 +214,8 @@ opensearch: enabled: true extraEnvs: - - name: OPENSEARCH_INITIAL_ADMIN_PASSWORD - value: Elast1flow! # Insecure + - name: OPENSEARCH_INITIAL_ADMIN_PASSWORD + value: Elast1flow! # Insecure tolerations: - key: k8s.elastiflow.io/role @@ -157,7 +244,7 @@ opensearch: opensearch-dashboards: enabled: true fullnameOverride: elastiflow-os-dashboards - opensearchHosts: https://opensearch-cluster-master.elastiflow.svc.gke-main-a.us-east1:9200 + opensearchHosts: https://opensearch-cluster-master.elastiflow.svc:9200 resources: requests: cpu: "1000m" @@ -227,6 +314,7 @@ opensearch-dashboards: {{- toYaml . | nindent 4 }} {{- end }} annotations: + # GKE still use the annotation: https://cloud.google.com/kubernetes-engine/docs/concepts/ingress#deprecated_annotation kubernetes.io/ingress.class: "gce-internal" spec: defaultBackend: @@ -234,14 +322,3 @@ opensearch-dashboards: name: '{{ template "opensearch-dashboards.fullname" . }}' port: number: {{ .Values.service.port }} - rules: - - host: "chart-example.local" - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: '{{ template "opensearch-dashboards.fullname" . }}' - port: - number: {{ .Values.service.port }} diff --git a/examples/flow_os_simple_gke_ingress/README.md b/examples/flow_os_simple_gke_ingress/README.md new file mode 100644 index 0000000..7f6a31f --- /dev/null +++ b/examples/flow_os_simple_gke_ingress/README.md @@ -0,0 +1,79 @@ +# NetObserv Flow with OpenSearch using K8s (GKE) Ingress + +- [NetObserv Flow with OpenSearch using K8s (GKE) Ingress](#netobserv-flow-with-opensearch-using-k8s-gke-ingress) + - [Overview](#overview) + - [Install](#install) + - [Access Dashboards](#access-dashboards) + - [Hints](#hints) + +## Overview + +This example deploys NetObserv Flow with OpenSearch as the data platform in a GCP GKE cluster with API and OTel gRPC inputs exposed. +This example is intended only for demonstration, testing, or proof-of-concept use, since OpenSearch is deployed in a single-node mode. + +Notes on the example deployment: + +- This example also assumes you can access internal GCP subnets via a VPN. +- Namespace used in the example: `elastiflow`. +- GKE [node auto-provisioning](https://cloud.google.com/kubernetes-engine/docs/how-to/node-auto-provisioning) must be enabled. +- TLS: + - GCP Load Balancer (ingress) needs the backend with TLS enabled since OTlp input uses gRPC, that is why a self-signed certificate is used (validity `Not After : Sep 24 10:48:37 2035 GMT`) + - In order to enable gRPC between client and GCP Load Balancer certificate is also required, same self-signed certificate is used. + - HTTP (port `80`) is completely disabled on the GCP Load Balancer that is used for the collector (gRPC, REST) +- A GKE internal load balancer is used for the OpenSearch Dashboard ingress. +- Spot instances are used, please tweak affinity and tolerations in the `values.yaml` if needed. + +## Install + +- Add Helm charts and Deploy + + ```sh + helm repo add netobserv https://elastiflow.github.io/helm-chart-netobserv/ + helm repo add opensearch https://opensearch-project.github.io/helm-charts/ + helm repo update + kubectl create namespace elastiflow + helm upgrade -i --wait --timeout 15m -n elastiflow -f examples/flow_os_simple_gke_ingress/values.yaml netobserv netobserv/netobserv-os + ``` + +- Get the GCP Load Balancer IP (API/OTLP endpoints address) by running following command: + + ```sh + kubectl get ingress netobserv-flow -o=jsonpath='{.status.loadBalancer.ingress[0].ip}' + ``` + +- Test the API/OTLP endpoints work as expected: + + ```sh + export NETOBSERV_LB_ADDR=$(kubectl get ingress netobserv-flow -o=jsonpath='{.status.loadBalancer.ingress[0].ip}') + curl -k "https://${NETOBSERV_LB_ADDR}/readyz" + # 200 - Ready! + + curl -k "https://${NETOBSERV_LB_ADDR}/api" + # 404 page not found + + grpcurl -insecure ${NETOBSERV_LB_ADDR}:443 list + # grpc.reflection.v1.ServerReflection + # grpc.reflection.v1alpha.ServerReflection + # opentelemetry.proto.collector.trace.v1.TraceService + ``` + +## Access Dashboards + +First, get the OpenSearch Dashboards address: + +```sh +kubectl get ingress elastiflow-os-dashboards -o=jsonpath='{.status.loadBalancer.ingress[0].ip}' +``` + +Now you can navigate to the obtained IP in your browser (assuming you have access to the private network), using `admin`/`Elast1flow!` as the user/password. Select "global tenant", and explore the data. + +## Hints + +To render and diff Helm templates to Kubernetes manifests, run: + +```sh +rm -rf helm_rendered; helm template -n elastiflow -f examples/flow_os_simple_gke_ingress/values.yaml --output-dir helm_rendered netobserv netobserv/netobserv-os + +# Diff with existing K8s resources +kubectl diff -R -f helm_rendered/ +``` diff --git a/examples/flow_os_simple_gke_ingress/values.yaml b/examples/flow_os_simple_gke_ingress/values.yaml new file mode 100644 index 0000000..7315bc1 --- /dev/null +++ b/examples/flow_os_simple_gke_ingress/values.yaml @@ -0,0 +1,321 @@ +netobserv-flow: + enabled: true + fullnameOverride: netobserv-flow + + env: + - name: EF_LICENSE_ACCEPTED + value: "true" + - name: EF_OUTPUT_OPENSEARCH_INDEX_TEMPLATE_REPLICAS + value: "0" + - name: EF_INPUT_OTLP_TRACE_GRPC_ENABLE + value: "true" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_ENABLE + value: "true" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_CERT_FILE + value: "/etc/ssl/netobserv/tls.crt" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_KEY_FILE + value: "/etc/ssl/netobserv/tls.key" + - name: EF_INPUT_OTLP_HEALTH_GRPC_ENABLE + value: "true" + - name: EF_INPUT_OTLP_HEALTH_GRPC_ADDR_PORT + value: "4316" + - name: EF_INPUT_FLOW_BENCHMARK_ENABLE + value: "false" # `false` is the default, keeping for ease of updating for testing + - name: EF_OUTPUT_STDOUT_ENABLE + value: "false" # `false` is the default, keeping for ease of updating for testing + + autoscaling: + enabled: true + minReplicas: 1 + maxReplicas: 1 + + tolerations: + - key: k8s.elastiflow.io/role + operator: Equal + value: elastiflow-spot + - key: cloud.google.com/gke-spot + operator: Equal + value: "true" + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: k8s.elastiflow.io/role + operator: In + values: + - elastiflow-spot + - key: "cloud.google.com/machine-family" + operator: "In" + values: ["e2"] + - key: "node.kubernetes.io/instance-type" + operator: "In" + # https://cloud.google.com/compute/vm-instance-pricing + values: ["e2-standard-2", "e2-standard-4"] + + # Discourage to colocate the collector with opensearch + topologySpreadConstraints: + - maxSkew: 1 + minDomains: 2 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: [opensearch] + + ports: + - name: api + containerPort: 8080 + protocol: TCP + - name: otlp-grpc-hlth + containerPort: 4316 + protocol: TCP + - name: otlp-grpc + containerPort: 4317 + protocol: TCP + + service: + annotations: + cloud.google.com/neg: '{"ingress": true}' + cloud.google.com/app-protocols: '{"api":"HTTP", "otlp-grpc":"HTTP2"}' + cloud.google.com/backend-config: '{"default": "netobserv"}' + ports: + - name: api + protocol: TCP + port: 8080 + targetPort: 8080 + - name: otlp-grpc + protocol: TCP + port: 4317 + targetPort: 4317 + + ingress: + enabled: true + annotations: + kubernetes.io/ingress.allow-http: "false" + # GKE still use the annotation: https://cloud.google.com/kubernetes-engine/docs/concepts/ingress#deprecated_annotation + kubernetes.io/ingress.class: "gce-internal" + tls: + - secretName: netobserv-tls + defaultBackend: + service: + port: + name: otlp-grpc + hosts: + - # host: chart-example.local # Uncomment if you have a DNS name for the ingress (Load Balancer) + paths: + - path: /readyz + pathType: ImplementationSpecific + backend: + service: + port: + name: api + - path: /api* + pathType: ImplementationSpecific + backend: + service: + port: + name: api + - path: /grpc.reflection.v1.ServerReflection + pathType: ImplementationSpecific + backend: + service: + port: + name: otlp-grpc + - path: /grpc.reflection.v1alpha.ServerReflection + pathType: ImplementationSpecific + backend: + service: + port: + name: otlp-grpc + - path: /opentelemetry.proto.collector.trace.v1.TraceService + pathType: ImplementationSpecific + backend: + service: + port: + name: otlp-grpc + + outputOpenSearch: + enable: true + addresses: opensearch-cluster-master.elastiflow.svc:9200 + password: Elast1flow! # Insecure + tls: + enable: true + skipVerification: true + dashboards: + provision: true + dashboards_url: http://elastiflow-os-dashboards.elastiflow.svc:5601 + + extraVolumes: + - name: netobserv-tls + secret: + secretName: netobserv-tls + extraVolumeMounts: + - name: netobserv-tls + mountPath: /etc/ssl/netobserv/ + + extraObjects: + # Needed by GKE Ingress controller + - | + apiVersion: cloud.google.com/v1 + kind: BackendConfig + metadata: + name: 'netobserv' + labels: + {{- include "netobserv.labels" . | nindent 4 }} + spec: + logging: + enable: true + # https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-configuration#direct_health + healthCheck: + checkIntervalSec: 60 + unhealthyThreshold: 2 + healthyThreshold: 3 + port: 8080 + type: HTTP + requestPath: /readyz + - | + apiVersion: v1 + kind: Secret + metadata: + name: netobserv-tls + labels: + {{- include "netobserv.labels" . | nindent 4 }} + type: kubernetes.io/tls + data: + tls.crt: {{ .Files.Get "tls/netobserv.crt" | b64enc }} + tls.key: {{ .Files.Get "tls/netobserv.key" | b64enc }} + +opensearch: + enabled: true + clusterName: elastiflow + fullnameOverride: "elastiflow-os" + singleNode: true + replicas: 1 + opensearchJavaOpts: "-Xmx15500M -Xmx15500M" + resources: + requests: + cpu: "6" + memory: 16384Mi + limits: + cpu: "6" + memory: 16384Mi + + persistence: + storageClass: standard-rwo + size: 50Gi + labels: + enabled: true + + extraEnvs: + - name: OPENSEARCH_INITIAL_ADMIN_PASSWORD + value: Elast1flow! # Insecure + + tolerations: + - key: k8s.elastiflow.io/role + operator: Equal + value: elastiflow-spot + - key: cloud.google.com/gke-spot + operator: Equal + value: "true" + + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: k8s.elastiflow.io/role + operator: In + values: + - elastiflow-spot + - key: "cloud.google.com/machine-family" + operator: "In" + values: ["e2"] + - key: "node.kubernetes.io/instance-type" + operator: "In" + # https://cloud.google.com/compute/vm-instance-pricing + values: ["e2-standard-2", "e2-standard-4", "e2-standard-8"] + +opensearch-dashboards: + enabled: true + fullnameOverride: elastiflow-os-dashboards + opensearchHosts: https://opensearch-cluster-master.elastiflow:9200 + resources: + requests: + cpu: "1000m" + memory: "768M" + limits: + cpu: "1000m" + memory: "768M" + + config: + ssl: + verificationMode: none + + tolerations: + - key: k8s.elastiflow.io/role + operator: Equal + value: elastiflow-spot + - key: cloud.google.com/gke-spot + operator: Equal + value: "true" + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: k8s.elastiflow.io/role + operator: In + values: + - elastiflow-spot + - key: "cloud.google.com/machine-family" + operator: "In" + values: ["e2"] + - key: "node.kubernetes.io/instance-type" + operator: "In" + # https://cloud.google.com/compute/vm-instance-pricing + values: ["e2-standard-2", "e2-standard-4", "e2-standard-8"] + + service: + annotations: + cloud.google.com/neg: '{"ingress": true}' + cloud.google.com/app-protocols: '{"http":"HTTP"}' + cloud.google.com/backend-config: '{"default": "elastiflow-os-dashboards"}' + + extraObjects: + # https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-configuration#direct_health + - apiVersion: cloud.google.com/v1 + kind: BackendConfig + metadata: + name: '{{ template "opensearch-dashboards.fullname" . }}' + spec: + healthCheck: + checkIntervalSec: 60 + unhealthyThreshold: 2 + healthyThreshold: 3 + port: 5601 + type: HTTP + requestPath: /app/login + # Adding ingress as extraObjects due to the lack of the `defaultBackend` in the original OpenSearch chart + - | + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: {{ template "opensearch-dashboards.fullname" . }} + labels: + {{- include "opensearch-dashboards.labels" . | nindent 4 }} + {{- with .Values.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + annotations: + # GKE still use the annotation: https://cloud.google.com/kubernetes-engine/docs/concepts/ingress#deprecated_annotation + kubernetes.io/ingress.class: "gce-internal" + spec: + defaultBackend: + service: + name: '{{ template "opensearch-dashboards.fullname" . }}' + port: + number: {{ .Values.service.port }} diff --git a/examples/flow_os_simple_svc/README.md b/examples/flow_os_simple_svc/README.md new file mode 100644 index 0000000..fe55d22 --- /dev/null +++ b/examples/flow_os_simple_svc/README.md @@ -0,0 +1,80 @@ +# NetObserv Flow with OpenSearch using K8s SVC + +- [NetObserv Flow with OpenSearch using K8s SVC](#netobserv-flow-with-opensearch-using-k8s-svc) + - [Overview](#overview) + - [Install](#install) + - [Access Dashboards](#access-dashboards) + - [Hints](#hints) + +## Overview + +This example deploys NetObserv Flow with OpenSearch as the data platform with API and OTel gRPC inputs exposed. Although local [Kind](https://kind.sigs.k8s.io/) was used for testing, any kubernetes cluster should work if nodes have sufficient resources and don't have any taints that should be tolerated (`tolerations` values may be used). +This example is intended only for demonstration, testing, or proof-of-concept use, since OpenSearch is deployed in a single-node mode. + +Notes on the example deployment: + +- [Location in the repository](https://github.com/elastiflow/mermin/tree/beta/docs/deployment/examples/netobserv_os_simple_svc) - `docs/deployment/examples/netobserv_os_simple_svc` +- Namespace used in the example: `elastiflow`. +- Allocatable resources needed (mCPU/MiB): + - OpenSearch `2000m`/`4000Mi` + - OpenSearch Dashboards `1000m`/`768M` + - NetObserv Flow `1000m`/`6000Mi` +- You may optionally customize and use `config.hcl` instead of the default config. + +## Install + +- Add Helm charts and Deploy + + ```sh + helm repo add netobserv https://elastiflow.github.io/helm-chart-netobserv/ + helm repo add opensearch https://opensearch-project.github.io/helm-charts/ + helm repo update + kubectl create namespace elastiflow + helm upgrade -i --wait --timeout 15m -n elastiflow -f examples/flow_os_simple_svc/values.yaml netobserv netobserv/netobserv-os + ``` + +- Optionally install `metrics-server` to get metrics if it has not been installed yet + + ```sh + kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.8.0/components.yaml + # Patch to use insecure TLS, commonly needed on dev local clusters + kubectl -n kube-system patch deployment metrics-server --type='json' -p='[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]' + ``` + +- Test the API/OTLP endpoints work as expected: + + ```sh + kubectl -n elastiflow port-forward svc/netobserv-flow 8080:8080 4317:4317 + + curl -k "https://127.0.0.1:8080/readyz" + # 200 - Ready! + + curl -k "https://127.0.0.1:8080/api" + # 404 page not found + + grpcurl -insecure 127.0.0.1:4317 list + # grpc.reflection.v1.ServerReflection + # grpc.reflection.v1alpha.ServerReflection + # opentelemetry.proto.collector.trace.v1.TraceService + ``` + +## Access Dashboards + +First, port forward the OpenSearch Dashboards service + +```sh +kubectl -n elastiflow port-forward svc/elastiflow-os-dashboards 5601:5601 +``` + +Now you can navigate to `http://localhost:5601/` in your browser to open OpenSearch Dashboards, using `admin`/`Elast1flow!` as the user/password. Select "global tenant", and explore the data. + +## Hints + +To render and diff Helm templates to Kubernetes manifests, run: + +```sh +rm -rf helm_rendered; helm template -n elastiflow -f examples/flow_os_simple_svc/values.yaml --output-dir helm_rendered netobserv netobserv/netobserv-os + +# Diff with existing K8s resources +kubectl diff -R -f helm_rendered/ +``` diff --git a/examples/flow_os_simple_svc/values.yaml b/examples/flow_os_simple_svc/values.yaml new file mode 100644 index 0000000..0e3ec98 --- /dev/null +++ b/examples/flow_os_simple_svc/values.yaml @@ -0,0 +1,152 @@ +netobserv-flow: + enabled: true + fullnameOverride: netobserv-flow + + env: + - name: EF_LICENSE_ACCEPTED + value: "true" + - name: EF_OUTPUT_OPENSEARCH_INDEX_TEMPLATE_REPLICAS + value: "0" + - name: EF_INPUT_OTLP_TRACE_GRPC_ENABLE + value: "true" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_ENABLE + value: "true" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_CERT_FILE + value: "/etc/ssl/netobserv/tls.crt" + - name: EF_INPUT_OTLP_TRACE_GRPC_SERVER_TLS_KEY_FILE + value: "/etc/ssl/netobserv/tls.key" + - name: EF_INPUT_OTLP_HEALTH_GRPC_ENABLE + value: "true" + - name: EF_INPUT_OTLP_HEALTH_GRPC_ADDR_PORT + value: "4316" + - name: EF_INPUT_FLOW_BENCHMARK_ENABLE + value: "false" # `false` is the default, keeping for ease of updating for testing + - name: EF_OUTPUT_STDOUT_ENABLE + value: "false" # `false` is the default, keeping for ease of updating for testing + + resources: + requests: + cpu: "1000m" + memory: "6000Mi" + limits: + cpu: "2000m" + memory: "6000Mi" + + autoscaling: + enabled: true + minReplicas: 1 + maxReplicas: 1 + pdb: + minAvailable: null + maxUnavailable: 10% + + # Discourage to colocate the collector with opensearch + topologySpreadConstraints: + - maxSkew: 1 + minDomains: 2 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: [opensearch] + + ports: + - name: api + protocol: TCP + containerPort: 8080 + - name: otlp-grpc-hlth + protocol: TCP + containerPort: 4316 + - name: otlp-grpc + protocol: TCP + containerPort: 4317 + - name: netflow + protocol: UDP + containerPort: 9995 + + service: + ports: + - name: api + protocol: TCP + port: 8080 + targetPort: 8080 + - name: otlp-grpc + protocol: TCP + port: 4317 + targetPort: 4317 + appProtocol: HTTP2 + + outputOpenSearch: + enable: true + addresses: opensearch-cluster-master.elastiflow.svc:9200 + password: Elast1flow! # Insecure + tls: + enable: true + skipVerification: true + dashboards: + provision: true + dashboards_url: http://elastiflow-os-dashboards.elastiflow.svc:5601 + + extraVolumes: + - name: netobserv-tls + secret: + secretName: netobserv-tls + extraVolumeMounts: + - name: netobserv-tls + mountPath: /etc/ssl/netobserv/ + + extraObjects: + - | + apiVersion: v1 + kind: Secret + metadata: + name: netobserv-tls + labels: + {{- include "netobserv.labels" . | nindent 4 }} + type: kubernetes.io/tls + data: + tls.crt: {{ .Files.Get "tls/netobserv.crt" | b64enc }} + tls.key: {{ .Files.Get "tls/netobserv.key" | b64enc }} + +opensearch: + enabled: true + clusterName: elastiflow + fullnameOverride: "elastiflow-os" + singleNode: true + replicas: 1 + opensearchJavaOpts: "-Xmx3700M -Xmx3700M" + resources: + requests: + cpu: "2000m" + memory: 4000Mi + limits: + cpu: "2000m" + memory: 4000Mi + + persistence: + storageClass: standard + size: 50Gi + labels: + enabled: true + + extraEnvs: + - name: OPENSEARCH_INITIAL_ADMIN_PASSWORD + value: Elast1flow! # Insecure + +opensearch-dashboards: + enabled: true + fullnameOverride: elastiflow-os-dashboards + opensearchHosts: https://opensearch-cluster-master.elastiflow.svc:9200 + resources: + requests: + cpu: "1000m" + memory: "768Mi" + limits: + cpu: "1000m" + memory: "768Mi" + + config: + ssl: + verificationMode: none