バックエンド

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

numa

はじめに

こんにちは!筋トレに絶賛どハマり中の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コンテナでコマンド実行すると、以下のような事象が起こり正常に実行できませんでした。

  1. コンテナが正常起動する前にcurlコマンドを実行してしまう
    • 正常起動してないので、curlコマンドが失敗し上手くデータが投入できません
  2. 自身のコンテナの正常起動を自身が検知できない
    • "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を開発しているのですが、初期データを投入された環境をコンテナでローカルに用意することで、チーム全体の開発アジリティを高めることができました。

AUTHOR
numa
numa
記事URLをコピーしました