Install the ELK stack on CentOS using Ansible
Create server, configure inventory
Create Droplet on Digital Ocean using CentOS 8.3 x64 with 4GB memory and 2 vCPUs configuring an SSH key to make easy access to it.
We can probably use other version of CentOS as well, but this is what I tried it with.
From the Digital Ocean web site copy the IP address of the drolet and add it to the inventory file replacing the IP address you find there:
examples/ansible/elk/inventory.yml
elastic: hosts: 68.183.26.18 all: children: elastic:
Verify that we have access to the server using Ansible Ping
ansible NAME -m ping
First it will want to verify the fingerprint of the server:
The authenticity of host '134.122.123.157 (134.122.123.157)' can't be established. ECDSA key fingerprint is SHA256:L1jIJx45fOP3lFH/qQysD7tAdY9/rNoeC+eA2mO4ijY. Are you sure you want to continue connecting (yes/no/[fingerprint])?
Type in "yes" and press enter.
Then the response is expected to look like this:
134.122.123.157 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/libexec/platform-python" }, "changed": false, "ping": "pong" }
Try the same with our first playbook:
ansible-playbook playbooks/ping.yml
The response is expected to be:
PLAY [all] **************************************************************************************** TASK [Gathering Facts] **************************************************************************** ok: [104.236.61.19] TASK [Ping] *************************************************************************************** ok: [104.236.61.19] PLAY RECAP **************************************************************************************** 104.236.61.19 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
examples/ansible/elk/playbooks/ping.yml
--- - hosts: all tasks: - name: Ping ansible.builtin.ping:
See Ping module
Fetch the hostname of the server
OK, so this is not necessary to our task, but I like to see it working.
examples/ansible/elk/playbooks/hostname.yml
--- - hosts: all tasks: - name: Bash ansible.builtin.shell: hostname register: response - debug: msg="{{ response.stdout }}"
ansible-playbook playbooks/hostname.yml
Output:
PLAY [all] *************************************************************************************** TASK [Gathering Facts] *************************************************************************** ok: [104.236.61.19] TASK [Bash] ************************************************************************************** changed: [104.236.61.19] TASK [debug] ************************************************************************************* ok: [104.236.61.19] => { "msg": "elk1" } PLAY RECAP *************************************************************************************** 104.236.61.19 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
See Ansible shell module.
Install Elasticsearch
The version of ElasticSearch is baked into the playbook file. You can visit the download page of Elasticsearch to pick a different version.
examples/ansible/elk/playbooks/elasticsearch.yml
--- - hosts: all gather_facts : no vars: elastic: elasticsearch-7.11.2-x86_64.rpm project_root: /root tasks: - get_url: url="https://artifacts.elastic.co/downloads/elasticsearch/{{elastic}}" dest="{{project_root}}/{{elastic}}" - name: Check if Elastic is installed command: rpm -q elasticsearch ignore_errors: True register: rpm_check - name: Install ansible.builtin.shell: rpm -vi {{elastic}} when: rpm_check.rc != 0 - name: Enable and Start ansible.builtin.service: name: elasticsearch state: started enabled: yes - name: Copy configuration file copy: src: ../files/etc/elasticsearch/elasticsearch.yml dest: /etc/elasticsearch/elasticsearch.yml # - name: Configure Elasticsearch Cluster # lineinfile: # destfile: /etc/elasticsearch/elasticsearch.yml # regexp: 'cluster.name:' # line: 'cluster.name: code-maven-demo' # # - name: Configure Elasticsearch Node # lineinfile: # destfile: /etc/elasticsearch/elasticsearch.yml # regexp: 'node.name:' # line: 'node.name: code-maven-elastic-1' # # - name: Configure Elasticsearch Node Master # lineinfile: # destfile: /etc/elasticsearch/elasticsearch.yml # regexp: 'node.master:' # line: 'node.master: true' # # - name: Configure Elasticsearch Node Data # lineinfile: # destfile: /etc/elasticsearch/elasticsearch.yml # regexp: 'node.data:' # line: 'node.data: true' # # - name: Configure Elasticsearch Single-host # lineinfile: # destfile: /etc/elasticsearch/elasticsearch.yml # regexp: 'discovery.type:' # line: 'discovery.type: single-node' - name: Restart ansible.builtin.service: name: elasticsearch state: restarted - name: Verify Elasticsearch ansible.builtin.shell: curl http://localhost:9200 register: response - debug: msg="{{ response.stdout }}"
ansible-playbook playbooks/elasticsearch.yml
examples/ansible/elk/files/etc/elasticsearch/elasticsearch.yml
# ======================== Elasticsearch Configuration ========================= # # NOTE: Elasticsearch comes with reasonable defaults for most settings. # Before you set out to tweak and tune the configuration, make sure you # understand what are you trying to accomplish and the consequences. # # The primary way of configuring a node is via this file. This template lists # the most important settings you may want to configure for a production cluster. # # Please consult the documentation for further information on configuration options: # https://www.elastic.co/guide/en/elasticsearch/reference/index.html # # ---------------------------------- Cluster ----------------------------------- # # Use a descriptive name for your cluster: # cluster.name: code-maven-demo # # ------------------------------------ Node ------------------------------------ # # Use a descriptive name for the node: # node.name: code-maven-elastic-1 # # Add custom attributes to the node: # #node.attr.rack: r1 # # ----------------------------------- Paths ------------------------------------ # # Path to directory where to store the data (separate multiple locations by comma): # path.data: /var/lib/elasticsearch # # Path to log files: # path.logs: /var/log/elasticsearch # # ----------------------------------- Memory ----------------------------------- # # Lock the memory on startup: # #bootstrap.memory_lock: true # # Make sure that the heap size is set to about half the memory available # on the system and that the owner of the process is allowed to use this # limit. # # Elasticsearch performs poorly when the system is swapping the memory. # # ---------------------------------- Network ----------------------------------- # # Set the bind address to a specific IP (IPv4 or IPv6): # #network.host: 192.168.0.1 # # Set a custom port for HTTP: # #http.port: 9200 # # For more information, consult the network module documentation. # # --------------------------------- Discovery ---------------------------------- # # Pass an initial list of hosts to perform discovery when this node is started: # The default list of hosts is ["127.0.0.1", "[::1]"] # #discovery.seed_hosts: ["host1", "host2"] # # Bootstrap the cluster using an initial set of master-eligible nodes: # #cluster.initial_master_nodes: ["node-1", "node-2"] # # For more information, consult the discovery and cluster formation module documentation. # # ---------------------------------- Gateway ----------------------------------- # # Block initial recovery after a full cluster restart until N nodes are started: # #gateway.recover_after_nodes: 3 # # For more information, consult the gateway module documentation. # # ---------------------------------- Various ----------------------------------- # # Require explicit names when deleting indices: # #action.destructive_requires_name: true node.master: true node.data: true discovery.type: single-node #network.host: 0.0.0.0 #discovery.seed_hosts: ["1.2.3.4"]
Setup Nginx with simple authentication
Follow the instructions on how to configure http basic authentication for Nginx create one or more username/password pairs:
$ htpasswd -c .htpasswd user1 (pw: secret1) $ htpasswd .htpasswd user2 (pw: secret2)
examples/ansible/elk/files/etc/nginx/nginx.conf
# For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; # server { # listen 80 default_server; # listen [::]:80 default_server; # server_name _; # root /usr/share/nginx/html; # # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # # location / { # } # # error_page 404 /404.html; # location = /404.html { # } # # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } # Settings for a TLS enabled server. # # server { # listen 443 ssl http2 default_server; # listen [::]:443 ssl http2 default_server; # server_name _; # root /usr/share/nginx/html; # # ssl_certificate "/etc/pki/nginx/server.crt"; # ssl_certificate_key "/etc/pki/nginx/private/server.key"; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 10m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # # location / { # } # # error_page 404 /404.html; # location = /404.html { # } # # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } }
examples/ansible/elk/files/etc/nginx/conf.d/nginx-elk.conf
server { listen [::]:80; listen 80; # server_name _; location / { auth_basic "Kibana area"; auth_basic_user_file /usr/share/nginx/html/.htpasswd; proxy_pass http://localhost:5601; proxy_redirect off; proxy_buffering off; proxy_http_version 1.1; proxy_set_header Connection "Keep-Alive"; proxy_set_header Proxy-Connection "Keep-Alive"; } } server { listen [::]:81; listen 81; # server_name _; location / { auth_basic "Elasticsearch"; auth_basic_user_file /usr/share/nginx/html/.htpasswd; proxy_pass http://localhost:9200; proxy_redirect off; proxy_buffering off; proxy_http_version 1.1; proxy_set_header Connection "Keep-Alive"; proxy_set_header Proxy-Connection "Keep-Alive"; } }
Then run the playbook:
ansible-playbook playbooks/nginx.yml
examples/ansible/elk/playbooks/nginx.yml
--- - hosts: all gather_facts : no vars: project_root: /root tasks: - name: Enable epel yum: name: epel-release state: present - name: Install Nginx yum: name: nginx state: present - name: Enable and Start ansible.builtin.service: name: nginx state: started enabled: yes - name: Nginx config file copy: src: ../files/etc/nginx/nginx.conf dest: /etc/nginx/nginx.conf - name: Nginx config file copy: src: ../files/etc/nginx/conf.d/nginx-elk.conf dest: /etc/nginx/conf.d/nginx-elk.conf - name: Nginx users file copy: src: ../files/usr/share/nginx/html/.htpasswd dest: /usr/share/nginx/html/.htpasswd - name: Allow Nginx to work as a reverse proxy ansible.builtin.shell: setsebool httpd_can_network_connect on -P - name: Restart ansible.builtin.service: name: nginx state: restarted
Visit http://IP:81 after replacing IP with the IP address of your host to get access to Elasticsearch
Kibana
examples/ansible/elk/playbooks/kibana.yml
--- - hosts: all gather_facts : no vars: kibana: kibana-7.11.2-x86_64.rpm project_root: /root tasks: - get_url: url="https://artifacts.elastic.co/downloads/kibana/{{kibana}}" dest="{{project_root}}/{{kibana}}" - name: Check if Kibana is installed command: rpm -q kibana ignore_errors: True register: rpm_check - name: Install ansible.builtin.shell: rpm -vi {{kibana}} when: rpm_check.rc != 0 - name: Enable and Start ansible.builtin.service: name: kibana state: started enabled: yes - name: Copy configuration file copy: src: ../files/etc/kibana/kibana.yml dest: /etc/kibana/kibana.yml - name: Restart ansible.builtin.service: name: kibana state: restarted
Metricbeat
examples/ansible/elk/playbooks/metricbeat.yml
--- - hosts: all vars: metricbeat: metricbeat-7.11.2-x86_64.rpm project_root: /root tasks: - get_url: url="https://artifacts.elastic.co/downloads/beats/metricbeat/{{metricbeat}}" dest="{{project_root}}/{{metricbeat}}" - name: Check if Metricbeat is installed command: rpm -q metricbeat ignore_errors: True register: rpm_check - name: Install ansible.builtin.shell: rpm -vi {{metricbeat}} when: rpm_check.rc != 0 - name: Enable and Start ansible.builtin.service: name: metricbeat state: started enabled: yes - name: Copy config file copy: src: ../files/etc/metricbeat/metricbeat.yml dest: /etc/metricbeat/metricbeat.yml - name: Restart ansible.builtin.service: name: metricbeat state: restarted
ELK
examples/ansible/elk/playbooks/elk.yml
--- - include: nginx.yml - include: elasticsearch.yml - include: kibana.yml - include: metricbeat.yml
Ansible Configuration file
examples/ansible/elk/ansible.cfg
[defaults] deprecation_warnings = False inventory = inventory.yml host_key_checking = True remote_user=root #ask_pass = True
Published on 2021-04-10