Elasticsearch, Configuration

Posted on lun. 26 juin 2017 in Elasticsearch

Les paramètres par défaut d'Elasticsearch ne sont pas mauvais, mais je vais détailler ici la configuration qu'il faut vérifier, et éventuellement modifier pour avoir un cluster près pour la production.

Attention: La configuration qui sera donnée ici n'est pas une configuration "aux petits oignons" pour une production exigeante. Il s'agit surtout de montrer la configuration minimale à modifier pour avoir un cluster Elasticsearch prêt à fonctionner dans de bonnes conditions, redondant et scalable.

Toute la configuration se fait dans un fichier elasticsearch.yml. Vous trouverez plus de documentation sur la page officielle.

Paths

Il y a 2 paramètres path.* à regarder, dont un particulièrement important :

#################################### Paths ####################################

# Path to directory where to store index data allocated for this node.
#
path.data: /mnt/data

# Path to log files:
#
path.logs: /var/log/elasticsearch

Je ne m'étendrais que sur path.data. C'est là que vont se retrouver les fichiers utilisés par Elasticsearch pour le stockage de ses donnnées. Il est de bon ton de les mettre sur une partition séparée, la plus grosse possible, en fonction de la quantité de données que vous pensez devoir stocker.

Cluster Name

Le paramètre cluster.name est important car votre serveur Elasticsearch ne pourra rejoindre qu'un seul cluster, et ce cluster aura le nom configuré avec ce paramètre.

################################### Cluster ###################################

# Cluster name identifies your cluster for auto-discovery. If you're running
# multiple clusters on the same network, make sure you're using unique names.
#
cluster.name: elk4logs-int

Assurez-vous que ce nom est unique au sein de votre réseau, sinon vous pourriez vous retrouvez avec un serveur joignant le mauvais cluster.

Node Name

Chaque serveur Elasticsearch doit avoir un nom unique qui l'identifie au sein de son cluster. Vous pouvez, soit lui indiquer un nom , celui que vous souhaitez, soit juste mettre le hostname.

#################################### Node #####################################
node.name: ${HOSTNAME}

Si votre serveur/VM a déjà un nom identifiable, utilisez-le, c'est le plus simple.

Memory

Elasticsearch est un logiciel écrit en Java, et il est donc important que votre JVM ne swappe pas. Pour cela, mettez à true le memory_lock.

################################### Memory ####################################

# Elasticsearch performs poorly when JVM starts swapping: you should ensure that
# it _never_ swaps.
#
# Set this property to true to lock the memory:
#
bootstrap.memory_lock: true

Attention : Pour que ce paramètre fontionne correctement, il y a quelques manipulations à effectuer sur votre système linux avant.

Network

Par défaut, Elasticsearch bind sur 127.0.0.1. Il n'écoutera que les connexions locales. Pour se mettre en cluster, il faut pouvoir écouter sur le réseau.

################################### Network ###################################
network.host: 192.168.1.10

Attention : Ici se place un potentiel problème de sécurité. Soyez sûr que votre serveur Elasticsearch est bien protégé. Typiquement, il ne doit jamais écouter sur le WAN (internet). Elasticsearch, par défaut n'embarque pas de mécanisme d'authentification/autorisation d'accès. Il doit être protégé avec des règles pare-feu qui vont bien.

Discovery

Il faut indiquer à vos serveurs Elasticsearch au moins un autre serveur qui fera parti du même cluster que lui (dans le cas d'une installation en cluster). Cela se fait avec discovery.zen.ping.unicast.hosts.

Il n'est pas important d'y faire figurer tous les serveurs d'un même cluster. Typiquement, si vous montez un cluster de plusieurs dizaines ou centaines de nœuds, cela rendrait votre configuration horrible et inutile. Un seul suffit, mais si vous avez plus de 3 serveurs, indiquer ici 3 IP/hostname me semble pas mal.

Le second paramètre discovery.zen.minimum_master_nodes indique le nombre minimum de serveurs capable d'agir en tant que master qui doivent se voir pour commencer à former un cluster. Ce point est important pour éviter un split-brain du cluster. plus d'informations sur elastic.co.

################################## Discovery ##################################

# Pass an initial list of hosts to perform discovery when new node is started:
#
discovery.zen.ping.unicast.hosts:
   - 192.168.1.10:9300
   - 192.168.1.11 
   - seeds.mydomain.com

# Prevent the "split brain" by configuring the majority of nodes (total number of nodes / 2 + 1):
#
discovery.zen.minimum_master_nodes: 2

Shards & Replica

Pour terminer, je vous recommande également de configurer un nombre de shards et de replica par défaut. Ces valeurs peuvent être modifiées lors de la création d'une nouvelle "database" dans Elasticsearch, mais j'aime en mettre pour les cas où l'appli qui utilisera Elasticsearch ne le ferait pas elle-même.

Idéalement, le nombre de shards devrait être suppérieur ou égal au nombre total de nœuds de stockage prévu au final. Cela peut paraître compliqué/vague, mais je développerai cela dans un prochain blogpost.

################################ Shards & Replica #############################
index.number_of_shards: 12
index.number_of_replicas: 1

Exemple

Voici en example un fichier de configuration elasticsearch.yml complet que j'utilise sur un de mes clusters actuellement en prod (petit cluster de 12 nœuds utilisé pour le stockage de logs).

L'avantage de ce fichier de configuration est qu'il est le même pour tous mes serveurs propres au cluster team_ELK. Le seul paramètre unique à chaque serveur est network.publish_host que je change avec un petit sed à l'installation pour mettre l'IP locale de la machine. (Et cette configuration fonctionne aussi en docker ;-))

#################################### Paths ####################################

# Path to directory where to store index data allocated for this node.
#
path.data: /mnt/data

# Path to temporary files:
#
path.work: /tmp/ELK-elasticsearch

# Path to log files:
#
path.logs: /srv/app/log

# Path to where plugins are installed:
#
path.plugins: /srv/app/src/plugins

################################### Cluster ###################################

# Cluster name identifies your cluster for auto-discovery. If you're running
# multiple clusters on the same network, make sure you're using unique names.
#
cluster.name: team_ELK

################################### Memory ####################################

# Elasticsearch performs poorly when JVM starts swapping: you should ensure that
# it _never_ swaps.
#
# Set this property to true to lock the memory:
#
bootstrap.mlockall: true

# Make sure that the ES_MIN_MEM and ES_MAX_MEM environment variables are set
# to the same value, and that the machine has enough memory to allocate
# for Elasticsearch, leaving enough memory for the operating system itself.
#
# You should also make sure that the Elasticsearch process is allowed to lock
# the memory, eg. by using `ulimit -l unlimited`.

############################## Network And HTTP ###############################

# Set the bind address specifically (IPv4 or IPv6):
#
network.bind_host: 0.0.0.0

# Set the address other nodes will use to communicate with this node. If not
# set, it is automatically derived. It must point to an actual IP address.
#
network.publish_host: 192.168.6.1

# Set both 'bind_host' and 'publish_host':
#
#network.host: 192.168.0.1

# Set a custom port for the node to node communication (9300 by default):
#
transport.tcp.port: 9300

# Set a custom port to listen for HTTP traffic:
#
http.port: 8888

# --------------------------------- Discovery ----------------------------------
#
# Pass an initial list of hosts to perform discovery when new node is started:
#
discovery.zen.ping.unicast.hosts: ["elkdb01.ma.superboite.net:9300", "elkdb02.ma.superboite.net:9300", "elkdb03.ma.superboite.net:9300"]
#
# Prevent the "split brain" by configuring the majority of nodes (total number of nodes / 2 + 1):
#
discovery.zen.minimum_master_nodes: 7


# ------------------------------ Shards & Replica ------------------------------
index.number_of_shards: 12
index.number_of_replicas: 1
cluster.routing.allocation.enable: all