Raspberry Pi 4Bのdocker上でElastic Stack 7.6.0/7.7.x/7.8.0/7.9.0 を動かす

# はじめに
以前からラズパイでElastic Stack(elasticsearch/kibana)を利用してますが、Raspberry Pi 4Bでメモリが飛躍的に多くなりました(RAM4GBモデル)。
メモリが多いと他にも色々動かしたくなりますが、そこで問題になるのがJavaとnode.jsのバージョン問題です。個人的にNode-REDも常用しているため、kibanaの要件だけでnode.jsのバージョン変更はできません。
ここでは、elasticsearchとkibanaのdockerイメージを作り、コンテナ仮想化技術でプロダクト間のバージョン問題を回避させた手順を記載しています。

[追記]7.7.0/7.7.1/7.8.0/7.9.0の場合は、7.6のバージョン記載部分を読み替えてください。
[追記]7.8.0/7.9.0の場合は、node.jsイメージのバージョンをv10.21.0にしてください。
[追記]7.8.0/7.9.0のopenjdkイメージは14-jdk-hotspotで確認しています。

# 前提環境
- Raspberry Pi 4B RAM4GB  
  OS : Raspbian (buster)  
  Docker : 19.03.5

dockerのインストール方法は公式にもありますし、別途調べてください。

# Elasticsearchのイメージ作成
elasticの配布しているイメージはraspbianでは動作しません。アーキテクチャが違うので当然ですよね。
ラズパイではDockerfileを作り、イメージをビルドする必要があります。

まず、作業用ディレクトリを作って、elasticsearch(Linux版)をダウンロードします。

```
$ mkdir /opt/elasticsearch
$ cd /opt/elasticsearch
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.6.0-linux-x86_64.tar.gz
```

自分用のDockerfileを作成します。

```
$ vi Dockerfile
```

Dockerfileの内容は以下としています。
軽く説明すると、adoptopenjdkの公式イメージ(JDK12)をベースに、elasticsearchを構築しています。
kuromojiのプラグインもインストールしています。JVMのメモリは512MBです。
※ adoptopenjdk(arm32)の13はCPU利用率が上がる[不具合](https://github.com/AdoptOpenJDK/openjdk-build/issues/1287)があるようです。

```
FROM adoptopenjdk:12-jdk-hotspot
COPY elasticsearch-7.6.0-linux-x86_64.tar.gz /opt

RUN tar xzf /opt/elasticsearch-*.tar.gz -C /opt &&\
    rm /opt/elasticsearch-*.tar.gz &&\
    ln -s /opt/elasticsearch-* /opt/elasticsearch &&\
    /opt/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji &&\
    echo "network.host: 0.0.0.0" >> /opt/elasticsearch/config/elasticsearch.yml &&\
    echo "discovery.type: single-node" >> /opt/elasticsearch/config/elasticsearch.yml &&\
    echo "xpack.ml.enabled: false" >> /opt/elasticsearch/config/elasticsearch.yml &&\
    perl -pi -e "s/Xms1g/Xms512m/" /opt/elasticsearch/config/jvm.options &&\
    perl -pi -e "s/Xmx1g/Xmx512m/" /opt/elasticsearch/config/jvm.options
ENV JAVA_HOME=/opt/java/openjdk
CMD ["/opt/elasticsearch/bin/elasticsearch"]

```

イメージをビルドします。タグ付けは自由にして良いと思います。

```
$ docker build -t rpi-elasticsearch:7.6.0 .
Sending build context to Docker daemon  296.2MB
Step 1/5 : FROM adoptopenjdk:13-jdk-hotspot
13-jdk-hotspot: Pulling from library/adoptopenjdk
b9b5ae93466e: Pull complete 
9e8983199234: Pull complete 
1e76f87f706a: Pull complete 
b196ba84f492: Pull complete 
22d5149f952e: Pull complete 
23518038960e: Pull complete 
Digest: sha256:6774f80c4cd4f21a7bcf063453da70b77e17f251cf86a234fb608d943056daba
Status: Downloaded newer image for adoptopenjdk:13-jdk-hotspot
 ---> ec294fa0b7ff
Step 2/5 : COPY elasticsearch-7.6.0-linux-x86_64.tar.gz /opt
 ---> 180f95f02c67
Step 3/5 : RUN tar xzf /opt/elasticsearch-*.tar.gz -C /opt &&    rm /opt/elasticsearch-*.tar.gz &&    ln -s /opt/elasticsearch-* /opt/elasticsearch &&    /opt/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji &&    echo "network.host: 0.0.0.0" >> /opt/elasticsearch/config/elasticsearch.yml &&    echo "discovery.type: single-node" >> /opt/elasticsearch/config/elasticsearch.yml &&    echo "xpack.ml.enabled: false" >> /opt/elasticsearch/config/elasticsearch.yml &&    perl -pi -e "s/Xms1g/Xms512m/" /opt/elasticsearch/config/jvm.options &&    perl -pi -e "s/Xmx1g/Xmx512m/" /opt/elasticsearch/config/jvm.options
 ---> Running in 04614ec30c83
-> Installing analysis-kuromoji
-> Downloading analysis-kuromoji from elastic
[=================================================] 100%   
-> Installed analysis-kuromoji
Removing intermediate container 04614ec30c83
 ---> 9fe6e4aba987
Step 4/5 : ENV JAVA_HOME=/opt/java/openjdk
 ---> Running in e7ac29a6ba08
Removing intermediate container e7ac29a6ba08
 ---> 3181a0333fce
Step 5/5 : CMD ["/opt/elasticsearch/bin/elasticsearch"]
 ---> Running in 6e359a5a0d2c
Removing intermediate container 6e359a5a0d2c
 ---> 5f154d40486e
Successfully built 5f154d40486e
Successfully tagged rpi-elasticsearch:7.6.0
```

起動テストをします。

```
$ docker run --rm -it rpi-elasticsearch:7.6.0
OpenJDK Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
[2020-03-01T03:40:15,773][WARN ][o.e.b.Natives            ] [acfc53556bd0] unable to load JNA native support library, native methods will be disabled.
　　：
　　：
[2020-03-01T03:41:52,371][INFO ][o.e.x.i.a.TransportPutLifecycleAction] [acfc53556bd0] adding index lifecycle policy [watch-history-ilm-policy]
[2020-03-01T03:41:52,657][INFO ][o.e.x.i.a.TransportPutLifecycleAction] [acfc53556bd0] adding index lifecycle policy [slm-history-ilm-policy]
[2020-03-01T03:41:52,984][INFO ][o.e.x.i.a.TransportPutLifecycleAction] [acfc53556bd0] adding index lifecycle policy [ilm-history-ilm-policy]
[2020-03-01T03:41:53,859][INFO ][o.e.l.LicenseService     ] [acfc53556bd0] license [62b59344-95fa-445c-919e-05d9cda77bfc] mode [basic] - valid
[2020-03-01T03:41:53,863][INFO ][o.e.x.s.s.SecurityStatusChangeListener] [acfc53556bd0] Active license is now [BASIC]; Security is disabled
```

若干警告が出ますが、問題なさそうなら[Ctrl]+[c]で終了させます。

# Kibanaのイメージ作成

elasticsearch同様にディレクトリ作成後にkibanaをダウンロードします。

```
$ mkdir /opt/kibana
$ cd /opt/kibana
$ wget https://artifacts.elastic.co/downloads/kibana/kibana-7.6.0-linux-x86_64.tar.gz
$ vi Dockerfile
```

Dockerfileは以下の内容です。
軽く説明すると、node.jsの公式イメージ(10.18.0)をベースに、kibanaを構築しています。
Kibanaは日本語ロケール設定と接続先を「elasticsearch」というホスト名に変更しています。
もし、前項のelasticsearchコンテナの名前を「elasticsearch」以外にする際は変更が必要です。

また、elasticsearchのコンテナもそうなのですが、コンテナ内ではrootユーザで起動させていますので、セキュリティ面を気にする場合は非rootユーザで起動できるようRUNスクリプトを見直してください。

```
FROM node:10.18.0
COPY kibana-7.6.0-linux-x86_64.tar.gz /opt

RUN tar xzf /opt/kibana-*.tar.gz -C /opt &&\
    rm /opt/kibana-*.tar.gz &&\
    ln -s /opt/kibana-* /opt/kibana &&\
    echo 'server.host: "0.0.0.0"' >> /opt/kibana/config/kibana.yml &&\
    echo 'i18n.locale: "ja-JP"' >> /opt/kibana/config/kibana.yml &&\
    echo 'elasticsearch.hosts: ["http://elasticsearch:9200"]' >> /opt/kibana/config/kibana.yml &&\
    rm /opt/kibana/node/bin/node &&\
    ln -sr `which node` /opt/kibana/node/bin/node
ENV NODE_OPTIONS=--max-old-space-size=512
CMD ["/opt/kibana/bin/kibana","--allow-root"]
```

kibanaのイメージをビルドします。
kibanaはファイル数が多いので、若干待たされますね。

```
$ time docker build -t rpi-kibana:7.6.0 .
Sending build context to Docker daemon  249.5MB
Step 1/5 : FROM node:10.18.0
10.18.0: Pulling from library/node
b531ae4a3925: Pull complete 
22754f6fc5d5: Pull complete 
cb2155e4b345: Pull complete 
fad0ae228784: Pull complete 
a85007ed2d2e: Pull complete 
107728f28858: Pull complete 
8f80cc20793e: Pull complete 
09183a419a5f: Pull complete 
5d502ef30c0b: Pull complete 
Digest: sha256:49f77fd32e8e796f85581a8d2321c2a9f1b084e1f8b9baa02cb28bce49563ad5
Status: Downloaded newer image for node:10.18.0
 ---> 0d771ddc5d69
Step 2/5 : COPY kibana-7.6.0-linux-x86_64.tar.gz /opt
 ---> 64fe78082d19
Step 3/5 : RUN tar xzf /opt/kibana-*.tar.gz -C /opt &&    rm /opt/kibana-*.tar.gz &&    ln -s /opt/kibana-* /opt/kibana &&    echo 'server.host: "0.0.0.0"' >> /opt/kibana/config/kibana.yml &&    echo 'i18n.locale: "ja-JP"' >> /opt/kibana/config/kibana.yml &&    echo 'elasticsearch.hosts: ["http://elasticsearch:9200"]' >> /opt/kibana/config/kibana.yml &&    rm /opt/kibana/node/bin/node &&    ln -sr `which node` /opt/kibana/node/bin/node
 ---> Running in ef24ee747be4
Removing intermediate container ef24ee747be4
 ---> 5ee7f3f5dda0
Step 4/5 : ENV NODE_OPTIONS=--max-old-space-size=512
 ---> Running in abc588273a14
Removing intermediate container abc588273a14
 ---> dbc47aa1b62e
Step 5/5 : CMD ["/opt/kibana/bin/kibana","--allow-root"]
 ---> Running in ef80e59468b0
Removing intermediate container ef80e59468b0
 ---> eb092c8a307f
Successfully built eb092c8a307f
Successfully tagged rpi-kibana:7.6.0

real	4m37.608s
user	0m0.966s
sys	0m1.342s
```

kibanaの起動確認です。

```
$ docker run --rm -it rpi-kibana:7.6.0
  log   [04:31:04.224] [info][plugins-service] Plugin "case" is disabled.
   :
   :
  log   [04:35:20.396] [warning][admin][elasticsearch] Unable to revive connection: http://elasticsearch:9200/
  log   [04:35:20.397] [warning][admin][elasticsearch] No living connections
```

elasticsearchに接続できない警告メッセージが続きますが、問題なさそうなら[Ctrl]+[c]で終了させます。

# ElasticsearchとKibanaを起動する
dockerでは、コンテナ同士は同じ仮想ネットワークを利用する事で接続できるようになります。
docker-composeなどを使えば、設定ファイル1つで定義できますが、dockerコマンドの勉強も兼ねてコンテナ同士を連携させてみましょう。

dockerにelasticというネットワークを作成します。

```
$ docker network create elastic
```

先にホスト側にelasticsearchが使うdataディレクトリのマッピング先のディレクトリを作ります。
で、dockerのrunコマンドで、以下のようなオプションを使い起動させます。※説明は独自解釈
 --rm : 終了時にコンテナを削除する
 -d : バックグラウンド起動
 --name : コンテナ名=ホスト名になる
 --network : 接続するdockerネットワーク指定
 -v : ホストとコンテナ内のボリュームマッピング
 -p : ネットワークポートのマッピング

オプションの詳細は調べてください。

```
$ mkdir /opt/elasticsearch/es-data
$ docker run --rm -d --name elasticsearch --network elastic -v /opt/elasticsearch/es-data:/opt/elasticsearch/data -p 9200:9200 rpi-elasticsearch:7.6.0
```

起動も確認しておきます。

```
$ docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                    NAMES
aca3cf3bc43a        rpi-elasticsearch:7.6.0   "/opt/elasticsearch/…"   9 minutes ago       Up 9 minutes        0.0.0.0:9200->9200/tcp   elasticsearch
```

kibanaの起動は以下のようにします。

```
$ docker run --rm -d --name kibana --network elastic -p 5601:5601 rpi-kibana:7.6.0
```

こんな感じで起動が確認できます。

```
$ docker ps
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                    NAMES
11ea95981b71        rpi-kibana:7.6.0          "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:5601->5601/tcp   kibana
aca3cf3bc43a        rpi-elasticsearch:7.6.0   "/opt/elasticsearch/…"   37 minutes ago      Up 37 minutes       0.0.0.0:9200->9200/tcp   elasticsearch
```

ブラウザでも利用できる事が確認でき、お目当てのCanvasのMap埋め込みもできました！！

![スクリーンショット 2020-03-01 0.45.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410957/a6aca79b-75d7-ea1c-9089-dde7373733d6.png)

# おわりに
7.6.0では[以前のバージョンで問題となっていた](https://qiita.com/Y-Shikase/items/7e6025855454c443f620)kibanaのctagsやらnodegit絡みの問題が無くなって容易にDockerfileに落とし込めるようになっていました。elasticのエンジニアの方々はさすがです。
7.6.0では、データの時系列ソートなどの速度が向上されているとの事なので、できれば比較したいと思います。
あと、このイメージをkubernetes上でも使いたい！！←勉強しながら頑張ります。←[追記]できました。

[追記] 7.7.0では、CanvasへのVisualizationオブジェクト埋め込みができるようになっていますが、不具合がありデータが更新して表示されません。7.6.0でも地図の位置情報が最新に変化しないため、Canvas目当てで移行される方はご注意ください。
[追記] 7.7.1/7.8.0では、確認する限り上記問題は解消されています。~~7/3時点ではまだissueはOPENなので、完全に解消されているのかは不明です。~~7/24にCLOSEされました。

[[Canvas] Embeddables don't refresh on "refresh data" or on auto-refresh #66205]
(https://github.com/elastic/kibana/issues/66205)