9-Elasticsearchのインストール及び設定　自動起動の検討

過去にはてなブログへ投稿した記事になります。

# はじめに
前回までで一通りの設定が終わりましたので、運用を簡単にするためにも自動化の検討をします。

# Elastic社公式のやり方を学ぶ
## 停止方法
https://www.elastic.co/guide/en/elasticsearch/reference/6.2/stopping-elasticsearch.html

```
$ ./bin/elasticsearch -p /tmp/elasticsearch-pid -d
$ cat /tmp/elasticsearch-pid && echo
15516
$ kill -SIGTERM 15516
```

上記のようにあくまでプロセスのKillで停止しています。（大胆だなぁ）

## RPMインストールで設定されるスクリプトを確認してみる

停止方法だけだとイマイチちゃんとしたものが作れないので、標準のsystemctlで実行しているスクリプトを確認したいと思います。

以下のようにサービスを有効化するとリンクが有効化されますので、そのファイルを確認してみました。

```
# systemctl enable elasticsearch.service
Created symlink from /etc/systemd/system/multi-user.target.wants/elasticsearch.service to /usr/lib/systemd/system/elasticsearch.service.
```

以下、標準の自動起動スクリプトの中身

```
[Unit]
Description=Elasticsearch   # メモ：Unitの説明文
Documentation=http://www.elastic.co # メモ：ドキュメントのURL
Wants=network-online.target # メモ：このUnitが必要とする前提Unit⇒自前systemctlで活用する
After=network-online.target # メモ：このUnitより先に起動するべきUnit⇒自前systemctlで活用する

[Service]
RuntimeDirectory=elasticsearch
Environment=ES_HOME=/usr/share/elasticsearch
Environment=ES_PATH_CONF=/etc/elasticsearch
Environment=PID_DIR=/var/run/elasticsearch
EnvironmentFile=-/etc/sysconfig/elasticsearch

WorkingDirectory=/usr/share/elasticsearch

User=elasticsearch
Group=elasticsearch

ExecStart=/usr/share/elasticsearch/bin/elasticsearch -p ${PID_DIR}/elasticsearch.pid --quiet

# StandardOutput is configured to redirect to journalctl since <===== ここから下も流用します。
# some error messages may be logged in standard output before
# elasticsearch logging system is initialized. Elasticsearch
# stores its logs in /var/log/elasticsearch and does not use
# journalctl by default. If you also want to enable journalctl
# logging, you can simply remove the "quiet" option from ExecStart.
StandardOutput=journal
StandardError=inherit

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536

# Specifies the maximum number of processes
LimitNPROC=4096

# Specifies the maximum size of virtual memory
LimitAS=infinity

# Specifies the maximum file size
LimitFSIZE=infinity

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=0

# SIGTERM signal is used to stop the Java process
KillSignal=SIGTERM

# Send the signal only to the JVM rather than its control group
KillMode=process

# Java process is never killed
SendSIGKILL=no

# When a JVM receives a SIGTERM signal it exits with code 143
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

# Built for distribution-6.2.2 (distribution)
```

# 自動起動の設定
Elastic社のやり方に習って自動起動を作成していきます

## PIDを格納するフォルダの作成
停止コマンドでも自動スクリプトでもPIDを元にプロセスの停止をしています。

起動時にこのPIDをファイルに書き込むのですが、そのファイルを保存するフォルダが必要となります。
/usr/lib配下にフォルダを作るのですが、RHEL7以降はちゃんと手順を踏まないと再起動したときに削除されてしまいます。

(1)/usr/lib/tmpfiles.d 配下に定義ファイルを作成

```
# vi /usr/lib/tmpfiles.d/my_auto_elasticsearch.conf
```

以下のように記述をします。

```
d /var/run/my_auto_elasticsearch 0755 elasticsearch elasticsearch
```

(2)OSの再起動を実施します。

(3)フォルダが作成されているか確認します。
例では「my_auto_elasticsearch」フォルダが出来ているはずです。

```
# ls /var/run
```

## systemctlで制御するスクリプトの作成
systemctlで制御するサービスと認識されるようにスクリプトの作成をします。

/etc/systemd/system　の配下に　サービス名.service のファイルを作成します。
「.service」部分が無いとsystemctlのサービスとして認識されないので注意が必要です。

(1)マスターノード起動/停止スクリプトの作成
　ノード毎に起動スクリプトを分けます。

・マスターノード

```
# vi /etc/systemd/system/master_node.service
```

・データノード

```
# vi /etc/systemd/system/data_node.service
```

・クライアントノード

```
# vi /etc/systemd/system/client_node.service
```

※下記のスクリプトのXXX箇所をmaster/data/clientに書き換えてください。

```
[Unit]
Description=Elasticsearch XXX Node Service  
Wants=network-online.target
After=network-online.target

[Service]
#メモ：外部スクリプトを呼ぶ場合はforkingにする
Type=forking

# メモ：外部スクリプトを呼ぶようにしています。引数で対象ノードと動作を指定します。
# XXXにmaster/node/clientのいずれかを記述してください。
ExecStart=/usr/local/bin/elasticsearch_control.sh XXX start

# StandardOutput is configured to redirect to journalctl since
# some error messages may be logged in standard output before
# elasticsearch logging system is initialized. Elasticsearch
# stores its logs in /var/log/elasticsearch and does not use
# journalctl by default. If you also want to enable journalctl
# logging, you can simply remove the "quiet" option from ExecStart.
StandardOutput=journal
StandardError=inherit

# プロセスの最大ファイルディスクリプタ数(Elasticsearchの起動スクリプトのデフォルト値を設定)
# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536

# プロセスの最大数(Elasticsearchの起動スクリプトのデフォルト値を設定)
# Specifies the maximum number of processes
LimitNPROC=4096

# 仮想メモリの最大サイズ(Elasticsearchの起動スクリプトのデフォルト値を設定)
# Specifies the maximum size of virtual memory
LimitAS=infinity

# 最大ファイルサイズ(Elasticsearchの起動スクリプトのデフォルト値を設定)
# Specifies the maximum file size
LimitFSIZE=infinity

# タイムアウトを無効化し、プロセスの停止まで待つ(Elasticsearchの起動スクリプトのデフォルト値を設定)
# Disable timeout logic and wait until process is stopped
TimeoutStopSec=0

# Elasticsearchのプロセス(Javaプロセス)のKillシグナルの指定(Elasticsearchの起動スクリプトのデフォルト値を設定)
# SIGTERM signal is used to stop the Java process
KillSignal=SIGTERM

# Elasticsearchのプロセス(Javaプロセス)の操作グループ(Elasticsearchの起動スクリプトのデフォルト値を設定)
# Send the signal only to the JVM rather than its control group
KillMode=process

# Javaプロセスを停止しない設定(Elasticsearchの起動スクリプトのデフォルト値を設定)
# Java process is never killed
SendSIGKILL=no

# JVMがSIGTERMシグナルを受信した際の終了コード(Elasticsearchの起動スクリプトのデフォルト値を設定)
# When a JVM receives a SIGTERM signal it exits with code 143
SuccessExitStatus=143

# 【追加】swap off時に必須となるパラメータ
# 参考：https://support.elastic.co/customers/s/article/How-do-I-enable-mlockall-on-Linux
# Memory Limit
LimitMEMLOCK=infinity

[Install]
WantedBy=multi-user.target
```

(2)サービスの確認
以下のコマンドを実施して(1)で作成したスクリプトがサービスとして認識されていることを確認します。

```
systemctl list-unit-files --type=service | grep node
```

(3)実際にノードを起動させるシェルの作成
systemctlに登録した起動スクリプトから呼び出しているシェルを作成します。

```
# vi /usr/local/bin/elasticsearch_control.sh
```

```
#!/bin/bash

#### 変数定義 ####
## Common
# Elasticsearchのインストールパス
ES_HOME=/usr/share/elasticsearch

# Elasticsearchのコンフィグが格納されているパス 
ES_PATH_CONF=/etc/elasticsearch

# プロセスIDを格納するパス
PID_DIR=/var/run/my_auto_elasticsearch

#ulimitはOS側に設定していますが、念のため記述します。
ulimit -n 65536

# 引数として渡されたノードの種類によって処理をパラメタを変えます。
case "$1" in
  client)
    echo "client"
    JVM="-Xms8g -Xmx8g" # JVM
    FLG_MASTER=false    # Master Node Flag
    FLG_DATA=false  # Data Node Flag
    HTTP_PORT=9200  # REST API PORT
    TCP_PORT=9300   # INTERNAL PORT
    PID_FILE=client.pid # PID FILE NAME
    OPTIONAL_PARM=""    # OPTIONAL PARAMETER
    NODE_NAME=${HOSTNAME}_CLIENT    # NODE_NAME
    ;;
  master)
    echo "master"
    JVM="-Xms8g -Xmx8g" # JVM
    FLG_MASTER=true # Master Node Flag
    FLG_DATA=false  # Data Node Flag
    HTTP_PORT=9290  # REST API PORT
    TCP_PORT=9390   # INTERNAL PORT
    PID_FILE=master.pid # PID FILE NAME
    OPTIONAL_PARM=""    # OPTIONAL PARAMETER
    NODE_NAME=${HOSTNAME}_MASTER    # NODE_NAME
    ;;
  data)
    echo "data"
    JVM="-Xms30g -Xmx30g"   # JVM
    FLG_MASTER=false    # Master Node Flag
    FLG_DATA=true   # Data Node Flag
    HTTP_PORT=9210  # REST API PORT
    TCP_PORT=9310   # INTERNAL PORT
    PID_FILE=hot1.pid   # PID FILE NAME

    # OPTIONAL PARAMETER
    #  hot/warmの設定をしたい時は以下のパラメータを付与します。 
    #OPTIONAL_PARM="-Enode.attr.box_type=hot"  # Hot Node
    #OPTIONAL_PARM="-Enode.attr.box_type=warm"  # Warm Node

    NODE_NAME=${HOSTNAME}_DATA  # NODE_NAME
    ;;
  *)
    echo $"Usage: NODE {master|data|client}"
    exit
esac

#### Action ####

case "$2" in
  start)
    echo "Start"
    sudo -u elasticsearch ES_JAVA_OPTS="${JVM}" ${ES_HOME}/bin/elasticsearch -p ${PID_DIR}/${PID_FILE} -d -Ehttp.port=${HTTP_PORT} -Etransport.tcp.port=${TCP_PORT} -Enode.master=${FLG_MASTER} -Enode.data=${FLG_DATA} -Enode.name=${NODE_NAME} ${OPTIONAL_PARM}

    ;;

  stop)
    echo "Stop"
    kill -SIGTERM `cat ${PID_DIR}/${PID_FILE}`
    ;;

  *)
    echo $"Usage: ACTION {start|stop|restart}"

esac
```

(4)シェルの動作確認

実際に作成したスクリプトにノード種類と制御を渡して実行します。
単一ノード及び各サーバで動作させたいノードを複数起動/停止できることを確認します。

```
/usr/local/bin/elasticsearch_control.sh master start
/usr/local/bin/elasticsearch_control.sh master stop
```

(5)systemctl制御の確認
実際にサービス制御が可能か確認をします。

・マスターノード

```
# systemctl start master_node.service
# systemctl stop master_node.service
```

・データノード

```
# systemctl start data_node.service
# systemctl stop data_node.service
```

・クライアントノード

```
# systemctl start client_node.service
# systemctl stop client_node.service
```

## 各サーバの起動/停止一覧
ここまで設定を実施するとsystemctl enableで自動起動/停止を有効にしたいところですが、Elasticsearchの複数ノード構成の場合は所定の手順で実施しないとデータが破損します。
※複数ノードの所定の起動/停止方法は後ほど記述します。

そのため、起動/停止コマンドをテキストにメモしておき実行することをオススメします。
※これまで作成してきた仕組みは短いコマンドで簡単に起動/停止できるようにするためのものです。
※現時点では管理データしかないので破損はほぼないです。

・RHEL#1

```
# systemctl start/stop master_node.service
# systemctl start/stop data_node.service
```

・RHEL#2

```
# systemctl start/stop master_node.service
# systemctl start/stop data_node.service
```

・RHEL#3

```
# systemctl start/stop master_node.service
# systemctl start/stop data_node.service
# systemctl start/stop client_node.service
```

・RHEL#4

```
# systemctl start/stop data_node.service
# systemctl start/stop client_node.service
```

・RHEL#5

```
# systemctl start/stop data_node.service
# systemctl start/stop client_node.service
```