GCP Private Kubernetes cluster for Helm installation of Elasticsearch

In this article, I will list the steps needed to deploy an Elasticsearch cluster on a private Google Cloud Platform (GCP) Kubernetes cluster using Helm, from creating a docker image with Elasticsearch, to the creation of a private Kubernetes cluster and more.

Let’s begin.

Continuer la lecture de « GCP Private Kubernetes cluster for Helm installation of Elasticsearch »

Découverte de la gestion de log avec ELK

Dans le cadre de mon stage, je m’intéresse actuellement au solution de monitoring et j’ai donc eu l’occasion de tester le triplet Elasticsearch Logstash Kibana connu sous l’abréviation ELK. Logstash permet d’agréger simplement des logs provenant de différentes sources, Elasticsearch s’occupe de les stocker et de les rendre disponibles et enfin Kibana les affiche sur un dashboard hautement personnalisable. Les instructions qui suivent m’ont donc permis d’avoir un rapide aperçu du fonctionnement de la solution ELK en local et dans un cas très simple de gestion de logs système.

Récupération des logiciels

wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.0.1.tar.gz
wget https://download.elasticsearch.org/logstash/logstash/logstash-1.3.3-flatjar.jar
wget https://download.elasticsearch.org/kibana/kibana/kibana-3.0.0milestone5.tar.gz

Extraction

tar xvf elasticsearch-1.0.1.tar.gz
tar xvf kibana-3.0.0milestone5.tar.gz

Elasticsearch

cd elasticsearch-1.0.1/

La configuration elasticsearch.yml se situe dans config/. Il n’est pas nécessaire d’y toucher pour un test en local, on pourrait toutefois modifier les paramètres cluster.name et node.name pour personnaliser l’installation.

Démarrer Elasticsearch:

./bin/elasticsearch

Logstash

Création d’un fichier de configuration logstash.conf:

touch logstash.conf

Nous allons lire les fichiers de log du système, de ce fait, il pourrait être nécessaire de lancer Logstash en root pour que celui-ci puisse lire les fichiers de logs. Cette solution n’est à utiliser que pendant la phase de test.

Contenu du fichier:

input {
    file {
        type => "linux-syslog"
        path => [ "/var/log/*.log", "/var/log/messages", "/var/log/syslog" ]
    }
}
output {
    stdout { }
    elasticsearch_http {
        host => "127.0.0.1"
    }
}

Documentation pour le paramètre elasticsearch_http.

Démarrer Logstash:

sudo java -jar logstash-1.3.3-flatjar.jar agent -f logstash.conf

Les nouveaux logs devraient donc maintenant être récupérés par Logstash et stockés par Elasticsearch. Nous donc pouvoir les visualiser avec Kibana.

Kibana

cd kibana-3.0.0milestone5/

Éditer le fichier config.js et changer la ligne:

elasticsearch: "http://"+window.location.hostname+":9200",

en

elasticsearch: "http://127.0.0.1:9200",

Cette modification nous permet d’ouvrir le fichier index.html directement dans notre navigateur pour accéder à Kibana sans avoir besoin de mettre en place un serveur comme Apache pour servir les fichiers.

Résultat

KibanaL’ajout d’un mécanisme d’authentification pour l’accès à Kibana peut être réalisé simplement en utilisant le projet fangli/kibana-authentication-proxy.

ElasticSearch and the Mystery of Auto-completion

Few months ago, I was looking for information concerning auto-completion with ElasticSearch as a source. I found many solutions, but none of them really fit my needs. Nevertheless, it helped me building my request.

What’s the situation Doc?

I needed to be able to extract values from an indexed field in ElasticSearch according to a group of letters (user input). In fact, my indexed document contains a field named map which is an array of string. The idea is the following: if the user is looking for the value « name » for instance, let’s say he will first type « na ». So here we must be able to suggest searches to the user. Furthermore, with this 2 letters, we must proposed existing fields like « name », « native » or « nature ».

I’m using Elastical to interact with ElasticSearch.
First, I’m building a regex which will be used later in the request.

var search = req.body.searched.toLowerCase(),
firstLetter = search.charAt(0),
rest = req.body.searched.slice(1),
reg = "^["+firstLetter+firstLetter.toUpperCase()+"]"+rest+".*";

The regex is build to match with both an upper case char or a lower case one in first position.

What about the request?

var request = {
  query: {
    query_string: {
      default_field: "map",
      default_operator: "AND",
      query: req.body.searched+"*"
    }
  },
  facets:{
    map:{
      terms:{
        field: "map.exact",
        regex: reg,
        size: 10
      }
    }
  }
}

First, I’m asking ElasticSearch to retrieve all documents which match req.body.searched+ »* » where req.body.searched contains the user input. I’ve change the default operator to « AND » rather than « OR » in order to be able to deal with fields like « Nom de la gare » or « Name of the dog ». By default, ElasticSearch uses the « OR » operator, so it will ask for « name » OR « of » OR « the » OR « dog »; which is not what I wanted.

Then, I’m using facets to retrieve values in the field map of found documents matching the given regex. I’m using map.exact for the same reason I must use the « AND » operator.

This request works great with on the tests I’ve made. Remains to be seen if it can handle big indexes.

I can now ask ElasticSearch with Elastical and build a clean response:

elastical.search(request, function (err, results, full) {
  var terms = [];
  async.forEach(full.facets.map.terms, function(data, callback) {
    terms.push(data.term);
    callback();
  }, function(err) {
    res.send(terms);
  });
});

Node-Elastical: Implement stats function

Recently, I had to find the size of an index in Elasticsearch. I could have just built my query using request like this:

var request = require('request');
request.get('http://localhost:9200/' + myIndex + '/_stats'
  , function (err, res, body) {
    console.log(res._all.primaries.store.size_in_bytes);
});

Fast and easy. Since it’s not available yet in node-elastical, I found it better to add this functionality so that other people can use it. Implementing the stats function wasn’t difficult. It just require parsing options to create the right url and then making the request (with request) to Elasticsearch. I used the Indices Stats API documentation to create the function.

In file client.js

stats: function (options, callback) {
  var query = [],
  url = '',
  hasOptions;

  if (typeof options === 'function') {
    callback = options;
    options = {};
  }
  //Create a copy of options so we can modify it.
  options = util.merge(options || {});

  if (options.index) {
    url = '/' + encode(Array.isArray(options.index) ?
      options.index.join(',') : options.index);
    delete options.index;
    //Look for types only if there is an index
    if (options.types) {
      query.push(encode('types') + '=' + encode(
        Array.isArray(options.types) ?
        options.types.join(',') : options.types));
    }
    delete options.types;
  }

  url += '/_stats';

  util.each(options, function (value, name) {
    if (value === true || value === false) {
      value = value ? '1' : '0';
    }

    query.push(encode(name) + '=' + encode(value));
  });

  if (query.length) {
    url += '?' + query.join('&');
  }

  this._request(url, {
    method: 'GET'
  }, function (err, res) {
    if(err) { return callback(err, null, res), undefined; }
    callback(null, res);
  });
},
In file index.js
stats: function (options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = {};
  }
  this.client.stats(util.merge(options,{index: this.name}), callback);
},

Node-Elastical: Delete by query option

What is Elastical?

Elastical is a Node.js client library for the ElasticSearch REST API.

That’s it for the presentation.

Until a few weeks ago, it wasn’t possible to delete data by query without using a hack. The hack was the following:

client.delete('twitter', 'tweet', '', {q: 'user:Shay'} );

Here, we set id to an empty string and we use the options parameter to perform a search on user with value Shay. Not so practical at all.

Using curl to interact with ElasticSearch, it is possible to delete by query:

curl -XDELETE 'http://localhost:9200/twitter/tweet/_query' -d ' 
  { "term" : { "user" : "kimchy" } 
}
'

This handy way of deleting things in ElasticSearch was not possible with Elastical (unless, you managed to use the hack above).

So I’ve added a new parameter options.query which allow us to perform such a query more easily.

client.delete('twitter', 'tweet', '', {query:
  { "term" : { "user" : "kimchy" } } 
});

When using the query parameter, id and all other options except ignoreMissing will be ignored.

Let’s take a quick look at the code involved:

if(params.query) {
  url = '/' + encode(this.name) + '/' + encode(type) + '/_query';

  this.client._request(url, {method: 'DELETE', json: params.query}
  , function (err, res) {
    if (err) {
      if (ignoreMissing && res && res.found === false) {
        return callback(null, res), undefined;
      } else {
        return callback(err, res), undefined;
      }
    }
    callback(null, res);
  });
} else {

It’s pretty simple. First, we need to build the url, then we’re requesting ElasticSearch on the given url, passing the query in the json parameter. If options.query doesn’t exist, then the original code is used.

As a conclusion, delete by query is now available in Elastical and you should use it!

 

ElasticSearch: Delete By Query API