How to pipe data from PostgreSQL into Elasticsearch using logstash

How to pipe data from PostgreSQL into Elasticsearch using logstash

elk_postgresql_integration

Test Environment

Fedora 32 installed
Docker and Docker compose installed

Here in this article we will see how we can ingest or pipe the data from postgres sql database table into the elasticsearch for indexing. We will be setting up a database table in postgres sql. We will be using the logstash with JDBC plugin to collect this postgres sql data and output it to elasticsearch index. Then we will be using kibana to visualize the data that has been indexed in elasticsearch.

Procedure

Step1: Setup elasticsearch and kibana using docker compose

As a first step. let’s setup the elasticsearch and kibana service using the below docker compose file. We are setting up a two nodes elasticsearch cluster with kibana. Please note we have used the volume mount ‘/apps/elasticsearch/data’ which is created on host machine and mapped to ‘/usr/share/elasticsearch/data’ for data persistence.

[admin@fedser32 kibana-docker]$ cat docker-compose.yml
version: '3'
services:
  odfe-node1:
    image: amazon/opendistro-for-elasticsearch:1.12.0
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"
    container_name: odfe-node1
    environment:
      - cluster.name=odfe-cluster
      - node.name=odfe-node1
      - discovery.seed_hosts=odfe-node1,odfe-node2
      - cluster.initial_master_nodes=odfe-node1,odfe-node2
      - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
      - "ES_JAVA_OPTS=-Xms4096m -Xmx4096m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536 # maximum number of open files for the Elasticsearch user, set to at least 65536 on modern systems
        hard: 65536
    volumes:
      - /apps/elasticsearch/data:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
      - 9600:9600 # required for Performance Analyzer
    networks:
      - odfe-net
  odfe-node2:
    image: amazon/opendistro-for-elasticsearch:1.12.0
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"
    container_name: odfe-node2
    environment:
      - cluster.name=odfe-cluster
      - node.name=odfe-node2
      - discovery.seed_hosts=odfe-node1,odfe-node2
      - cluster.initial_master_nodes=odfe-node1,odfe-node2
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms4096m -Xmx4096m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - /apps/elasticsearch/data:/usr/share/elasticsearch/data
    networks:
      - odfe-net
  kibana:
    image: amazon/opendistro-for-elasticsearch-kibana:1.12.0
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"
    container_name: odfe-kibana
    ports:
      - 5601:5601
    expose:
      - "5601"
    environment:
      ELASTICSEARCH_URL: https://odfe-node1:9200
      ELASTICSEARCH_HOSTS: https://odfe-node1:9200
    networks:
      - odfe-net

#volumes:
#  odfe-data1:
#  odfe-data2:

networks:
  odfe-net:

Once the docker compose file is prepared and required volume mounts created on host machine, We can start the elasticsearch and kibana service as shown below.

[admin@fedser32 kibana-docker]$ docker-compose up -d
Starting odfe-kibana ... done
Starting odfe-node2  ... done
Starting odfe-node1  ... done

Step2: Setup Postgre SQL database using docker compose

Now. let’s us setup our Postgre SQL database using the below docker compose file. Here we have configured the environment variables database, user, password which we will be using to connect to the database once the service is up and running.

[admin@fedser32 postgres-docker]$ cat docker-compose.yml 
version: '2.1'
services:
  db:
    image: postgres
    ports:
      - "5432:5432"
    volumes:
      - ./pg-data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: inventorydb
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres 

Once the docker compose file is ready, we can start the postgres sql database service as shown below.

[admin@fedser32 postgres-docker]$ docker-compose up -d
Starting postgres-docker_db_1 ... done

Step3: Create a table and insert data

Here, we will connect to our Postgre SQL server which is running within the container on port 5432 as shown below.

[admin@fedser32 Postgres-ELK-Docker]$ psql -U postgres -p 5432 -h localhost -W

Now lets connect to the database named ‘inventorydb’ in which we will be creating our table and insert the data.

postgres=# \c inventorydb

Lets create the table named booksdb with four varchar fields as shown below.

inventorydb=# CREATE TABLE booksdb(title VARCHAR(32), firstname VARCHAR(32), lastname VARCHAR(32), publisher VARCHAR(64));
CREATE TABLE

Now, let’s insert the data into the table which we just created. Here we are inserting some data related to books.

inventorydb=# INSERT INTO booksdb(title, firstname, lastname, publisher) VALUES('Learning Python 5th Edition', 'Mark', 'Lutz', 'Orielly');
INSERT 0 1
inventorydb=# INSERT INTO booksdb(title, firstname, lastname, publisher) VALUES('Mastering Elastic Stack', 'Yuvraj', 'Gupta', 'Packt');
INSERT 0 1
inventorydb=# INSERT INTO booksdb(title, firstname, lastname, publisher) VALUES('Head First Python', 'Paul', 'Barry', 'Orielly');
INSERT 0 1

Let’s verify our table ‘booksdb’ for the data that we inserted.

inventorydb=# select * from booksdb;
            title            | firstname | lastname | publisher 
-----------------------------+-----------+----------+-----------
 Learning Python 5th Edition | Mark      | Lutz     | Orielly
 Mastering Elastic Stack     | Yuvraj    | Gupta    | Packt
 Head First Python           | Paul      | Barry    | Orielly
(3 rows)

Step4: Dwonload the Postgre SQL JDBC driver jar

Now, in order to integrate logstash with Postgre SQL database to collect the data we will need Postgre SQL database driver which needs to be configured in the JDBC input plugin. You can download the latest avilable version of this driver from the below download page.

Download URL – https://jdbc.postgresql.org/download.html

[admin@fedser32 logstashoss-docker]$ ls -ltr /apps/logstash/postgresql-42.2.22.jar
-rwxrwxrwx. 1 admin admin 1005173 Jul  5 17:14 /apps/logstash/postgresql-42.2.22.jar

Step5: Create a logstash.conf to pipe data from Postgre SQL database and index in Elasticsearch

Lets now prepare our logstash.conf file in which we need to define our source of input and destination to which we would like to send the data. As shown below, we are using the JDBC input plugin here to configure our database input source by defining the jdbc driver jar file, drive class name, connection string url, jdbc username and password. Also we have defined the schedule at which the logstash need to run SQL statement to collect the data from the Postgre SQL database. The statement that we have defined here is select statement which will collect all the rows available in the table.

[admin@fedser32 logstashoss-docker]$ cat logstash.conf 
input {
  jdbc {
    jdbc_driver_library => "/usr/share/logstash/postgresql-42.2.22.jar"
    jdbc_driver_class => "org.postgresql.Driver"
    jdbc_connection_string => "jdbc:postgresql://localhost:5432/inventorydb"
    jdbc_user => "postgres"
    jdbc_password => "postgres"
    schedule => "* * * * *"
    statement => "SELECT * from booksdb"
  }
}

output {
  stdout {
    codec => rubydebug
  }
}

output {
    elasticsearch {
        hosts => ["https://localhost:9200"]
        index => "booksdata"
        ssl => true
        ssl_certificate_verification => false
        user => "admin"
        password => "admin@1234"
    }
}

Step7: Update the logstash docker-compose with the logstash.conf

Now, let’s configure our logstash service with the jdbc driver jar file and logstash.conf file volume mounted. Here i have also used the self signed certificate and key file to configure the logstash which is optional can be removed for testing purpose. Also please note the volume mount ‘/apps/logstash/data’ created on host machine to persist the logstash data mapped within container at ‘/usr/share/logstash/data’.

[admin@fedser32 logstashoss-docker]$ cat docker-compose.yml 
version: '2.1'
services:
  logstash:
    image: docker.elastic.co/logstash/logstash-oss:7.9.1
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"
    ports:
      - "5044:5044"
    depends_on:
      - db
    environment:
      - PIPELINE_WORKERS=1
      - PIPELINE_BATCH_SIZE=125
      - PIPELINE_BATCH_DELAY=50
    volumes:
      - $PWD/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
      - $PWD/server.crt:/etc/server.crt
      - $PWD/server.key:/etc/server.key
      - /apps/logstash/data:/usr/share/logstash/data
      - /apps/logstash/postgresql-42.2.22.jar:/usr/share/logstash/postgresql-42.2.22.jar

Start the logstash oss service using the docker compose file as shown below.

[admin@fedser32 logstashoss-docker]$ docker-compose up -d
Creating network "logstashoss-docker_default" with the default driver
Creating logstashoss-docker_logstash_1 ... done

Step8: Validate the logstash service logs

Here you can see that logstash service which is collecting the data from Postgres SQL database which further will be sent to elasticsearch for indexing.

[admin@fedser32 logstashoss-docker]$ docker-compose logs -f logstash
...
logstash_1  | [2021-10-05T05:24:00,309][INFO ][logstash.inputs.jdbc     ][main][6d86c188d1be3b42f2a7b7d4bd8b349abcea27452c16dd9c4787840c8ebcd206] (0.001130s) SELECT * from booksdb
logstash_1  | {
logstash_1  |      "publisher" => "Orielly",
logstash_1  |     "@timestamp" => 2021-10-05T05:24:00.312Z,
logstash_1  |       "lastname" => "Lutz",
logstash_1  |      "firstname" => "Mark",
logstash_1  |          "title" => "Learning Python 5th Edition",
logstash_1  |       "@version" => "1"
logstash_1  | }
logstash_1  | {
logstash_1  |      "publisher" => "Packt",
logstash_1  |     "@timestamp" => 2021-10-05T05:24:00.312Z,
logstash_1  |       "lastname" => "Gupta",
logstash_1  |      "firstname" => "Yuvraj",
logstash_1  |          "title" => "Mastering Elastic Stack",
logstash_1  |       "@version" => "1"
logstash_1  | }
logstash_1  | {
logstash_1  |      "publisher" => "Orielly",
logstash_1  |     "@timestamp" => 2021-10-05T05:24:00.313Z,
logstash_1  |       "lastname" => "Barry",
logstash_1  |      "firstname" => "Paul",
logstash_1  |          "title" => "Head First Python",
logstash_1  |       "@version" => "1"
logstash_1  | }

Step9: Validate the Elasticsearch index for SQL data

Now, we can go to Kibana service and add the booksdata index to discover our indexed data which is Postgre SQL database entries.

So, here we have seen how we can synchronize the data from Postgre SQL database into the Elasticsearch for indexing using the logstash JDBC input plugin.

Hope you enjoyed reading this article. Thank you..