ElasticsearchをDocker Composeで起動時に初期データを投入する

はじめに
こんにちは!筋トレに絶賛どハマり中のnumaです。エンジニアに必要なのは筋肉ですよね?
ですが、今回は筋トレではなくコンテナのお話です。
私は現在、とあるプロジェクトでElasticsearchを使った開発をしています。
Elasticsearchをローカル上にコンテナとして立ち上げた時に、つまずきポイントがありましたので、紹介させていただきます。
つまずきポイント
Elasticsearchコンテナ起動時に初期データ投入の仕方がわからなくてつまずいた。
コンテナでの初期データの入れ方がDBとは少し違っていた。
ゴール
- ローカル上でElasticseachコンテナを立ち上げられること
- Elasticsearchコンテナ起動時に初期データが投入されていること
Docker Compose 構成図
いきなり対策方法を提示します。
以下のようなコンテナ構成を取ることで、コンテナ起動〜初期データの投入までを行うことができました。
Docker Compose up 開始時

Elasticsearchコンテナにsetup-Elasticsearchコンテナからデータを投入します。
Docker Compose up 完了時

setup-Elasticsearchコンテナはデータ投入が完了次第、停止させます。
なお、Elasticsearchにデータを投入するには、 curl等でPUTやPOSTメソッドで行っていきます。(後述)
Elastic Searchコンテナ内でコマンド実行すればいいんじゃないの?
Elastic Searchコンテナでコマンド実行すると、以下のような事象が起こり正常に実行できませんでした。
- コンテナが正常起動する前にcurlコマンドを実行してしまう
- 正常起動してないので、curlコマンドが失敗し上手くデータが投入できません
- 自身のコンテナの正常起動を自身が検知できない
- "1."を受け、wait処理を入れて正常起動するまで待機してから、curlコマンドを実行を試しましたが、正常起動を検知できず、ずっとwait処理に留まったままでした
そのため、Elastic Searchコンテナではなく外部のコンテナからcurlコマンドを実行することにしました。
ファイルの中身
こちらがDocker Composeと関連ファイルの最終成果物です。
services:
elasticsearch:
build:
context: ./elasticsearch
dockerfile: local.Dockerfile
hostname: elasticsearch
volumes:
- elasticsearch-volume:/elasticsearch/data/elasticsearch/nodes/0
ports:
- 9200:9200
environment:
# elasticsearchの設定
- cluster.name=elasticsearch
- node.name=elasticsearch
# セキュリティが厳格化された(elasticsearch8系)ため、falseに設定して回避(ローカルのため許容する)
- xpack.security.enabled=false
# ローカルのため明示的にシングルノードを指定
- discovery.type=single-node
healthcheck:
test: curl -s http://elasticsearch:9200/_cluster/health
interval: 5s
timeout: 5s
retries: 20
start_period: 5s
setup-elasticsearch:
build:
context: ./elasticsearch
dockerfile: local.Dockerfile
volumes:
- ./elasticsearch/elasticdump:/mnt/elasticdump
- ./elasticsearch/insert.sh:/mnt/insert.sh
environment:
# elasticsearchの設定
- cluster.name=elasticsearch
- node.name=elasticsearch
# セキュリティが厳格化された(elasticsearch8系)ため、falseに設定して回避(ローカルのため許容する)
- xpack.security.enabled=false
# ローカルのため明示的にシングルノードを指定
- discovery.type=single-node
command: /bin/sh -c "set -e && chmod +x /mnt/insert.sh && /mnt/insert.sh && exit 0"
links:
- elasticsearch
app:
build:
context: ./app
dockerfile: local.Dockerfile
working_dir: /app
depends_on:
elasticsearch:
condition: service_healthy
setup-elasticsearch:
condition: service_completed_successfully
env_file:
- /app/.env
platform: linux/amd64
tty: true
volumes:
- ../:/app
command:
- /bin/bash
dependsOnを使ってElasticsearchとSetUp-Elasticsearchの起動順を制御しています。
また、SetUp-Elasticsearchコンテナは初期データ投入後は不要なので、停止されるようにしています。
appコンテナは、Elasticsearchコンテナのヘルスチェックが通り、SetUp-Elasticsearchが正常に終了した後に起動するようにしています。
insert.shは以下です。
#!/bin/sh
echo "Waiting for Elasticsearch to become available..."
sleep 10
# Elasticsearchが起動しているか、ルートエンドポイントで確認
until curl -s http://elasticsearch:9200/ >/dev/null; do
echo "Elasticsearch is unavailable. Waiting..."
sleep 5
done
echo "Elasticsearch is up."
# 各インデックスの作成
echo "Creating index mapping from /temp/index_mapping.json"
curl -sS -X PUT "http://elasticsearch:9200/sample-index" \
-H "Content-Type: application/json" \
-d "@/temp/index_mapping.json"
# インデックスの設定
elasticdump --input=/elasticdump/sample-index.json --output=http://elasticsearch:9200/sample-index --limit=1000
# エイリアスの設定
curl -sS -X POST "http://elasticsearch:9200/_aliases" \
-H "Content-Type: application/json" \
-d '{
"actions" : [
{"add": {"index": "sample-index", "alias": "sample"}}
]
}'
echo "Elasticsearch index finished."
Elasticsearchの正常起動を待機し、必要な処理を実行します。
まとめ
ローカルでElasticsearchを構築する手法を紹介しました。
Elasicsearchを利用したAPIを開発しているのですが、初期データを投入された環境をコンテナでローカルに用意することで、チーム全体の開発アジリティを高めることができました。