0% found this document useful (0 votes)
82 views21 pages

OpenSearch Deployment With Kubernetes Log Ingestion

The document provides a comprehensive guide for setting up an OpenSearch deployment using Kubernetes, detailing the installation and configuration of OpenSearch, OpenSearch Dashboards, FluentBit, and NGINX. It includes step-by-step instructions for creating necessary configurations, starting services, and verifying their operation. Additionally, it covers generating fake traffic and creating visualizations in OpenSearch Dashboards.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
82 views21 pages

OpenSearch Deployment With Kubernetes Log Ingestion

The document provides a comprehensive guide for setting up an OpenSearch deployment using Kubernetes, detailing the installation and configuration of OpenSearch, OpenSearch Dashboards, FluentBit, and NGINX. It includes step-by-step instructions for creating necessary configurations, starting services, and verifying their operation. Additionally, it covers generating fake traffic and creating visualizations in OpenSearch Dashboards.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 21

OpenSearch Deployment with Kubernetes Log

Ingestion
Suhas Dissanayake ([email protected])

Contents
1 Setting Up Opensearch 2
1.1 Setting up the Virtual machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Download and install Opensearch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Configuring Opensearch service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Starting Opensearch service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Checking the Opensearch service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Setting up Opensearch Dashboards 4


2.1 Download and install Opensearch Dashboards . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Configuring Opensearch Dashboards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Starting Opensearch Dashboards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.4 Verify Opensearch dashboards are running . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 Setting up FluentBit 5
3.1 Create FluentBit DaemonSet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Deploy FluentBit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

4 Installing and Configuring NGINX 9


4.1 Create NGINX ConfigMap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.2 Create NGINX Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.3 Deploying NGINX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.4 Update Fluentbit config to add NGINX . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.5 Update Fluentbit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

5 Generating / Simulating fake traffic 14

6 Creating Visualizations in Opensearch Dashboards 16


6.1 Accessing Opensearch dashboards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.2 Create Index Pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.3 Create Scripted Field for Request Method . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6.4 Check Opensearch Dashboard - Discovery Page . . . . . . . . . . . . . . . . . . . . . . . 19
6.5 Create Dashboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
6.6 Create Visualizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
6.6.1 Visualization 1: Requests by Status Code (Pie Chart) . . . . . . . . . . . . . . . . 19
6.6.2 Visualization 2: Top 10 Requesting IPs (Data Table) . . . . . . . . . . . . . . . . 20
6.6.3 Visualization 3: Request Method Distribution (Vertical Bar Chart) . . . . . . . . 20
6.6.4 Visualization 4: User-Agent Distribution (Horizontal Bar Chart) . . . . . . . . . . 21
6.7 Save Dashboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

1
1 Setting Up Opensearch
1.1 Setting up the Virtual machine
Create a virtual machine running Ubuntu server 24.04. this virtual machine should have access to a
kubernetes cluster running on a different set of virtual machines.

First we need to tweak the vm.max map count of our virtual machine.

edit the file /etc/sysctl.conf then add the following line:

vm.max map count=262144

1.2 Download and install Opensearch


We can download the official .deb package from opensearch

wget https://artifacts.opensearch.org/releases/bundle/opensearch/3.1.0
/opensearch-3.1.0-linux-x64.deb

Then install it using:

sudo env OPENSEARCH INITIAL ADMIN PASSWORD=<custom-admin-password> dpkg -i


opensearch-3.1.0-linux-x64.deb

make sure to choose a long and complicated password for the <custom-admin-password>

1.3 Configuring Opensearch service


Edit the /etc/opensearch/opensearch.yml file and update it like this:

1 path.data: /var/lib/opensearch
2 path.logs: /var/log/opensearch
3

4 plugins.security.ssl.transport.pemcert_filepath: esnode.pem
5 plugins.security.ssl.transport.pemkey_filepath: esnode-key.pem
6 plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
7 plugins.security.ssl.transport.enforce_hostname_verification: false
8 plugins.security.ssl.http.enabled: true
9 plugins.security.ssl.http.pemcert_filepath: esnode.pem
10 plugins.security.ssl.http.pemkey_filepath: esnode-key.pem
11 plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem
12 plugins.security.allow_unsafe_democertificates: true
13 plugins.security.allow_default_init_securityindex: true
14 plugins.security.authcz.admin_dn: ['CN=kirk,OU=client,O=client,L=test,C=de']
15 plugins.security.audit.type: internal_opensearch

2
16 plugins.security.enable_snapshot_restore_privilege: true
17 plugins.security.check_snapshot_restore_write_privileges: true
18 plugins.security.restapi.roles_enabled: [all_access, security_rest_api_access]
19 plugins.security.system_indices.enabled: true
20 plugins.security.system_indices.indices: [.plugins-ml-agent, .plugins-ml-config,
,→ .plugins-ml-connector,
21 .plugins-ml-controller, .plugins-ml-model-group, .plugins-ml-model,
,→ .plugins-ml-task,
22 .plugins-ml-conversation-meta, .plugins-ml-conversation-interactions,
,→ .plugins-ml-memory-meta,
23 .plugins-ml-memory-message, .plugins-ml-stop-words, .opendistro-alerting-config,
24 .opendistro-alerting-alert*, .opendistro-anomaly-results*,
,→ .opendistro-anomaly-detector*,
25 .opendistro-anomaly-checkpoints, .opendistro-anomaly-detection-state,
,→ .opendistro-reports-*,
26 .opensearch-notifications-*, .opensearch-notebooks, .opensearch-observability,
,→ .ql-datasources,
27 .opendistro-asynchronous-search-response*, .replication-metadata-store,
,→ .opensearch-knn-models,
28 .geospatial-ip2geo-data*, .plugins-flow-framework-config,
,→ .plugins-flow-framework-templates,
29 .plugins-flow-framework-state, .plugins-search-relevance-experiment,
,→ .plugins-search-relevance-judgment-cache]
30 node.max_local_storage_nodes: 3
31

32 # Add these two lines


33 network.host: 0.0.0.0
34 discovery.type: single-node
35

1.4 Starting Opensearch service


We can now start our opensearch service using:

sudo systemctl enable opensearch


sudo systemctl start opensearch

1.5 Checking the Opensearch service


Use CURL to test if the opensearch is working fine:

curl -X GET https://localhost:9200 -u ’admin:<custom-admin-password>’


--insecure

3
2 Setting up Opensearch Dashboards
2.1 Download and install Opensearch Dashboards
We can download the official .deb package from opensearch

wget https://artifacts.opensearch.org/releases/bundle/opensearch-dashboards/
3.1.0/opensearch-dashboards-3.1.0-linux-x64.deb

Then install it using:

sudo dpkg -i opensearch-dashboards-3.1.0-linux-x64.deb

2.2 Configuring Opensearch Dashboards


Edit the /etc/opensearch-dashboards/opensearch dashboards.yml file and update it like this:

1 opensearch.hosts: ["https://localhost:9200"]
2 opensearch.ssl.verificationMode: none
3 opensearch.username: "kibanaserver"
4 opensearch.password: "kibanaserver"
5 opensearch.requestHeadersWhitelist: [authorization, securitytenant]
6

7 opensearch_security.multitenancy.enabled: true
8 opensearch_security.multitenancy.tenants.preferred: ["Private", "Global"]
9 opensearch_security.readonly_mode.roles: ["kibana_read_only"]
10 opensearch_security.cookie.secure: false
11

12 server.host: "0.0.0.0"
13 server.ssl.enabled: false

4
2.3 Starting Opensearch Dashboards
We can now start our opensearch-dashboards service using:

sudo systemctl daemon-reload


sudo systemctl enable opensearch-dashboards
sudo systemctl start opensearch-dashboards

2.4 Verify Opensearch dashboards are running


Check service status:

sudo systemctl status opensearch-dashboards

We can also check the output of CURL:

curl -I http://localhost:5601

3 Setting up FluentBit
Continue these steps from within the master node of the kubernetes cluster

5
3.1 Create FluentBit DaemonSet
Create a file fluent-bit-daemonset.yaml

1 apiVersion: v1
2 kind: ServiceAccount
3 metadata:
4 name: fluent-bit
5 namespace: kube-system
6 ---
7 apiVersion: rbac.authorization.k8s.io/v1
8 kind: ClusterRole
9 metadata:
10 name: fluent-bit-read
11 rules:
12 - apiGroups: [""]
13 resources:
14 - namespaces
15 - pods
16 - nodes
17 - nodes/proxy
18 verbs: ["get", "list", "watch"]
19 ---
20 apiVersion: rbac.authorization.k8s.io/v1
21 kind: ClusterRoleBinding
22 metadata:
23 name: fluent-bit-read
24 roleRef:
25 apiGroup: rbac.authorization.k8s.io
26 kind: ClusterRole
27 name: fluent-bit-read
28 subjects:
29 - kind: ServiceAccount
30 name: fluent-bit
31 namespace: kube-system
32 ---
33 apiVersion: v1
34 kind: ConfigMap
35 metadata:
36 name: fluent-bit-config
37 namespace: kube-system
38 data:
39 fluent-bit.conf: |
40 [SERVICE]
41 Flush 1
42 Log_Level info
43 Daemon off
44 Parsers_File parsers.conf
45 HTTP_Server On
46 HTTP_Listen 0.0.0.0

6
47 HTTP_Port 2020
48 [INPUT]
49 Name tail
50 Path /var/log/containers/*.log
51 Parser docker
52 Tag kube.*
53 Refresh_Interval 5
54 Mem_Buf_Limit 50MB
55 Skip_Long_Lines On
56 [FILTER]
57 Name kubernetes
58 Match kube.*
59 Kube_URL https://kubernetes.default.svc:443
60 Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
61 Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
62 Kube_Tag_Prefix kube.var.log.containers.
63 Merge_Log On
64 Keep_Log Off
65 K8S-Logging.Parser On
66 K8S-Logging.Exclude On
67 [OUTPUT]
68 Name es
69 Match *
70 Host 192.168.1.20
71 Port 9200
72 Index kubernetes-logs
73 Type _doc
74 Logstash_Format On
75 Logstash_Prefix kubernetes-logs
76 Logstash_DateFormat %Y.%m.%d
77 Replace_Dots On
78 Retry_Limit False
79 Suppress_Type_Name On
80 tls On
81 tls.verify Off
82 tls.debug 2
83 HTTP_User admin
84 HTTP_Passwd N*sd%L77d*syQNz0XY
85 net.connect_timeout 30
86 net.io_timeout 30
87 net.keepalive On
88 net.keepalive_idle_timeout 30
89 parsers.conf: |
90 [PARSER]
91 Name docker
92 Format json
93 Time_Key time
94 Time_Format %Y-%m-%dT%H:%M:%S.%L
95 Time_Keep On

7
96 ---
97 apiVersion: apps/v1
98 kind: DaemonSet
99 metadata:
100 name: fluent-bit
101 namespace: kube-system
102 spec:
103 selector:
104 matchLabels:
105 name: fluent-bit
106 template:
107 metadata:
108 labels:
109 name: fluent-bit
110 spec:
111 hostNetwork: true
112 dnsPolicy: ClusterFirstWithHostNet
113 serviceAccountName: fluent-bit
114 tolerations:
115 - key: node-role.kubernetes.io/master
116 operator: Exists
117 effect: NoSchedule
118 containers:
119 - name: fluent-bit
120 image: fluent/fluent-bit:latest
121 imagePullPolicy: Always
122 ports:
123 - containerPort: 2020
124 volumeMounts:
125 - name: varlog
126 mountPath: /var/log
127 - name: varlibdockercontainers
128 mountPath: /var/lib/docker/containers
129 readOnly: true
130 - name: fluent-bit-config
131 mountPath: /fluent-bit/etc/
132 - name: mnt
133 mountPath: /mnt
134 readOnly: true
135 resources:
136 limits:
137 memory: 200Mi
138 requests:
139 cpu: 100m
140 memory: 100Mi
141 terminationGracePeriodSeconds: 10
142 volumes:
143 - name: varlog
144 hostPath:

8
145 path: /var/log
146 - name: varlibdockercontainers
147 hostPath:
148 path: /var/lib/docker/containers
149 - name: fluent-bit-config
150 configMap:
151 name: fluent-bit-config
152 - name: mnt
153 hostPath:
154 path: /mnt

Here 192.168.1.20 is the IP address of our virtual machine running Opensearch.

Make sure to use the password from section 1.2

3.2 Deploy FluentBit


Deploy the configuration using:

kubectl apply -f fluent-bit-daemonset.yaml

Check if the depolyment is successful:

kubectl get pods -n kube-system | grep fluent-bit

4 Installing and Configuring NGINX


4.1 Create NGINX ConfigMap
Create a file nginx-configmap.yaml

1 apiVersion: v1
2 kind: ConfigMap
3 metadata:
4 name: nginx-config
5 namespace: nginx
6 data:
7 default.conf: |
8 apiVersion: v1
9 kind: ConfigMap
10 metadata:

9
11 name: nginx-config
12 namespace: nginx
13 data:
14 default.conf: |
15 log_format forwarded '$remote_addr - $remote_user [$time_local] "$request" '
16 '$status $body_bytes_sent "$http_referer" '
17 '"$http_user_agent" "$http_x_forwarded_for"';
18 server {
19 listen 80;
20 server_name localhost;
21

22 access_log /var/log/nginx/access.log forwarded;


23 error_log /var/log/nginx/error.log;
24

25 location = / {
26 return 200 'OK';
27 add_header Content-Type text/plain;
28 }
29

30 location = /redirect {
31 return 300;
32 }
33

34 location = /forbidden {
35 return 403;
36 }
37

38 location = /notfound {
39 return 404;
40 }
41

42 location / {
43 return 404;
44 }
45 }

4.2 Create NGINX Deployment


Create a file nginx-deployment.yaml

1 apiVersion: apps/v1
2 kind: Deployment
3 metadata:
4 name: nginx-deployment
5 namespace: nginx
6 spec:
7 replicas: 1
8 selector:
9 matchLabels:

10
10 app: nginx
11 template:
12 metadata:
13 labels:
14 app: nginx
15 spec:
16 containers:
17 - name: nginx
18 image: nginx:alpine
19 ports:
20 - containerPort: 80
21 volumeMounts:
22 - name: nginx-config
23 mountPath: /etc/nginx/conf.d
24 readOnly: true
25 volumes:
26 - name: nginx-config
27 configMap:
28 name: nginx-config
29 ---
30 apiVersion: v1
31 kind: Service
32 metadata:
33 name: nginx-service
34 namespace: nginx
35 spec:
36 selector:
37 app: nginx
38 ports:
39 - port: 80
40 targetPort: 80
41 type: ClusterIP

4.3 Deploying NGINX


Use these command to deploy NGINX:

kubectl create namespace nginx


kubectl apply -f nginx-configmap.yaml
kubectl apply -f nginx-deployment.yaml

We can check the status of our deployment using:

kubectl get pods -A | grep nginx


kubectl get svc -A | grep nginx

11
4.4 Update Fluentbit config to add NGINX
Create a file fluent-bit-nginx-config.yaml

1 apiVersion: v1
2 kind: ConfigMap
3 metadata:
4 name: fluent-bit-config
5 namespace: kube-system
6 data:
7 fluent-bit.conf: |
8 [SERVICE]
9 Flush 1
10 Log_Level info
11 Daemon off
12 Parsers_File parsers.conf
13 HTTP_Server On
14 HTTP_Listen 0.0.0.0
15 HTTP_Port 2020
16 [INPUT]
17 Name tail
18 Path /var/log/containers/*nginx*.log
19 Parser docker
20 Tag nginx.*
21 Refresh_Interval 5
22 Mem_Buf_Limit 50MB
23 Skip_Long_Lines On
24 [INPUT]
25 Name tail
26 Path /var/log/containers/*.log
27 Parser docker
28 Tag kube.*
29 Refresh_Interval 5
30 Mem_Buf_Limit 50MB
31 Skip_Long_Lines On
32 [FILTER]
33 Name kubernetes
34 Match nginx.*
35 Kube_URL https://kubernetes.default.svc:443
36 Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
37 Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
38 Kube_Tag_Prefix nginx.var.log.containers.
39 Merge_Log On
40 Keep_Log Off

12
41 K8S-Logging.Parser On
42 K8S-Logging.Exclude On
43 [FILTER]
44 Name parser
45 Match nginx.*
46 Key_Name log
47 Parser nginx_custom
48 Reserve_Data On
49 [FILTER]
50 Name kubernetes
51 Match kube.*
52 Kube_URL https://kubernetes.default.svc:443
53 Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
54 Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
55 Kube_Tag_Prefix kube.var.log.containers.
56 Merge_Log On
57 Keep_Log Off
58 K8S-Logging.Parser On
59 K8S-Logging.Exclude On
60 [OUTPUT]
61 Name opensearch
62 Match nginx.*
63 Host 192.168.1.20
64 Port 9200
65 Index nginx-logs
66 Type _doc
67 Logstash_Format On
68 Logstash_Prefix nginx
69 Logstash_DateFormat %Y.%m.%d
70 Replace_Dots On
71 Retry_Limit False
72 Suppress_Type_Name On
73 tls On
74 tls.verify Off
75 HTTP_User admin
76 HTTP_Passwd N*sd%L77d*syQNz0XY
77 net.connect_timeout 30
78 net.io_timeout 30
79 net.keepalive On
80 net.keepalive_idle_timeout 30
81 [OUTPUT]
82 Name opensearch
83 Match kube.*
84 Host 192.168.1.20
85 Port 9200
86 Index kubernetes-logs
87 Type _doc
88 Logstash_Format On
89 Logstash_Prefix kubernetes-logs

13
90 Logstash_DateFormat %Y.%m.%d
91 Replace_Dots On
92 Retry_Limit False
93 Suppress_Type_Name On
94 tls On
95 tls.verify Off
96 HTTP_User admin
97 HTTP_Passwd N*sd%L77d*syQNz0XY
98 net.connect_timeout 30
99 net.io_timeout 30
100 net.keepalive On
101 net.keepalive_idle_timeout 30
102 parsers.conf: |
103 [PARSER]
104 Name docker
105 Format json
106 Time_Key time
107 Time_Format %Y-%m-%dT%H:%M:%S.%L
108 Time_Keep On
109 [PARSER]
110 Name nginx_custom
111 Format regex
112 Regex ^(?<time_docker>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)
,→ \s+(?<stream>stdout|stderr)\s+(?<logtag>[F|P])\s+(?<remote_addr>[^ ]*) -
,→ (?<remote_user>[^ ]*) \[(?<time_local>[^\]]*)\] "(?<request>[^"]*)"
,→ (?<status>[0-9]*) (?<body_bytes_sent>[0-9]*) "(?<http_referer>[^"]*)"
,→ "(?<http_user_agent>[^"]*)" "(?<http_x_forwarded_for>[^"]*)"
113 Time_Key time_local
114 Time_Format %d/%b/%Y:%H:%M:%S %z
115 Time_Keep On

Here 192.168.1.20 is the IP address of our virtual machine running Opensearch.

Make sure to use the password from section 1.2

4.5 Update Fluentbit


Run these commands to apply the new configuration and restart our pods

kubectl apply -f fluent-bit-nginx-config.yaml


kubectl delete pods -n kube-system -l name=fluent-bit

IMPORTANT: Note down the ClusterIP of the nginx service as we’ll need it later

5 Generating / Simulating fake traffic


We can use a script traffic.sh to simulate fake traffic

14
1 #!/bin/bash
2

3 # ------------------------
4 # Configuration
5 # ------------------------
6 NGINX_URL="http://10.104.189.119" # Replace with actual NGINX endpoint
7 REQUESTS=200 # Number of total requests
8 METHODS=("GET" "POST" "HEAD")
9 PATHS=("/" "/redirect" "/forbidden" "/notfound")
10 USER_AGENTS=(
11 "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
12 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
13 "curl/7.68.0"
14 "PostmanRuntime/7.28.0"
15 )
16

17 # ------------------------
18 # Helper Functions
19 # ------------------------
20

21 # Generate a random IP
22 function random_ip() {
23 echo "$((RANDOM % 256)).$((RANDOM % 256)).$((RANDOM % 256)).$((RANDOM % 256))"
24 }
25

26 # Pick a random element from array


27 function pick_random() {
28 local array=("$@")
29 echo "${array[$RANDOM % ${#array[@]}]}"
30 }
31

32 # ------------------------
33 # Main Loop
34 # ------------------------
35

36 echo "Sending $REQUESTS requests to $NGINX_URL ..."


37 for ((i = 1; i <= REQUESTS; i++)); do
38 METHOD=$(pick_random "${METHODS[@]}")
39 PATHH=$(pick_random "${PATHS[@]}")
40 IP=$(random_ip)
41 UA=$(pick_random "${USER_AGENTS[@]}")
42

43 curl -s -o /dev/null -X "$METHOD" "$NGINX_URL$PATHH" \


44 -H "X-Forwarded-For: $IP" \
45 -H "User-Agent: $UA"
46

47 sleep $((RANDOM % 2 + 1)) # Add some delay (1{2 sec)


48 done

15
49

50 echo "Traffic generation completed."

Update the NGINX URL to point to the ClusterIP we found in section 4.5

6 Creating Visualizations in Opensearch Dashboards


6.1 Accessing Opensearch dashboards
Open a browser and goto http://OPENSEARCH VM IP:5601

Then login with the username admin and the password we gave earlier in section 1.2

6.2 Create Index Pattern


1. In the left navigation pane, go to Dashboards Management → Index Management.

2. Click the Create index pattern button.

3. In the ”Index pattern name” field, enter: nginx-*

4. Click Next step.

5. From the ”Time filter field name” dropdown, select: @timestamp

6. Click Create index pattern.

16
6.3 Create Scripted Field for Request Method
(Needed for Visualization 3)
1. In the left navigation pane, go to Dashboards Management → Index Management.
2. Select the nginx-* index pattern.
3. Go to the Scripted Fields tab.
4. Click Add scripted field.
5. Fill in the details:
• Name: http method
• Language: painless
• Type: string
• Format: Default
• Script:
if (doc['request.keyword'].size() > 0) {
String requestLine = doc['request.keyword'].value;
String[] parts = requestLine.splitOnToken(' ');
if (parts.length > 0) {
return parts[0];
}
}
return null;

17
6. Click Create field.

18
6.4 Check Opensearch Dashboard - Discovery Page
We can now open the Discovery page of our Opensearch Dashboard and check if the log data from
NGINX is visible

6.5 Create Dashboard


1. In the left navigation pane, go to Dashboard.

2. Click Create new dashboard.

3. Click the Add button.

6.6 Create Visualizations


6.6.1 Visualization 1: Requests by Status Code (Pie Chart)
1. Click Create new visualization.

2. Select Pie.

3. Select index pattern: nginx-*

4. In the ”Buckets” section:

• Click Add → Split slices.


• Aggregation: Terms
• Field: status.keyword
• Size: 10

19
5. Click the Update button to refresh the visualization.

6. Click Save and save as ”Requests by Status Code”.

6.6.2 Visualization 2: Top 10 Requesting IPs (Data Table)


1. Click Create new visualization.

2. Select Data Table.

3. Select index pattern: nginx-*

4. In the ”Buckets” section:

• Click Add → Split rows.


• Aggregation: Terms
• Field: http x forwarded for.keyword
• Size: 10
• Order By: Metric: Count
• Order: Descending

5. Click the Update button.

6. Click Save and save as ”Top 10 Requesting IPs”.

6.6.3 Visualization 3: Request Method Distribution (Vertical Bar Chart)


1. Click Create new visualization.

2. Select Vertical Bar.

3. Select index pattern: nginx-*

4. In the ”Buckets” section:

• Click Add → X-axis.


• Aggregation: Terms
• Field: http method (Scripted Field)
• Size: 10

5. Click the Update button.

6. Click Save and save as ”Request Method Distribution”.

20
6.6.4 Visualization 4: User-Agent Distribution (Horizontal Bar Chart)
1. Click Create new visualization.

2. Select Horizontal Bar.

3. Select index pattern: nginx-*

4. In the ”Buckets” section:

• Click Add → Y-axis.


• Aggregation: Terms
• Field: http user agent.keyword
• Size: 10

5. Click the Update button.

6. Click Save and save as ”User-Agent Distribution”.

6.7 Save Dashboard


1. After adding all visualizations to your dashboard, click the Save button.

2. Name it ”Nginx Log Analysis Dashboard”.

3. Click Save dashboard.

Now your dashboard should look like this:

21

You might also like