概要
Elasticsearch Python Client (elasticsearch-py)をプロキシサーバを通して利用する方法がググってもあまり出てこないため、簡単に設定方法をまとめました。
elasticsearch-pyのバージョンによって設定方法が少し異なりますので、v7とv8で分けて記載します。
elasticsearch-pyのドキュメント
elasticsearch-pyのGitHub
準備
お手軽に試せるようにdocker-compose一発で環境が整うようにします。
Elastic Cloud
構成
以下のようなファイルを用意します。
.
├── app
│ ├── Dockerfile
│ ├── v7.py
│ └── v8.py
├── docker-compose.yml
└── squid
└── Dockerfile
ではそれぞれのファイルの中身を見てみましょう。
プロキシサーバ
Docker HubにあるUbuntu/Squidイメージを使用します。
Dockerfileはこちら
FROM ubuntu/squid
RUN echo acl SSL_ports port 443 9243 >> /etc/squid/squid.conf
Elasticsearchのポートが9243
ですのでこのポートだけ追加をしています。
Python Client
Docker Hubにあるpython:bullseyeを使用します。
Dockerfile
Dockerfileはこちら
apt install
しているパッケージは後ほどプロキシ経由に通信を変更する際に使用します。
v8
FROM python:bullseye
RUN apt update
RUN apt install -y net-tools iputils-ping curl
RUN pip3 install requests elasticsearch
COPY v8.py v8.py
v7
version 7でのインストールを明記します。
FROM python:bullseye
RUN apt update
RUN apt install -y net-tools iputils-ping curl
RUN pip3 install requests elasticsearch==7.17.8
COPY v7.py v7.py
docker-compose
version: '3.7'
services:
app:
build:
context: ./app
dockerfile: Dockerfile
container_name: app
command: /bin/sh -c "while :; do sleep 10; done"
privileged: true
squid:
build:
context: ./squid
dockerfile: Dockerfile
container_name: squid
ports:
- 3128:3128
command
部分はコンテナが落ちないようにしているだけです。
ソースコード
v8
from elasticsearch import Elasticsearch
from elastic_transport import RequestsHttpNode
es = Elasticsearch("https://xxxx.es.asia-northeast1.gcp.cloud.es.io:9243",basic_auth=("elastic","xxxxxxxx"),node_class=RequestsHttpNode)
print(es.info())
v8.xはシンプルです。プロキシサーバの情報は環境変数から持ってきます。
v7
from elasticsearch import Elasticsearch, RequestsHttpConnection
class MyConnection(RequestsHttpConnection):
def __init__(self,*args, **kwargs):
proxies = kwargs.pop('proxies', {})
super(MyConnection, self).__init__(*args, **kwargs)
self.session.proxies = proxies
es = Elasticsearch("https://xxxx.es.asia-northeast1.gcp.cloud.es.io:9243",http_auth=("elastic","xxxxxxx"),connection_class=MyConnection, proxies = {})
print(es.info())
v7.xではconnection classを自前で用意する必要があります。
MyConnectionクラスがそれにあたります。
こちらを参考にしました。
https://github.com/elastic/elasticsearch-py/issues/275
プロキシサーバの情報はv8と同じように環境変数から持ってきます。
動作確認
では実際に動かしてみましょう。
v8
Dockerfileをv8のものにしてdocker-compose build
docker-compose up -d
を実行します。docker-compose ps
で以下のようになればOKです。
Name Command State Ports
-----------------------------------------------------------------------
app /bin/sh -c while :; do sle ... Up
squid entrypoint.sh -f /etc/squi ... Up 0.0.0.0:3128->3128/tcp
ではdocker exec -it app /bin/bash
でapp
に入って実際に通信を見てみましょう。
# curl google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
# python v8.py
{'name': 'instance-0000000001', 'cluster_name': 'e939240763684a8db3183d6f8b47d0a1', 'cluster_uuid': 'eLMujpfhTr2vc92rhENRvA', 'version': {'number': '8.4.2', 'build_flavor': 'default', 'build_type': 'docker', 'build_hash': '89f8c6d8429db93b816403ee75e5c270b43a940a', 'build_date': '2022-09-14T16:26:04.382547801Z', 'build_snapshot': False, 'lucene_version': '9.3.0', 'minimum_wire_compatibility_version': '7.17.0', 'minimum_index_compatibility_version': '7.0.0'}, 'tagline': 'You Know, for Search'}
これはもちろんプロキシサーバ経由ではありません。
少し乱暴ですがroute delete default
でルートを潰してみます。
# route delete default
# curl google.com
curl: (6) Could not resolve host: google.com
# python v8.py
Traceback (most recent call last):
File "//v8.py", line 5, in <module>
print(es.info())
^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/elasticsearch/_sync/client/utils.py", line 414, in wrapped
return api(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/elasticsearch/_sync/client/__init__.py", line 2296, in info
return self.perform_request( # type: ignore[return-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/elasticsearch/_sync/client/_base.py", line 286, in perform_request
meta, resp_body = self.transport.perform_request(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/elastic_transport/_transport.py", line 329, in perform_request
meta, raw_data = node.perform_request(
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/elastic_transport/_node/_http_requests.py", line 244, in perform_request
raise err from None
elastic_transport.ConnectionError: Connection error caused by: ConnectionError(Connection error caused by: ConnectionError(HTTPSConnectionPool(host='dep1.es.asia-northeast1.gcp.cloud.es.io', port=9243): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0xffff8341cdd0>: Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))))
では次にプロキシサーバを環境変数で設定します。
export http_proxy=http://squid:3128
export https_proxy=http://squid:3128
curl google.com
もpython v8.py
も問題なく動作します。
ここでSquidログを見てみます。
# docker-compose logs
...
squid | 1671678795.332 92 192.168.0.2 TCP_MISS/301 869 GET http://google.com/ - HIER_DIRECT/172.217.175.46 text/html
squid | 1671678828.075 72 192.168.0.2 TCP_TUNNEL/200 7151 CONNECT xxxxxxx.es.asia-northeast1.gcp.cloud.es.io:9243 - HIER_DIRECT/34.85.47.11 -
無事プロキシサーバ経由で動作していることが確認できます。
v7
v8と全く同じ手順でテストできます。
まとめ
ElasticのドキュメントにはPython Clientをプロキシサーバ経由で使用する場合についての記述がありません。
この記事が少しでもお役に立てばと思います。
おまけ
Advent Calendarが埋まってしまったため、一部掲載できない記事がありました。
弊社のコンサルタントによるKibana VEGAについての記事です。
こちらもぜひご覧ください。
https://gist.github.com/ijokarumawak/0dfcc1cca3ad38e1d5aae3b61b787cd4
Elastic Cloud 無料トライアル
こちらからElastic Cloudの14日間無料トライアルを是非お試しください
Elastic Cloud 無料トライアル
手順は下記リンクをご参照ください
Elastic Cloud について 〜実際にデプロイメントを作ってみよう〜