How to integrate opensearch with logstash on the Kubernetes Cluster? - kubernetes

I have a kubernetes cluster on which I have deployed a opensearch cluster and opensearch dashboard using Helm, I am also able to deploy logstash using helm successfully but I am confused on how to integrate those, I want to feed data to my Opensearch using logstash as my OBJECTIVE as I am not able to find much documentation on it as well. Any help is appreciated....Thanks in advance!
Deployed opensearch using Helm and logstash as well but unable to integrate them
Update here!!!
Have made a few changes to simplify the deployment and more control over the function,
I am testing deployment and service files this time, I will add the files below
Opensearch deployment file
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
namespace: logging
name: opensearch
labels:
component: opensearch
spec:
selector:
matchLabels:
component: opensearch
replicas: 1
serviceName: opensearch
template:
metadata:
labels:
component: opensearch
spec:
initContainers:
- name: init-sysctl
image: busybox
imagePullPolicy: IfNotPresent
command:
- sysctl
- -w
- vm.max_map_count=262144
securityContext:
privileged: true
containers:
- name: opensearch
securityContext:
capabilities:
add:
- IPC_LOCK
image: opensearchproject/opensearch
env:
- name: KUBERNETES_CA_CERTIFICATE_FILE
value: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: "cluster.name"
value: "opensearch-cluster"
- name: "network.host"
value: "0.0.0.0"
- name: "discovery.seed_hosts"
value: "[]"
- name: discovery.type
value: single-node
- name: OPENSEARCH_JAVA_OPTS
value: -Xmx512M -Xms512M
- name: "plugins.security.disabled"
value: "false"
ports:
- containerPort: 9200
name: http
protocol: TCP
- containerPort: 9300
name: transport
protocol: TCP
volumeMounts:
- name: os-mount
mountPath: /data
volumes:
- name: os-mount
persistentVolumeClaim:
claimName: nfs-pvc-os-logging
Opensearch svc file
---
apiVersion: v1
kind: Service
metadata:
name: opensearch
namespace: logging
labels:
service: opensearch
spec:
type: ClusterIP
selector:
component: opensearch
ports:
- port: 9200
targetPort: 9200
Opensearch dashboard deployment
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: open-dash
namespace: logging
spec:
replicas: 1
selector:
matchLabels:
app: open-dash
template:
metadata:
labels:
app: open-dash
spec:
# securityContext:
# runAsUser: 0
containers:
- name: opensearch-dashboard
image: opensearchproject/opensearch-dashboards:latest
ports:
- containerPort: 80
env:
# - name: ELASTICSEARCH_URL
# value: https://opensearch.logging:9200
# - name: "SERVER_HOST"
# value: "localhost"
# - name: "opensearch.hosts"
# value: https://opensearch.logging:9200
- name: OPENSEARCH_HOSTS
value: '["https://opensearch.logging:9200"]'
Opensearch Dashboard svc
---
apiVersion: v1
kind: Service
metadata:
name: opensearch
namespace: logging
labels:
service: opensearch
spec:
type: ClusterIP
selector:
component: opensearch
ports:
- port: 9200
targetPort: 9200
with the above configuration I am able to get the Dashboard UI open but in Dashboard pod logs I can see a 400 code logs can anyone please try to reproduce this issue, Also I need to integrate the logstash with this stack.
{"type":"response","#timestamp":"2023-02-20T05:05:34Z","tags":[],"pid":1,"method":"head","statusCode":400,"req":{"url":"/app/home","method":"head","headers":{"connection":"Keep-Alive","content-type":"application/json","host":"3.108.199.0:30406","user-agent":"Manticore 0.9.1","accept-encoding":"gzip,deflate","securitytenant":"user"},"remoteAddress":"10.244.1.1","userAgent":"Manticore 0.9.1"},"res":{"statusCode":400,"responseTime":2,"contentLength":9},"message":"HEAD /app/home 400 2ms - 9.0B
When deploying a logstash pod I get an error that
[WARN ] 2023-02-20 05:13:52.212 [Ruby-0-Thread-9: /usr/share/logstash/vendor/bundle/jruby/2.6.0/gems/logstash-output-opensearch-2.0.1-java/lib/logstash/outputs/opensearch/http_client/pool.rb:217] opensearch - Attempted to resurrect connection to dead OpenSearch instance, but got an error {:url=>"http://logstash:xxxxxx#opensearch.logging:9200/", :exception=>LogStash::Outputs::OpenSearch::HttpClient::Pool::HostUnreachableError, :message=>"OpenSearch Unreachable: [http://logstash:xxxxxx#opensearch.logging:9200/][Manticore::ClientProtocolException] opensearch.logging:9200 failed to respond"}
Can somebody please try to help me with this puzzle
#Benla have made changes as per your recommendation to image now I am getting the following logs in logstash
[2023-02-20T05:18:43,028][INFO ][logstash.agent ] Successfully started Logstash API endpoint {:port=>9600, :ssl_enabled=>false}
[2023-02-20T05:18:43,147][INFO ][org.reflections.Reflections] Reflections took 70 ms to scan 1 urls, producing 127 keys and 444 values
[2023-02-20T05:18:43,351][INFO ][logstash.javapipeline ] Pipeline main is configured with pipeline.ecs_compatibility: v8 setting. All plugins in this pipeline will default to ecs_compatibility => v8 unless explicitly configured otherwise.
[2023-02-20T05:18:43,370][INFO ][logstash.javapipeline ][main] Starting pipeline {:pipeline_id=>"main", "pipeline.workers"=>16, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>50, "pipeline.max_inflight"=>2000, "pipeline.sources"=>["/usr/share/logstash/pipeline/logstash.conf"], :thread=>"#<Thread:0x3bf49916#/usr/share/logstash/logstash-core/lib/logstash/java_pipeline.rb:131 run>"}
[2023-02-20T05:18:43,811][INFO ][logstash.javapipeline ][main] Pipeline Java execution initialization time {"seconds"=>0.44}
[2023-02-20T05:18:43,816][INFO ][logstash.inputs.beats ][main] Starting input listener {:address=>"0.0.0.0:5044"}
[2023-02-20T05:18:43,821][INFO ][logstash.javapipeline ][main] Pipeline started {"pipeline.id"=>"main"}
[2023-02-20T05:18:43,835][INFO ][logstash.agent ] Pipelines running {:count=>1, :running_pipelines=>[:main], :non_running_pipelines=>[]}
[2023-02-20T05:18:43,869][INFO ][org.logstash.beats.Server][main][0710cad67e8f47667bc7612580d5b91f691dd8262a4187d9eca8cf87229d04aa] Starting server on port: 5044
I started getting these endless loop of logs
[WARN ] 2023-02-20 05:13:37.191 [Ruby-0-Thread-9: /usr/share/logstash/vendor/bundle/jruby/2.6.0/gems/logstash-output-opensearch-2.0.1-java/lib/logstash/outputs/opensearch/http_client/pool.rb:217] opensearch - Attempted to resurrect connection to dead OpenSearch instance, but got an error {:url=>"http://logstash:xxxxxx#opensearch.logging:9200/", :exception=>LogStash::Outputs::OpenSearch::HttpClient::Pool::HostUnreachableError, :message=>"OpenSearch Unreachable: [http://logstash:xxxxxx#opensearch.logging:9200/][Manticore::ClientProtocolException] opensearch.logging:9200 failed to respond"}

I think there is not much difference in deploying logstash<->opensearch pipeline from deploying logstash<->elasticsearch in K8S,
The only differences I've encountered are:
The docker or other container runtime image should be opensearchproject/logstash-oss-with-opensearch-output-plugin:latest rather than logstash.
The output plugin in your logstash config file sould be
opensearch rather than elasticsearch.
Other than those you can go to every Logstash<->ElasticSearch in K8S tutorial, there are many.
Good Luck!

Related

Can't deploy Keycloak using Kubernetes (AWS and local)

I'm trying to deploy Keycloak in Kubernetes. Here there is my service and deploy:
apiVersion: v1
kind: Service
metadata:
name: keycloak
labels:
app: keycloak
spec:
ports:
- name: https
port: 443
targetPort: 8443
selector:
app: keycloak
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
labels:
app: keycloak
spec:
replicas: 2
selector:
matchLabels:
app: keycloak
template:
metadata:
labels:
app: keycloak
spec:
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:16.1.1
env:
- name: KEYCLOAK_USER
value: "admin"
- name: KEYCLOAK_PASSWORD
value: "admin"
- name: PROXY_ADDRESS_FORWARDING
value: "true"
- name: JGROUPS_DISCOVERY_PROTOCOL
value: dns.DNS_PING
- name: JGROUPS_DISCOVERY_PROPERTIES
value: "dns_query=keycloak"
- name: CACHE_OWNERS_COUNT
value: "2"
- name: CACHE_OWNERS_AUTH_SESSIONS_COUNT
value: "2"
ports:
- name: jgroups
containerPort: 7600
- name: http
containerPort: 8080
- name: https
containerPort: 8443
readinessProbe:
httpGet:
path: /auth/realms/master
port: 8080
If I make the deploy in a local cluster (the default docker-desktop cluster using MacOSX), the pod became ready but i can't reach the main /auth page.
I try also to deploy using AWS but I get this error:
'Readiness probe failed: Get http://XXXXXX/: dial tcp XXXXX: getsockopt: connection refused'.
I tried increasing initialDelay seconds but without result, maybe I entered too low value?
Could anyone help me solve the problem?
Also it would be helpful how I should import a configuration of realm.
Keycloak should be deployed as Statefulset, not as deployment. there is a discussion on the this to avoid any issue in the future.
Keycloak Deployment vs. Statefulset
Also, it should be backed by database for the persistent realm.
Keycloak uses a relational database management system (RDBMS) to persist some metadata about realms, clients, users, and so on.
Configuring the database - Server - Keycloak
so I will suggest to go with helm-chart
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-release bitnami/keycloak

Kibana on Kubernetes - how to point to ES container running on a different pod

Learning Kubernetes by setting up two pods, each running an elastic-search and a kibana container respectively.
My configuration file is able to setup both pods as well as create two services to access these applications on host machine's web browser.
Issue is that i don't know how to make Kibana container communicate with ES application/pod.
Earlier while learning Docker i crafted a docker-compose app configuration and now basically trying to do the same using Kubernetes ( docker-compose config pasted below ) .
Came across a blog that suggested using Deployment instead of Pod. Again not sure how would one make Kibana talk to ES
Kubernetes configuation yaml:
apiVersion: v1
kind: Pod
metadata:
name: pod-elasticsearch
labels:
app: myapp
spec:
hostname: "es01-docker-local"
containers:
- name: myelasticsearch-container
image: myelasticsearch
imagePullPolicy: Never
volumeMounts:
- name: my-volume
mountPath: /home/newuser
volumes:
- name: my-volume
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: myelasticsearch-service
spec:
type: NodePort
ports:
- targetPort: 9200
port: 9200
nodePort: 30015
selector:
app: myapp
---
apiVersion: v1
kind: Pod
metadata:
name: pod-kibana
labels:
app: myapp
spec:
containers:
- name: mykibana-container
image: mykibana
imagePullPolicy: Never
volumeMounts:
- name: my-volume
mountPath: /home/newuser
volumes:
- name: my-volume
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: mykibana-service
spec:
type: NodePort
ports:
- targetPort: 5601
port: 5601
nodePort: 30016
selector:
app: myapp
For reference below is the docker-compose that i am trying to replicate on Kubernetes
version: "2.2"
services:
elasticsearch:
image: myelasticsearch
container_name: myelasticsearch-container
restart: always
hostname: 'es01.docker.local'
ports:
- '9200:9200'
- '9300:9300'
volumes:
- myVolume:/home/newuser/
environment:
- discovery.type=single-node
kibana:
depends_on:
- elasticsearch
image: mykibana
container_name: mykibana-container
restart: always
ports:
- '5601:5601'
volumes:
- myVolume:/home/newuser/
environment:
ELASTICSEARCH_URL: http://es01:9200
ELASTICSEARCH_HOSTS: http://es01:9200
volumes:
myVolume:
networks:
myNetwork:
ES Pod description:
% kubectl describe pod/pod-elasticsearch
Name: pod-elasticsearch
Namespace: default
Priority: 0
Node: docker-desktop/192.168.65.3
Start Time: Sun, 10 Jan 2021 23:06:18 -0800
Labels: app=myapp
Annotations: <none>
Status: Running
IP: 10.x.0.yy
IPs:
IP: 10.x.0.yy
In kubernetes Pod/Deployment/DaemonSet... in the same cluster can communicate with each other with no problem because it has a flat network architecture .One way for these resources to call each other directly is by the name of Kubernetes service of each resource.
For example any resource in the cluster can call your kibana-app directly by service name you give it to it mykibana-service.name-of-namespace.
So for kibana pod to communicate with elasticsearch it can use http://name-of-service-of-elasticsearch.name-of-namespace:9200 namespace is be default if you dont specify where you create your service => http://name-of-service-of-elasticsearch.default:9200 or http://name-of-service-of-elasticsearch:9200
The concern you raised on what type of your resource you have to create (pod, deployment,daemonset or statefulSet) is not important for these resources to communicate with each other.
If you re having problem converting docker-compose to manifest file you can start with Kompose you can do kompose convert where is your docker-compose is located .
Here sample
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: elasticsearch
name: elasticsearch
namespace: default
spec:
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- image: myelasticsearch:yourtag #fix this
name: elasticsearch
ports:
- containerPort: 9200
- containerPort: 9300
volumeMounts:
- mountPath: /home/newuser/
name: my-volume
volumes:
- name: my-volume
emptyDir: {} # I wouldnt use emptydir
---
apiVersion: v1
kind: Service
metadata:
labels:
app: elasticsearch
name: elasticsearch
namespace: default
spec:
ports:
- port: 9200
name: "9200"
targetPort: 9200
- port: 9300
name: "9300"
targetPort: 9300
selector:
app: elasticsearch
type: ClusterIP #you dont need to make expose your service publicly
#####################################
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: kibana
name: kibana
namespace: default
spec:
selector:
matchLabels:
app: kibana
template:
metadata:
labels:
app: kibana
spec:
containers:
- env:
- name: ELASTICSEARCH_URL
value: http://elasticsearch:9200/ #elasticsearch is the same name as service resrouce name
- name: ELASTICSEARCH_HOSTS
value: http://elasticsearch:9200
image: mykibana:yourtagname #fix this
name: kibana
---
apiVersion: v1
kind: Service
metadata:
labels:
app: kibana
name: kibana
namespace: default
spec:
ports:
- port: 5601
protocol: TCP
targetPort: 5601
selector:
app: kibana
type: NodePort
You can choose whats adequate for your app , for example in elasticsearch you can use StatefulSet ,Deployment, in ElasticSearch, and you can you use Deployment for Kibana , Also you can change the type of volume .
Also the mynetwork that you created in docker-compose can be translated network policy where you can isolate your resources (for example isolated mynetwork namespace) because these resources are not isolated if they are created in the same cluster by default.
Hope I helped
If you want to deploy Elasticsearch and Kibana in Kubernetes the usual way then you have to take care of some core Elasticsearch cluster configuration like:
cluster.initial_master_nodes [7.0] Added in 7.0.
network.host
network.publish_host
Also you would have to carefully setup the network.host so that even after accidental pod restarts the network.host remains the same.
While deploying Kibana you need provide Elasticsearch service and also manually configure the SSL certificates if Elasticsearch has SSL enabled.
So to install Elastic Stack on Kubernetes then you should probably prefer
Elastic Cloud on Kubernetes (ECK). The documentation provided by Elastic is easy to understand.
Elastic Cloud on Kubernetes (ECK) uses Kubernetes Operators to make installation easier and it automatically takes care of core cluster configuration.
ECK installation will create a default user called "elastic" and you can retrieve its password from secrets. It also creates self-signed certificates which can be found in secrets.
For deploying Kibana you can just provide "elasticsearchRef" in your YAML file and it will automatically configure the Elasticsearch endpoints. You can use the default "elastic" user to login to Kibana.

Connecting to redis pod from another pod in the same cluster

In my cluster I have a nodejs application pod and a redis pod, and I am trying to connect to redis from nodejs, but I am getting the following error:
[ioredis] Unhandled error event: Error: getaddrinfo ENOTFOUND redis at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26)
It is worth noting that in my nodejs app I am pointing at redis:6379 and if I change the pointer to localhost:6379, I will get a ECONNREFUSED error.
My redis deployment yaml looks like this:
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis:5.0.4
command:
- redis-server
- '/redis-master/redis.conf'
env:
- name: MASTER
value: 'true'
ports:
- containerPort: 6379
resources:
limits:
cpu: '0.1'
volumeMounts:
- mountPath: /redis-master-data
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: redis-config
items:
- key: redis-config
path: redis.conf
Mu redis service yaml is the following:
apiVersion: v1
kind: Service
metadata:
name: redis-master
labels:
app: redis
role: master
tier: backend
spec:
ports:
- name: redis
port: 6379
targetPort: 6379
selector:
app: redis
role: master
tier: backend
And the service of my app looks like this:
apiVersion: v1
kind: Service
metadata:
name: bff
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '8080'
labels:
app: bff
spec:
ports:
- name: external
port: 80
targetPort: web
protocol: TCP
- name: metrics
port: 8080
targetPort: metrics
protocol: TCP
selector:
app: bff
I have tried following other answers given to similar questions, but they do not seem to work in my case.
The root cause is your service selector definition doesn't match your pods's lables.
Quote from Kubernetes service document:
The controller for the Service selector continuously scans for Pods that match its selector, and then POSTs any updates to an Endpoint object also named “my-service”.
See this link for full document.
In short, by following this Kubernetes official example, you should deploy the deployment "redis-master-deployment.yaml" instead of bare pod.

kibana 7.2 can't reach elasticsearch on kubernetes

I'm testing the latest version of the Elastic Stack (7.2.0) and i can't seem to connect Kibana to Elasticsearch, but when i rollback to 6.8.1 it works. Any ideas ?
Kibana Deploy & Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana
namespace: *************
labels:
component: kibana
spec:
replicas: 1
selector:
matchLabels:
component: kibana
template:
metadata:
labels:
component: kibana
spec:
containers:
- name: kibana
image: docker.elastic.co/kibana/kibana:7.2.0
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
env:
- name: ELASTICSEARCH_URL
value: http://elastic.****************:80
ports:
- containerPort: 5601
name: kibana
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: kibana
namespace: *************
labels:
component: kibana
spec:
selector:
component: kibana
ports:
- port: 80
protocol: "TCP"
name: "http"
targetPort: 5601
I am using an ingress but Kibana comlpetely ignores the ELASTICSEARCH_URL value when i try to deploy the 7.2.0 but it works when i rollback to the 6.8.1. I don't know if this methode is no longer supported on the 7.2.0, i've been all over trying to find some documentation but no luck.
As of Kibana 7.0 elasticsearch.url is no longer valid and it is now elasticsearch.hosts: https://www.elastic.co/guide/en/kibana/7.x/breaking-changes-7.0.html#_literal_elasticsearch_url_literal_is_no_longer_valid.
The environment variables translate to these settings names. In this case, the new environment variable would be ELASTICSEARCH_HOSTS. See the example at https://www.elastic.co/guide/en/kibana/7.2/docker.html.
update ingest service dns name in ELASTICSEARCH_URL as shown below. assuming kibana and es are running in the same k8s cluster
- name: ELASTICSEARCH_URL
value: http://ingest.<namespace>.svc.cluster.local:9200
update the correct namespace they are running in
change your env key from ELASTICSEARCH_URL to ELASTICSEARCH_HOSTS

Edit config file inside image before deployment/pod creation

I am running grafana as a pod inside my Kubernetes cluster. Once Grafana is initialized, it create a DB on localhost and saves all data there. This means that whenever a pod is destroyed and recreated, the whole DB is reinitialized and I lose all previous Data.
The grafana config inside the Pod for DB is ::
#################################### Database ####################################
[database]
# Either "mysql", "postgres" or "sqlite3", it's your choice
;type = sqlite3
;host = 127.0.0.1:3306
;name = grafana
;user = root
;password =
Inorder to get rid of this problem, I have to create an external DB and point my Grafana to use that DB instance everytime I create the Grafana Pod. My current default implementation to create the Grafana pod is ::
apiVersion: v1
kind: Service
metadata:
name: lb-grafana-service
spec:
ports:
- port: 4545
targetPort: 4545
protocol: TCP
clusterIP: 10.100.10.100
----
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: 'true'
labels:
app: grafana
name: grafana
name: grafana
spec:
ports:
- name: scrape
port: 4545
nodePort: 30999
protocol: TCP
type: NodePort
selector:
app: grafana
----
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: grafana
spec:
replicas: 1
selector:
matchLabels:
app: grafana
template:
metadata:
name: grafana
labels:
app: grafana
spec:
containers:
- name: grafana
image: grafana/grafana:develop
env:
- name: Prometheus_SERVICE_URL
value: http://172.29.219.105:30901
- name: GF_SECURITY_ADMIN_PASSWORD
value: "grafana"
- name: GF_SERVER_HTTP_PORT
value: "4545"
ports:
- containerPort: 9101
volumeMounts:
- mountPath: /var
name: grafana-storage
volumes:
- name: grafana-storage
emptyDir: {}
So what I want to do is overwrite the /etc/grafana/grafana.ini file before Grafana pod comes online OR just rewrite the current file with new values. I have no idea how I can do that right now. A little guidance will be much appreciated.
In general, you could use ConfigMaps like the comment said.
The Grafana image itself provides the ability to provide all configuration parameters via environment variables. This is only mentioned in the GitHub readme.
This way you could set the environment variables with Kubernetes, like:
spec:
template:
spec:
containers:
- name: grafana
image: grafana/grafana:4.1.1
env:
- name: "GF_SERVER_ROOT_URL"
value: "http://grafana.{{.clusterDomain}}"
- name: "GF_DATABASE_TYPE"
value: "{{.gfDatabaseType}}"
- name: "GF_DATABASE_HOST"
value: "{{.gfDatabaseHost}}"
- name: "GF_DATABASE_NAME"
value: "{{.gfDatabaseName}}"
- name: "GF_DATABASE_USER"
value: "{{.gfDatabaseUser}}"
- name: "GF_DATABASE_PASSWORD"
value: "{{.gfDatabasePassword}}"
- name: "GF_DATABASE_SSL_MODE"
value: "disable"
- name: "GF_AUTH_ANONYMOUS_ENABLED"
value: "true"