- ブログ
全文検索エンジンを使ってみよう・その1〜Elasticsearch開発環境構築編
2024.02.26 Mon

一周回って、Laravelでの開発に日々奮闘しているsoobeです!
今回のブログのテーマは、Elasticsearch(エラスティックサーチ)です。
Elasticsearchは、検索ライブラリ「Apache Lucene」をベースにした「全文検索エンジン」です。
今回の目標です
・Dockerコンテナを使用したElasticsearchを構築できる。
・Pythonアプリケーションを使ってElasticsearchに接続して通信を確認できる。
*この記事では、Mac(Apple Silicon)+ Docker Desktop を使用しています。
1. Elasticsearch プロジェクトを作成しましょう
ターミナルを開いて、作業フォルダへcdした後、次のコマンドを入力してください。
mkdir elastic-study
cd elastic-study
mkdir -p elasticsearch python/src
touch elasticsearch/docker-compose.yml
touch elasticsearch/.env
touch python/Dockerfile
touch python/docker-compose.yml
touch python/requirements.txt
touch python/src/__init__.py
touch python/src/test_connect_elasticsearch.pyElasticsearchとPythonを構成するディレクトリと新しい空のファイルが作成されます。
# プロジェクト名
elastic-study/
│
├── elasticsearch/
│ ├── docker-compose.yml
│ └── .env
│
└── python/
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── src/
├── __init__.py
└── test_connect_elasticsearch.py2.Elasticsearch Docker Composeを構築しましょう
elasticsearch/docker-compose.yml
以下の Elasticsearch Docker Compose をコピーして貼り付けてください。
version: "2.2"
services:
setup:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
container_name: setup
volumes:
- certs:/usr/share/elasticsearch/config/certs
user: "0"
command: >
bash -c '
if [ x${ELASTIC_PASSWORD} == x ]; then
echo "Set the ELASTIC_PASSWORD environment variable in the .env file";
exit 1;
elif [ x${KIBANA_PASSWORD} == x ]; then
echo "Set the KIBANA_PASSWORD environment variable in the .env file";
exit 1;
fi;
if [ ! -f config/certs/ca.zip ]; then
echo "Creating CA";
bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
unzip config/certs/ca.zip -d config/certs;
fi;
if [ ! -f config/certs/certs.zip ]; then
echo "Creating certs";
echo -ne \
"instances:\n"\
" - name: es01\n"\
" dns:\n"\
" - es01\n"\
" - localhost\n"\
" ip:\n"\
" - 127.0.0.1\n"\
> config/certs/instances.yml;
bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
unzip config/certs/certs.zip -d config/certs;
fi;
echo "Setting file permissions"
chown -R root:root config/certs;
find . -type d -exec chmod 750 \{\} \;;
find . -type f -exec chmod 640 \{\} \;;
echo "Waiting for Elasticsearch availability";
until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done;
echo "Setting kibana_system password";
until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done;
echo "All done!";
'
healthcheck:
test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"]
interval: 1s
timeout: 5s
retries: 120
mem_limit: ${MEM_LIMIT}
es01:
depends_on:
setup:
condition: service_healthy
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
container_name: es01
volumes:
- certs:/usr/share/elasticsearch/config/certs
- esdata01:/usr/share/elasticsearch/data
- ./:/etc/elasticsearch
ports:
- ${ES_PORT}:9200
environment:
- node.name=es01
- cluster.name=${CLUSTER_NAME}
- cluster.initial_master_nodes=es01
- discovery.seed_hosts=es01
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=true
- xpack.security.http.ssl.key=certs/es01/es01.key
- xpack.security.http.ssl.certificate=certs/es01/es01.crt
- xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.http.ssl.verification_mode=certificate
- xpack.security.transport.ssl.enabled=true
- xpack.security.transport.ssl.key=certs/es01/es01.key
- xpack.security.transport.ssl.certificate=certs/es01/es01.crt
- xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
- xpack.security.transport.ssl.verification_mode=certificate
- xpack.license.self_generated.type=${LICENSE}
mem_limit: ${MEM_LIMIT}
ulimits:
memlock:
soft: -1
hard: -1
healthcheck:
test:
[
"CMD-SHELL",
"curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
]
interval: 10s
timeout: 10s
retries: 120
kibana:
depends_on:
es01:
condition: service_healthy
image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
container_name: kibana
volumes:
- certs:/usr/share/kibana/config/certs
- kibanadata:/usr/share/kibana/data
ports:
- ${KIBANA_PORT}:5601
environment:
- SERVERNAME=kibana
- ELASTICSEARCH_HOSTS=https://es01:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
- ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
mem_limit: ${MEM_LIMIT}
healthcheck:
test:
[
"CMD-SHELL",
"curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'",
]
interval: 10s
timeout: 10s
retries: 120
volumes:
certs:
driver: local
esdata01:
driver: local
kibanadata:
driver: localelasticsearch/.env
公式ドキュメントElasticsearch Guideの.envを参考にしました。
STACK_VERSION = 8.6.2
ELASTIC_PASSWORD = elastic
KIBANA_PASSWORD = elastic
ES_PORT = 9200
CLUSTER_NAME = test_cluster
LICENSE = trial
MEM_LIMIT = 1073741824
KIBANA_PORT = 56013.Python 3.10 Docker Compose を構築しましょう
python/Dockerfile
FROM python:3.10
# ロケールとタイムゾーンの設定
RUN apt-get update && apt-get install -y locales && \
localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 && \
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# 必要なパッケージのインストール
RUN apt-get install -y vim less
# Pythonパッケージのインストール
COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir --upgrade pip setuptools && \
pip install --no-cache-dir -r /tmp/requirements.txt
# 作業ディレクトリの設定
WORKDIR /root/srcpython/docker-compose.yml
version: '3'
services:
python:
restart: always
build: .
container_name: 'python'
working_dir: '/root/src'
tty: true
volumes:
- ./src:/root/srcpython/requirements.txt
requests
elastic-transport
elasticsearchpython/src/__init__.py
# 空python/src/test_connect_elasticsearch.py
import os
from elasticsearch import Elasticsearch
ELASTIC_SEARCH_HOST = "<--ここにプライベートIPを貼り付けてください-->"
ELASTIC_CERT_FINGERPRINT = "<--ここにELASTIC_CERT_FINGERPRINTを貼り付けてください-->"
ELASTIC_PASSWORD = "elastic"
# Elasticsearchインスタンスを作成
es = Elasticsearch(
f"https://{ELASTIC_SEARCH_HOST}:9200",
ssl_assert_fingerprint=ELASTIC_CERT_FINGERPRINT,
basic_auth=("elastic", ELASTIC_PASSWORD),
)
try:
# Elasticsearchへの疎通確認
es.info()
print(es.info())
except Exception as e:
# その他の一般的なエラーの場合
print("An unexpected error occurred:", e)
finally:
# 内部接続を閉じる
es.close()4. Elasticsearch Docker Compose を立ち上げましょう。
事前にDocker Desktopを起動してください。ターミナルを開いて、プロジェクト直下で次のコマンドを入力してください。
% (cd ./elasticsearch && docker-compose build --no-cache && docker-compose up -d)
[+] Running 6/6
✔ Container elasticsearch-setup-1 Recreated 0.3s
✔ Container elasticsearch-es01-1 Recreated 3.3s
✔ Container elasticsearch-kibana-1 Recreated 0.1s
✔ Container setup Healthy 0.4s
✔ Container es01 Healthy 0.2s
✔ Container kibana Started実行中のDockerコンテナの一覧を表示してみましょう。
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3dfb585f1af0 docker.elastic.co/kibana/kibana:8.6.2 "/bin/tini -- /usr/l…" About a minute ago Up About a minute (healthy) 0.0.0.0:5601->5601/tcp kibana
7cf48cacdabc docker.elastic.co/elasticsearch/elasticsearch:8.6.2 "/bin/tini -- /usr/l…" About a minute ago Up About a minute (healthy) 0.0.0.0:9200->9200/tcp, 9300/tcp es01es01とkibanaの2つが立ち上がったら成功です。
5. Python アプリケーションを修正しましょう。
Elasticsearch Docker コンテナが立ち上がっていること。
python/src/test_connect_elasticsearch.py
・ELASTIC_SEARCH_HOSTに、プライベートIPアドレスを貼り付けてください。
・ELASTIC_CERT_FINGERPRINTに、下記コマンドの出力結果を貼り付けてください。
% elastic_cert_fingerprint=$(openssl s_client -connect localhost:9200 -servername localhost -showcerts </dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -noout -in /dev/stdin | awk -F '=' '{print $2}')
% echo $elastic_cert_fingerprint
0F:7A:B3:77:58:FD:3E:AD:45:69:15:45:BA:00:9F:A1:04:1C:36:AB:0D:6B:E9:4D:2F:A2:09:FF:E1:7F:2F:7EElasticsearchに対してSL/TLS接続を確立するための証明書のフィンガープリントが出力されました。
修正後:
python/src/test_connect_elasticsearch.py
import os
from elasticsearch import Elasticsearch
ELASTIC_SEARCH_HOST = "192.168.105.1"
ELASTIC_CERT_FINGERPRINT = "0F:7A:B3:77:58:FD:3E:AD:45:69:15:45:BA:00:9F:A1:04:1C:36:AB:0D:6B:E9:4D:2F:A2:09:FF:E1:7F:2F:7E"
ELASTIC_PASSWORD = "elastic"
# Elasticsearchインスタンスを作成
es = Elasticsearch(
f"https://{ELASTIC_SEARCH_HOST}:9200",
ssl_assert_fingerprint=ELASTIC_CERT_FINGERPRINT,
basic_auth=("elastic", ELASTIC_PASSWORD),
)
try:
# Elasticsearchへの疎通確認
es.info()
print(es.info())
except Exception as e:
# その他の一般的なエラーの場合
print("An unexpected error occurred:", e)
finally:
# 内部接続を閉じる
es.close()6. Python Docker Compose を立ち上げましょう。
% (cd ./python && docker-compose build --no-cache && docker-compose up -d)
[+] Building 23.7s (11/11) FINISHED docker:desktop-linux
=> [python internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 604B 0.0s
=> [python internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [python internal] load metadata for docker.io/library/python:3.10 3.8s
=> CACHED [python 1/6] FROM docker.io/library/python:3.10@sha256:b54e76c629a98430ac9c92e4f6bddeb672396a895b44a85022d12ee2f7239144 0.0s
=> [python internal] load build context 0.0s
=> => transferring context: 83B 0.0s
=> [python 2/6] RUN apt-get update && apt-get install -y locales && localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 && ln -sf /usr/share/zoneinfo/Asia/T 8.4s
=> [python 3/6] RUN apt-get install -y vim less 4.1s
=> [python 4/6] COPY requirements.txt /tmp/requirements.txt 0.0s
=> [python 5/6] RUN pip install --no-cache-dir --upgrade pip setuptools && pip install --no-cache-dir -r /tmp/requirements.txt 7.0s
=> [python 6/6] WORKDIR /root/src 0.0s
=> [python] exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:57e96a7696a8999a6c76fe798a652746026a6004d1c5e9b5a639aa06eed4b27d 0.0s
=> => naming to docker.io/library/python-python 0.0s
[+] Building 0.0s (0/0) docker:desktop-linux
[+] Running 2/2
✔ Network python_default Created 0.1s
✔ Container python Started pythonコンテナが立ち上がりました。
7. PythonアプリケーションからElasticsearchへ接続できるか確認しましょう
% docker exec -it python bash -c "python test_connect_elasticsearch.py"
{
'name': 'es01',
'cluster_name': 'test_cluster',
'cluster_uuid': 'ihlWTaJXSdyh8Z7L4qCShA',
'version': {
'number': '8.6.2',
'build_flavor': 'default',
'build_type': 'docker',
'build_hash': '2d58d0f136141f03239816a4e360a8d17b6d8f29',
'build_date': '2023-02-13T09:35:20.314882762Z',
'build_snapshot': False,
'lucene_version': '9.4.2',
'minimum_wire_compatibility_version': '7.17.0',
'minimum_index_compatibility_version': '7.0.0'
},
'tagline': 'You Know, for Search'
}Elasticsearchレスポンスデータが出力されました。
おめでとうございます。Elasticsearchへの接続に成功しました!
今回はここまでになります。次回は、登録や検索の紹介ができたらと思います。