簡単なパスワード保護付き検索サービスを5分で立ち上げる

# TL;DR （経験者向けまとめ）
[下記のコンテナをまとめたdocker-compose.yml](https://github.com/chopstickexe/es-kibana-nginx-python) を作りました: 

- Elasticsearch: 検索エンジン
- Kibana: 簡単な検索画面
- nginx: リバースプロキシ（ID/PWによる軽いユーザー認証）
- Python3: データを加工したりインデックスしたりする作業用

# 背景

みなさんのご家庭にあるテキストデータをちょっと検索してみたくなることってありますよね？

検索の機能自体はElasticsearchで提供できるのですが

- Non programmerでも使えるように、簡単な検索画面が欲しい（Kibana）
- 秘密のデータなのでパスワード認証かけたい（nginxによるベーシック認証） 
- 手軽にデータを追加できるようにしたい

・・・といった要求も一緒に上がってくることが多いです。

以上の要求をかなえるための環境を作りました。[^1]

[^1]: ベーシック認証はもしかしたら[Elasticsearch Security](https://www.elastic.co/jp/blog/getting-started-with-elasticsearch-security)を使うと、もう少し気の利いたものができるのかもしれません。また、本記事で紹介する方法はhttp接続を利用していて、セキュリティ的にはガバガバなのでこちらの記事を参考にhttps化することもご検討ください: https://qiita.com/hsano/items/3b4fb372c4dec0cabc08

# 作ったもの

このリポジトリに全部載せてあります: https://github.com/chopstickexe/es-kibana-nginx-python

主な内容は下記の通りです: 

- docker-compose.yml: Elasticsearch, Kibana, nginx, Python3の４つのコンテナをまとめて立ち上げて連携させるための設定ファイル
- index.py: Python3コンテナの中でElasticsearchへのデータの登録（インデキシング）を行うためのサンプルコード
- data/sample.csv: index.pyで登録しているサンプルデータ（ご覧の通り、ノーラン監督作品の個人的な感想文４件です）

## Docker Compose概要

このdocker-composeを使うと、下記のような環境が立ち上がります: 
![IMG_0028.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290088/32279990-e8ab-8ec3-644a-4f10b645e129.jpeg)

- Elasticsearch, Kibana, nginx, Pythonの４つのコンテナが立ち上がるが、ホストにポートがマップされている（ホスト外からHTTPアクセス可能な）コンテナはnginxだけ。そのため、ElasticsearchやKibanaにはnginxで設定したID/PWを知ってる人しかアクセスできない
- Elasticsearchのインデックスデータはホストのどこかのディレクトリに保存される（local volume）。そのため、コンテナを終了・再起動しても、また同じインデックスにアクセスできる。
- `http://ホストアドレス` のような簡単なアドレスでKibanaにアクセス可能。
- Pythonコンテナにソースコードやデータをマウントしているため、`docker exec` でこのコンテナに入って、データの加工やインデキシングを行うPythonコードを実行することが可能。[^2]

[^2]: また、例えば[VSCodeのRemote Containers extension](https://code.visualstudio.com/docs/remote/containers-tutorial)を利用してコンテナに接続し、コードを編集・実行することも可能。

# 動かし方

以下、Ubuntu18.04を前提として説明しますが、docker-composeやApache HTTPサーバー（より具体的にはhtpasswdコマンド）が動く環境であれば、CentOSやMac, Windowsでも動くと思います。

## 事前準備1. docker-composeのインストール

まず、docker-composeがインストールされた環境を用意します。[参考](https://docs.docker.jp/compose/install.html)

## 事前準備2. Apache HTTPサーバーのインストール

まず、apache2-utils（HTTPサーバーが入っているパッケージ）をインストールします。

```
$ sudo apt -y install apache2-utils
```

CentOSの場合は `httpd-tools` をインストールすれば、後述する `htpasswd` コマンドは利用できます。

## 1. Gitリポジトリのclone

上記リポジトリ[chopstickexe/es-kibana-nginx-python](https://github.com/chopstickexe/es-kibana-nginx-python)をcloneします。

## 2. ログインID・パスワードの準備

そして、この後立ち上げるKibana（検索画面）にログインするためのIDとパスワードを何か考えます。
（以下の例ではID=adminでログインします）

htpasswdコマンドを以下のように実行し、パスワードを設定したファイル `(cloneしたディレクトリ)/htpasswd/localhost`を作成してください。

```
$ cd /path/to/repo
$ mkdir htpasswd && cd htpasswd
$ htpasswd -c localhost admin 
# ここにパスワードを入力
```
※ このファイル名（localhost）はdocker-compose.ymlのKibanaコンテナに設定した環境変数VIRTUAL_HOSTと同じ文字列にする必要があります。詳しくは[jwilder/nginx-proxy](https://github.com/nginx-proxy/nginx-proxy)のREADMEを見てください。

## 3. （オプショナル） docker-compose.ymlの編集

### Kibanaにホスト以外のマシンからWebブラウザ経由でアクセスしたい場合

cloneしてきたディレクトリのdocker-compose.ymlを開き、[KibanaコンテナのVIRTUAL_HOSTの設定値](https://github.com/chopstickexe/es-kibana-nginx-python/blob/master/docker-compose.yml#L25)を`localhost`からホストのIPアドレスか、または`foo.bar.com`のようなFQDNに変更してください。

### すでにホストの80番ポートで別のサービスが立ち上がっている場合

[nginxコンテナのポートマッピング](https://github.com/chopstickexe/es-kibana-nginx-python/blob/master/docker-compose.yml#L35)を `80:80` から `ホストの空いているポート:80` に変更してください。

## 4. Dockerコンテナの起動

下記のdocker-composeコマンドでコンテナを起動します。

```
$ cd /path/to/this/directory
$ docker-compose up
```

## 5. WebブラウザからKibanaにアクセスできることを確認

docker-compose.ymlを変更していない場合はホストのブラウザから`http://localhost`、
変更した場合はお手元の環境のブラウザから`http://ホストアドレス`を開き、設定したIDとパスワードでログインして、Kibanaの画面が見えることを確認してください。

## 6. Elasticsearchにサンプルデータ登録

ホストマシンのターミナルに戻り、下記のコマンドでPythonコンテナに入ってください：

```
$ docker exec -it python bash
```

Pythonコンテナに入ったあとは、下記のコマンドで仮想環境（venv）を作り、そこに必要パッケージをpip installします：

```
# python -m venv .venv
# source .venv/bin/activate
(.venv) # pip install -r requirements.txt
```

パッケージのインストールが終わったら、下記のコマンドでサンプルデータをElasticsearchの`nolan`インデックスに登録してください:

```
(.venv) # python index.py
Finished indexing
```

ここで実行しているPythonスクリプトindex.pyは[こちら](https://github.com/chopstickexe/es-kibana-nginx-python/blob/master/index.py)です。
下記でRELEASE_DATEという列のデータ型を`date`（日付型）、フォーマットを`yyyyMMdd`に設定しています。

```python

    es.indices.create(
        index,
        body={
            "mappings": {
                "properties": {"RELEASE_DATE": {"type": "date", "format": "yyyyMMdd"}}
            }
        },
    )
```

## 7. Kibana上で検索できることを確認

Webブラウザから再びKibanaにアクセスし、下記を設定する:

### Index Patternを作成

画面左側のメニュー（表示されていない場合は左上の三をクリック)
から Kibana > Index Patterns を選択し、index pattern nameに `nolan` を入力する。上記のPythonコードが問題なく実行できていれば `Your index pattern matches 1 source` というメッセージが出るのでNext stepをクリック：

![Screenshot from 2020-09-28 09-20-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290088/8c2eafcc-3ab8-c195-617a-dd7fe17bcd87.png)

Time fieldに`RELEASE_DATE`列を設定し、Create index patternをクリックする。

![Screenshot from 2020-09-28 09-20-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290088/8dd7540b-505c-16e0-e7f4-3d1192b50041.png)

### Discover画面上でTime rangeを~11 years ago -> nowに設定

画面左側のメニューからDiscoverを選択し、画面中程のカレンダーアイコンをクリックして、Time rangeをRelative > 11 years agoに設定する。
（結構古いRELEASE_DATEのレビューが入っているので、このようにしないと検索にヒットしません）

正しく設定できると、以下のように４件のレビューが表示されます:

![Screenshot from 2020-09-28 09-18-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290088/08c60ac0-c8f0-2bd2-18d8-a2574de1f524.png)

このDiscover画面上から「トム・ハーディ」を含むレビューを検索することも可能です:

![Screenshot from 2020-09-28 09-18-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290088/65a4af03-7826-fe53-a376-0ea158ad00b1.png)

# 参考資料

kibanaの使い方はこちらも参考にしてください: https://qiita.com/namutaka/items/b67290e75cbd74cd9a2f