Elasticsearch8をDockerで使ってみる (2) | 永続化とX-Packセキュリティ

※この記事は前回(Elasticsearch8をDockerで使ってみる (1) | シングルノード構成)の続きとなります。

前回の記事では簡単なシングルノードクラスタを構築してみたが、 データの永続化が行われていないためdocker-compose downを実行するとデータが失われてしまう状態となっていた。 そこで、今回はデータの永続化を有効にするところから始めてみる。

永続化に立ちはだかる壁

Elasticsearchのデータは/usr/share/elasticsearch/dataに格納されるようになっている。 とりあえずこのディレクトリをVolumeに結びつけて永続化してみる。

 1services:
 2  es:
 3    build:
 4      context: .
 5    environment:
 6      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
 7    ports:
 8      - 9200:9200
 9    volumes:
10      - es_data:/usr/share/elasticsearch/data
11volumes:
12  es_data:

この状態でdocker-compose up -dすると、以下のようなエラーで終了してしまった。

1...
2bootstrap check failure [1] of [2]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured
3bootstrap check failure [2] of [2]: Transport SSL must be enabled if security is enabled. Please set [xpack.security.transport.ssl.enabled] to [true] or disable security by setting [xpack.security.enabled] to [false]
4ERROR: Elasticsearch did not exit normally - check the logs at /usr/share/elasticsearch/logs/docker-cluster.log
5...
6ERROR: [2] bootstrap checks failed. You must address the points described in the following [2] lines before starting Elasticsearch.

シングルノード構成のときには出てこなかったエラーがいきなり出てきてしまったが、 これはElasticsearchコンテナが本番環境用のモードで起動したためである。 (Elasticsearchのdockerイメージは、/usr/share/elasticsearch/dataの中身がデフォルトの状態のときのみ開発用モードで動作するようである。) 本番環境用のElasticsearchコンテナでは、以下の設定を手動で行う必要がある。

  • クラスタの初回起動に必要なマスターノードの指定
  • X-Packセキュリティの設定(SSL証明書の発行・設定)

上記のエラーはこれらの設定に不備があることを指摘している。 一見不便に思えるが、一般的なElasticsearchの本番構成だと複数のノードを組み合わせるのが一般的なので、 むしろ当然の動作と言える。

ということで、上記の設定を簡単に行っていくこととする。

クラスタのマスターノードの指定

クラスタを初回起動する際に、最低限以下の設定を入れる必要がある。

  • cluster.initial_master_nodes: 最初にマスターノードとして動作するノード
  • discovery.seed_hosts: マスターノードのアドレス

今回はシングルノードで構成するので、とりあえず両方とも自分自身を指定すれば良い。 (詳細についてはマルチノード構成を扱う際に取り上げようと思う。)

これらの設定は環境変数に設定する。

1    environment:
2      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
3      - "cluster.initial_master_nodes=es"
4      - "discovery.seed_hosts=es"

esはdocker-compose内のサービス名を指定しており、これはdocker networkのalias機能によりコンテナのIPアドレスに解決される。

X-Packセキュリティのセットアップ

X-PackはElasticsearchで標準的に使用されているセキュリティプラグインである。 Elasticsearch7.xまではオプショナルのプラグインだったが、 8.0以降は標準で有効になっているため改めてインストールする必要はない。

X-Packセキュリティを使うにあたって、以下の準備を行う必要がある。

  • CA証明書の発行
  • 各ノードの証明書の発行
  • 各ノードへの証明書の設定

CA証明書の発行

以降、ホスト側のcertsディレクトリに証明書関連のファイルを格納することとする。

証明書に関する各種操作はelasticsearch-certutilコマンドで簡単に行うことができる。 まずは以下のコマンドを実行してCA証明書を発行する。

1$ mkdir -p certs
2$ docker run --rm -it -v "$PWD/certs:/certs" elasticsearch:8.5.0 \
3  bin/elasticsearch-certutil ca --silent --pem -out /certs/ca.zip
4$ unzip certs/ca.zip -d certs

certs/ca/ca.crtにCA証明書が発行される。 また、certs/ca/ca.keyはCA証明書の秘密鍵なので、セキュリティを考慮するのであれば安全性の高い場所に移動して保管するのが望ましい。 (今回は検証用なのでここに置いたままにしておく)

各ノードの証明書の発行

先程発行したCAを用いて、各ノードの証明書を発行する。

まずはcerts/instances.ymlに以下のようにノードリストを記述する。

1instances:
2  - name: es
3    dns:
4      - es
5      - localhost
6    ip:
7      - 127.0.0.1

dnsipで指定しているのは、証明書に記載されるCommon Nameである。 HTTPSでアクセスした際、ここで指定したCommon NameとリクエストURLのホスト名が一致する必要がある。 今回は本来のホスト名であるesの他にlocalhost127.0.0.1を指定しているが、 これらはdockerのポートバインディングを経由してhttps://localhost:9200のようにアクセスする際に必要となる。

ノードリストを作成したら以下のコマンドを実行して証明書を発行する。

1$ docker run --rm -it -v "$PWD/certs:/certs" elasticsearch:8.5.0 \
2  bin/elasticsearch-certutil cert --silent --pem \
3  -out /certs/certs.zip --in /certs/instances.yml \
4  --ca-cert /certs/ca/ca.crt --ca-key /certs/ca/ca.key
5$ unzip certs/certs.zip -d certs

これにより、certs/es以下にes.crt(証明書)とes.key(秘密鍵)が作成される。

各ノードへの証明書の設定・TLSの有効化

最後に、Elasticsearchノードが今回発行した証明書を使用するように設定する。 docker-composeを以下のように編集する。

 1services:
 2  es:
 3    build:
 4      context: .
 5    environment:
 6      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
 7      - cluster.initial_master_nodes=es
 8      - discovery.seed_hosts=es
 9      - ELASTIC_PASSWORD=p@ssw0rd
10      - xpack.security.enabled=true
11      - xpack.security.http.ssl.enabled=true
12      - xpack.security.http.ssl.key=certs/es/es.key
13      - xpack.security.http.ssl.certificate=certs/es/es.crt
14      - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
15      - xpack.security.http.ssl.verification_mode=certificate
16      - xpack.security.transport.ssl.enabled=true
17      - xpack.security.transport.ssl.key=certs/es/es.key
18      - xpack.security.transport.ssl.certificate=certs/es/es.crt
19      - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
20      - xpack.security.transport.ssl.verification_mode=certificate
21    ports:
22      - 9200:9200
23    volumes:
24      - ./certs:/usr/share/elasticsearch/config/certs:ro
25      - es_data:/usr/share/elasticsearch/data
26volumes:
27  es_data:

xpack.security.httpxpack.security.transportの2種類があるが、2つとも設定している内容は全く同一である。 これは、以下の2種類の通信それぞれに暗号化を設定していることになる。

  • http: クライアントとノードの通信、HTTPSにより保護
  • transport: ノード間の通信、TLSにより保護(HTTPを用いていない)

また、ELASTIC_PASSWORDにてelasticアカウントのパスワードも設定している。

動作確認

ここまでできたら準備完了なので、動作確認する。

 1$ docker-compose up -d
 2# 立ち上がるまで待った後、以下を実行
 3$ curl --cacert certs/ca/ca.crt -u 'elastic' https://localhost:9200
 4Enter host password for user 'elastic':
 5{
 6  "name" : "3fcf20ffb466",
 7  "cluster_name" : "docker-cluster",
 8  "cluster_uuid" : "_na_",
 9  "version" : {
10    "number" : "8.5.0",
11    "build_flavor" : "default",
12    "build_type" : "docker",
13    "build_hash" : "c94b4700cda13820dad5aa74fae6db185ca5c304",
14    "build_date" : "2022-10-24T16:54:16.433628434Z",
15    "build_snapshot" : false,
16    "lucene_version" : "9.4.1",
17    "minimum_wire_compatibility_version" : "7.17.0",
18    "minimum_index_compatibility_version" : "7.0.0"
19  },
20  "tagline" : "You Know, for Search"
21}
ノードの再起動にあたって

ノードの再起動を行う場合、cluster.initial_master_nodesは予め削除しておくことが望ましい。 これは、cluster.initial_master_nodesはクラスタの初回起動時にのみ必要な設定であり、 残したままにしておくと再起動時に悪影響を及ぼす可能性があるためである。

まとめ

今回はシングルノード構成で永続化を達成するため、クラスタの初期設定とX-Packセキュリティのセットアップを自力で行った。

今回のセットアップでも一応Elasticsearchの機能は利用できるが、 基本的にElasticsearchは複数ノードでの動作を前提している部分が多い。 そこで、次回はマルチノードの構成、および本番利用に耐えうるコンテナの設定を行っていこうと思う。

関連記事