Table of Contents

Guía para instalar múltiples clusters ElasticSearch en un mismo sistema

Esta guía muestra los pasos básicos para poder instalar dentro de un mismo sistema, varios clusters ElasticSearch (No confundir con instalar múltiples nodos pertenecientes a un solo cluster). Se configurará un solo nodo por cluster (1 cluster - 1 nodo), cada uno de ellos tendrá una IP diferente y serán necesariamente independientes el uno del otro. Para tener dos IPs diferentes (usando la misma puerta de enlace) se pueden usar interfaces virtuales / alias (eth0, eth:0, eth:1), pero no es algo que se vaya a explicar en esta guía.

Tener dos clusters dentro de un mismo servidor, no suele ser un escenario muy habitual, pero puede ser interesante en algunos casos donde se requieran instancias totalmente separadas sin necesitar un uso elevado de recursos (normalmente entornos de pruebas). Si por la circunstancia que sea se pretende usar en producción, lo recomendable sería que cada cluster utilizase un disco duro diferente (punto de montaje).

Enlaces recomendados sobre ElasticSearch.

Para el ejemplo se usarán dos clusters de un solo nodo cada uno, “integration” y “staging”. A cada uno se le asignarán 6Gb de memoria RAM (ES_HEAP_SIZE) para ElasticSearch, sumando los dos cluster se utilizará un total de 12Gb para elasticsearch, por lo que un sistema de 24Gb es lo recomendado para un funcionamiento decente de las pruebas a realizar. Recordemos que solo el 50% de la memoria disponible debe ser dedicada a Elasticsearch .

Si los indices van a ser guardados en puntos de montaje específicos, estos deben tener como usuario propietario “elasticsearch”, dependiendo del sistema de ficheros utilizado, se deberá montar el punto de montaje especificando el id y gid del usuario elasticsearch. Si no se especifica un directorio o punto de montaje para los datos de ElasticSearch, estos serán guardados dentro del mismo directorio de elasticsearch (ej. /opt/elasticsearch_staging/data).

Descomprimir en “/opt/” y modificar los nombres para mantener cierto orden.

cp elasticsearch-2.2.1 elasticsearch-2.2.1_integration
ln -s elasticsearch-2.2.1_integration elasticsearch_integration
 
cp elasticsearch-2.2.1 elasticsearch-2.2.1_staging
ln -s elasticsearch-2.2.1_staging elasticsearch_staging

Crear en el sistema el usuario no privilegiado “elasticsearch”.

useradd -M -s /usr/sbin/nologin -c "ElasticSearch service" elasticsearch

Creamos el directorio para el pid y asignamos el usuario elasticsearch como propietario.

mkdir /var/run/elasticsearch_integration
mkdir /var/run/elasticsearch_staging
chown -R elasticsearch:elasticsearch /var/run/elasticsearch* /opt/elastic*
 
# Sólo si se tienen puntos de montaje específicos para guardar los indices.
# Puede ser necesario especificar el UID / GID al montar el disco / partición.
chown -R elasticsearch:elasticsearch /mnt/staging /mnt/integration

Se debe aumentar el número de ficheros abiertos que un usuario no privilegiado puede manejar y también eliminar el límite predeterminado de memoria asignada para el usuario elasticsearch. Para ello se debe editar el fichero “/etc/security/limits.conf” o bien ejecutar los siguientes comandos “ulimit”.

elasticsearch - nofile 100000
elasticsearch - memlock unlimited

# Quitar límites al bloqueo de memoria por linea de comandos.
# ulimit -l unlimited
# ulimit -SHn 10000

Si se desea que el límite de ficheros abiertos supere lo establecido por el kernel, se debe modificar también “sysctl fs.file-max”.

Lectura recomendada: Configurar el límite de ficheros abiertos en GNU/Linux

Configuración de Elasticsearch para cada cluster

Una de las cosas más importante en la configuración de los clusters es la especificación de puertos (http.port y transport.tcp.port), no se pueden especificar los puertos predeterminados en los dos nodos porque entrarían en conflicto. Para el ejemplo, el nodo “staging” utilizará los puertos predeterminados, aunque de todas maneras se han especificado en el fichero de configuración.

staging: /opt/elasticsearch_staging/config/elasticsearch.yml

cluster.name: staging
node.name: staging
path.data: /mnt/staging # Sólo si se usa un punto de montaje / directorio en concreto.

bootstrap.mlockall: true
network.host: ["10.10.200.89", "localhost"]
http.port: "9200-9300"
transport.tcp.port: "9300-9400"
transport.tcp.compress: true

http.cors.enabled: true
http.cors.allow-origin: "*"

action.destructive_requires_name: true
action.disable_shutdown: true

integration: /opt/elasticsearch_integration/config/elasticsearch.yml

cluster.name: integration
node.name: integration
path.data: /mnt/integration # Sólo si se usa un punto de montaje / directorio en concreto.
bootstrap.mlockall: true
network.host: ["10.10.200.90","localhost"]
http.port: "9000-9100"
transport.tcp.port: "9100-9199"
transport.tcp.compress: true

http.cors.enabled: true
http.cors.allow-origin: "*"

action.destructive_requires_name: true
action.disable_shutdown: true

Puertos / URL.

NOTA: En el caso de que otros nodos quisieran unirse a alguno de los dos cluster, estos deben utilizar el mismo rango de puertos en la opción “transport.tcp.port” para evitar problemas.

Scripts de inicio para cada cluster de ElasticSearch

A continuación se muestran los dos script de inicio para cada cluster, son idénticos en todo menos en las rutas utilizadas en las siguientes variables.

ES_HOME
LOG_DIR
DATA_DIR
CONF_DIR
PID_DIR

Script de inicio para el cluster staging: /etc/init.d/elasticsearch_staging

elasticsearch_staging
#!/bin/sh
#
# elasticsearch <summary>
#
# chkconfig:   2345 80 20
# description: Starts and stops a single elasticsearch instance on this system 
#
 
### BEGIN INIT INFO
# Provides: Elasticsearch
# Required-Start: $network $named
# Required-Stop: $network $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: This service manages the elasticsearch daemon
# Description: Elasticsearch is a very scalable, schema-free and high-performance search solution supporting multi-tenancy and near realtime search.
### END INIT INFO
 
#
# init.d / servicectl compatibility (openSUSE)
#
if [ -f /etc/rc.status ]; then
    . /etc/rc.status
    rc_reset
fi
 
#
# Source function library.
#
if [ -f /etc/rc.d/init.d/functions ]; then
    . /etc/rc.d/init.d/functions
fi
 
# Sets the default values for elasticsearch variables used in this script
ES_USER="elasticsearch"
ES_GROUP="elasticsearch"
ES_HOME="/opt/elasticsearch_staging"
MAX_OPEN_FILES=65535
MAX_MAP_COUNT=262144
LOG_DIR="/opt/elasticsearch_staging/log/"
DATA_DIR="/mnt/staging"
CONF_DIR="/opt/elasticsearch_staging/config"
PID_DIR="/var/run/elasticsearch_staging"
 
# Source the default env file
#ES_ENV_FILE="/opt/elasticsearch_staging/"
if [ -f "$ES_ENV_FILE" ]; then
    . "$ES_ENV_FILE"
fi
 
# CONF_FILE setting was removed
if [ ! -z "$CONF_FILE" ]; then
    echo "CONF_FILE setting is no longer supported. elasticsearch.yml must be placed in the config directory and cannot be renamed."
    exit 1
fi
 
exec="$ES_HOME/bin/elasticsearch"
prog="elasticsearch"
pidfile="$PID_DIR/${prog}.pid"
 
################
export ES_HEAP_SIZE=6G
export ES_HEAP_NEWSIZE
export ES_DIRECT_SIZE
export ES_JAVA_OPTS
export JAVA_HOME
export MAX_LOCKED_MEMORY=unlimited
export LimitMEMLOCK=infinity
export MAX_OPEN_FILES=262144
export MAX_MAP_COUNT=262144
###############
 
export ES_GC_LOG_FILE
export ES_STARTUP_SLEEP_TIME
 
lockfile=/var/lock/subsys/$prog
 
# backwards compatibility for old config sysconfig files, pre 0.90.1
if [ -n $USER ] && [ -z $ES_USER ] ; then 
   ES_USER=$USER
fi
 
checkJava() {
    if [ -x "$JAVA_HOME/bin/java" ]; then
        JAVA="$JAVA_HOME/bin/java"
    else
        JAVA=`which java`
    fi
 
    if [ ! -x "$JAVA" ]; then
        echo "Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"
        exit 1
    fi
}
 
start() {
    checkJava
    [ -x $exec ] || exit 5
    if [ -n "$MAX_LOCKED_MEMORY" -a -z "$ES_HEAP_SIZE" ]; then
        echo "MAX_LOCKED_MEMORY is set - ES_HEAP_SIZE must also be set"
        return 7
    fi
    if [ -n "$MAX_OPEN_FILES" ]; then
        ulimit -n $MAX_OPEN_FILES
    fi
    if [ -n "$MAX_LOCKED_MEMORY" ]; then
        ulimit -l $MAX_LOCKED_MEMORY
    fi
    if [ -n "$MAX_MAP_COUNT" -a -f /proc/sys/vm/max_map_count ]; then
        sysctl -q -w vm.max_map_count=$MAX_MAP_COUNT
    fi
    export ES_GC_LOG_FILE
 
    # Ensure that the PID_DIR exists (it is cleaned at OS startup time)
    if [ -n "$PID_DIR" ] && [ ! -e "$PID_DIR" ]; then
        mkdir -p "$PID_DIR" && chown "$ES_USER":"$ES_GROUP" "$PID_DIR"
    fi
    if [ -n "$pidfile" ] && [ ! -e "$pidfile" ]; then
        touch "$pidfile" && chown "$ES_USER":"$ES_GROUP" "$pidfile"
    fi
 
    cd $ES_HOME
    echo -n $"Starting $prog: "
    # if not running, start it up here, usually something like "daemon $exec"
    daemon --user $ES_USER --pidfile $pidfile $exec -p $pidfile -d -Des.default.path.home=$ES_HOME -Des.default.path.logs=$LOG_DIR -Des.default.path.data=$DATA_DIR -Des.default.path.conf=$CONF_DIR
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
 
stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    killproc -p $pidfile -d 86400 $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
 
restart() {
    stop
    start
}
 
reload() {
    restart
}
 
force_reload() {
    restart
}
 
rh_status() {
    # run checks to determine if the service is running or use generic status
    status -p $pidfile $prog
}
 
rh_status_q() {
    rh_status >/dev/null 2>&1
}
 
 
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?

Script de inicio para el cluster staging: /etc/init.d/elasticsearch_integration

elasticsearch_integration
#!/bin/sh
#
# elasticsearch <summary>
#
# chkconfig:   2345 80 20
# description: Starts and stops a single elasticsearch instance on this system 
#
 
### BEGIN INIT INFO
# Provides: Elasticsearch
# Required-Start: $network $named
# Required-Stop: $network $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: This service manages the elasticsearch daemon
# Description: Elasticsearch is a very scalable, schema-free and high-performance search solution supporting multi-tenancy and near realtime search.
### END INIT INFO
 
#
# init.d / servicectl compatibility (openSUSE)
#
if [ -f /etc/rc.status ]; then
    . /etc/rc.status
    rc_reset
fi
 
#
# Source function library.
#
if [ -f /etc/rc.d/init.d/functions ]; then
    . /etc/rc.d/init.d/functions
fi
 
# Sets the default values for elasticsearch variables used in this script
ES_USER="elasticsearch"
ES_GROUP="elasticsearch"
ES_HOME="/opt/elasticsearch_integration"
MAX_OPEN_FILES=65535
MAX_MAP_COUNT=262144
LOG_DIR="/opt/elasticsearch_integration/log/"
DATA_DIR="/mnt/integration"
CONF_DIR="/opt/elasticsearch_integration/config"
PID_DIR="/var/run/elasticsearch_integration"
 
if [ -f "$ES_ENV_FILE" ]; then
    . "$ES_ENV_FILE"
fi
 
# CONF_FILE setting was removed
if [ ! -z "$CONF_FILE" ]; then
    echo "CONF_FILE setting is no longer supported. elasticsearch.yml must be placed in the config directory and cannot be renamed."
    exit 1
fi
 
exec="$ES_HOME/bin/elasticsearch"
prog="elasticsearch"
pidfile="$PID_DIR/${prog}.pid"
 
################
export ES_HEAP_SIZE=6G
export ES_HEAP_NEWSIZE
export ES_DIRECT_SIZE
export ES_JAVA_OPTS
export JAVA_HOME
export MAX_LOCKED_MEMORY=unlimited
export LimitMEMLOCK=infinity
export MAX_OPEN_FILES=262144
export MAX_MAP_COUNT=262144
###############
 
export ES_GC_LOG_FILE
export ES_STARTUP_SLEEP_TIME
 
lockfile=/var/lock/subsys/$prog
 
# backwards compatibility for old config sysconfig files, pre 0.90.1
if [ -n $USER ] && [ -z $ES_USER ] ; then 
   ES_USER=$USER
fi
 
checkJava() {
    if [ -x "$JAVA_HOME/bin/java" ]; then
        JAVA="$JAVA_HOME/bin/java"
    else
        JAVA=`which java`
    fi
 
    if [ ! -x "$JAVA" ]; then
        echo "Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"
        exit 1
    fi
}
 
start() {
    checkJava
    [ -x $exec ] || exit 5
    if [ -n "$MAX_LOCKED_MEMORY" -a -z "$ES_HEAP_SIZE" ]; then
        echo "MAX_LOCKED_MEMORY is set - ES_HEAP_SIZE must also be set"
        return 7
    fi
    if [ -n "$MAX_OPEN_FILES" ]; then
        ulimit -n $MAX_OPEN_FILES
    fi
    if [ -n "$MAX_LOCKED_MEMORY" ]; then
        ulimit -l $MAX_LOCKED_MEMORY
    fi
    if [ -n "$MAX_MAP_COUNT" -a -f /proc/sys/vm/max_map_count ]; then
        sysctl -q -w vm.max_map_count=$MAX_MAP_COUNT
    fi
    export ES_GC_LOG_FILE
 
    # Ensure that the PID_DIR exists (it is cleaned at OS startup time)
    if [ -n "$PID_DIR" ] && [ ! -e "$PID_DIR" ]; then
        mkdir -p "$PID_DIR" && chown "$ES_USER":"$ES_GROUP" "$PID_DIR"
    fi
    if [ -n "$pidfile" ] && [ ! -e "$pidfile" ]; then
        touch "$pidfile" && chown "$ES_USER":"$ES_GROUP" "$pidfile"
    fi
 
    cd $ES_HOME
    echo -n $"Starting $prog: "
    # if not running, start it up here, usually something like "daemon $exec"
    daemon --user $ES_USER --pidfile $pidfile $exec -p $pidfile -d -Des.default.path.home=$ES_HOME -Des.default.path.logs=$LOG_DIR -Des.default.path.data=$DATA_DIR -Des.default.path.conf=$CONF_DIR
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
 
stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    killproc -p $pidfile -d 86400 $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
 
restart() {
    stop
    start
}
 
reload() {
    restart
}
 
force_reload() {
    restart
}
 
rh_status() {
    # run checks to determine if the service is running or use generic status
    status -p $pidfile $prog
}
 
rh_status_q() {
    rh_status >/dev/null 2>&1
}
 
 
case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?

Ya que aquí no se tratarán las opciones de rendimiento de ElasticSearch (ficheros abiertos, memoria RAM, etc), se recomienda encarecidamente leer el enlace sobre “rendimiento en ElasticSearch” del principio de la guía.

Arrancar los dos cluster ElasticSearch automáticamente en el inicio del sistema.

chkconfig --add elasticsearch_staging
chkconfig --add elasticsearch_integration
 
# Arrancar manualmente los clusters Elasticsearch
/etc/init.d/elasticsearch_staging {start|stop|status|restart|condrestart|try-restart|reload|force-reload}
/etc/init.d/elasticsearch_integration {start|stop|status|restart|condrestart|try-restart|reload|force-reload}
 
service elasticsearch_staging {start|stop|status|restart|condrestart|try-restart|reload|force-reload}
service elasticsearch_integration {start|stop|status|restart|condrestart|try-restart|reload|force-reload}

Establecer autenticación HTTP en ElasticSearch básica con shield (Ejecutar en cada nodo de cada cluster)

/opt/elasticsearch_integration/bin/plugin install license
/opt/elasticsearch_integration/bin/plugin install shield
/opt/elasticsearch_integration/bin/shield/esusers useradd admin -r admin

NOTA: Se debe reiniciar el servicio elasticsearch.

service elasticsearch_XXXX restart

Autenticación HTTP con Curl.

curl USUARIO:PASSWORD@XXXXXX:9200
curl -u USUARIO XXXXXX:9200