Cloudflaredを使ってLambdaからローカルに構築したOpenSearchへアクセスする

Argo Tunnel ClientのCloudflaredを利用して、ローカル環境に構築したOpenSearchとLambdaを接続してみました。
2021.09.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

現在、自分はProfllyというプロフィールビューアーサービスの開発を行っています。

Profllyでは、サービス内の検索エンジンとしてAmazon OpenSearch Service(旧Amazon Elasticsearch Service)を採用しています。

システム内においては、OpenSearch Serviceで起動しているOpenSearchドメインのエンドポイントに対しAWS Lambdaからアクセスを行う、という形になっていますが、開発環境ではコストを抑えたり自由に検証するために、OpenSearch Serviceのインスタンスではなく、個人のローカル環境に構築したOpenSearchを利用したい、というニーズがありました。

このエントリでは、CloudflaredというArgo Tunnel Clientを利用して、ローカルのOpenSearchとLambdaを接続するための構築手順をご紹介します。

構築イメージ

上記画像のように、Amazon OpenSearch Serviceをローカルにて構築したOpenSearch(with Docker)に置き換え、Cloudflare Argo Tunnelを経由してLambdaからアクセスできるようにしてみます。

検証環境

  • OpenSearch 1.0.1
  • OpenSearch Dashboards 1.0.1
  • Docker 20.10.8
  • Docker Compose 1.29.2
  • Cloudflared 2021.9.1 (built 2021-09-21-1033 UTC)

OpenSearchをローカル環境に構築

まず初めに、以下を参考にしてローカル環境にOpenSearch + OpenSearch Dashboardsを構築・起動しておきます。

OpenSearchをローカル環境でDockerを利用して構築する

今回は検証のためにセキュリティプラグインを無効化したため、Dockerで必要な各ファイルは以下のようになりました。

docker-compose.yml

version: '3'
services:
  opensearch-dashboards:
    build:
      context: .
      dockerfile: Dockerfile.dsbd
    container_name: opensearch-dashboards
    environment:
      OPENSEARCH_HOSTS: http://opensearch:9200
    ports:
      - 5601:5601
    links:
      - opensearch
    networks:
      - sandbox

  opensearch:
    build:
      context: .
      dockerfile: Dockerfile.os
    container_name: opensearch
    environment:
      - cluster.name=docker-cluster
      - node.name=os-node
      - cluster.initial_master_nodes=os-node
      - bootstrap.memory_lock=true
      - http.host=0.0.0.0
      - transport.host=127.0.0.1
      - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
      - "plugins.security.disabled=true"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - $PWD/.local/opensearch:/usr/share/opensearch/data
    ports:
      - 9200:9200
    networks:
      - sandbox

networks:
  sandbox:

Dockerfile.os

FROM opensearchproject/opensearch:1.0.1
RUN /usr/share/opensearch/bin/opensearch-plugin install https://artifacts.opensearch.org/releases/plugins/analysis-kuromoji/1.0.0/analysis-kuromoji-1.0.0.zip
RUN /usr/share/opensearch/bin/opensearch-plugin install https://artifacts.opensearch.org/releases/plugins/analysis-icu/1.0.0/analysis-icu-1.0.0.zip

opensearch_dashboards.yml

server.name: opensearch-dashboards
server.host: "0"
opensearch.hosts: http://localhost:9200

Dockerfile.dsbd

FROM opensearchproject/opensearch-dashboards:1.0.1
RUN /usr/share/opensearch-dashboards/bin/opensearch-dashboards-plugin remove securityDashboards
COPY --chown=opensearch-dashboards:opensearch-dashboards opensearch_dashboards.yml /usr/share/opensearch-dashboards/config/

Cloudflaredを使ってOpenSearchを外部からアクセス可能にする

ローカル環境でOpenSearchが起動できたら、Lambdaからインターネット経由でローカルのOpenSearchへアクセスできるように、ローカル環境でCloudflaredを設定していきます。

Cloudflaredについて

Cloudflaredは、Cloudflare社が提供するArgo Tunnel(Tunneling Daemon)のコマンドラインクライアントです。
Cloudflareのネットワークを介して、任意のローカルウェブサーバをプロキシすることができます。
類似する別のサービスとしては、ngrokなどが挙げられます。

Cloudflaredは、開発用途であれば基本的に無償で利用することが可能で、Cloudflareへのサインアップも必要無くインストールするだけですぐに利用することができます。

注意点として、起動時に割り当てられるURLtrycloudflare.comのサブドメインは起動ごとにランダムで生成されるため、起動ごとに異なるURLとなります。
実際にLambdaからアクセスする際は、これらを考慮しOpenSearchエンドポイントを環境変数などで外部から設定できるようにしておくとよいでしょう。

また、このエントリでは利用していませんが、自分で取得済みのカスタムドメインを割り当てることもできます。
(但し、利用するためにはCloudflareのサインアップおよびドメインの追加が必要となります)

Cloudflaredのセットアップと起動

それでは、実際にCloudflaredを設定してローカルのOpenSearchを外部公開してみます。

まずは、こちらのドキュメントを参考にインストールを行います。

$ brew install cloudflare/cloudflare/cloudflared

インストールできたら、こちらを参考にCloudflare Tunnelを新規作成し、起動済みのローカルOpenSearchのURL/ポートを割り当ててみます。

$ cloudflared tunnel --url http://localhost:9200
...
2021-09-26T02:57:11Z INF Requesting new quick Tunnel on trycloudflare.com...
2021-09-26T02:57:12Z INF +--------------------------------------------------------------------------------------------+
2021-09-26T02:57:12Z INF |  Your quick Tunnel has been created! Visit it at (it may take some time to be reachable):  |
2021-09-26T02:57:12Z INF |  https://tex-buildings-sandy-live.trycloudflare.com                                        |
2021-09-26T02:57:12Z INF +--------------------------------------------------------------------------------------------+
...

コマンドを実行すると、Cloudflare側でランダムなURLを生成し、指定したlocalhostのURLに割り当てられます。
今回は、https://tex-buildings-sandy-live.trycloudflare.comというURLが生成されたようです。

実際にアクセスできるか、割り当てられたURLを指定してcurlを叩いてみます。

$ curl -XGET https://tex-buildings-sandy-live.trycloudflare.com
{
  "name" : "os-node",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "5wu-pBlIQb-64niPP_zY0A",
  "version" : {
    "distribution" : "opensearch",
    "number" : "1.0.0",
    "build_type" : "tar",
    "build_hash" : "34550c5b17124ddc59458ef774f6b43a086522e3",
    "build_date" : "2021-07-02T23:22:21.383695Z",
    "build_snapshot" : false,
    "lucene_version" : "8.8.2",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "The OpenSearch Project: https://opensearch.org/"
}

ひとまず、OpenSearchにはアクセスできているようですね。

LambdaからローカルOpenSearchへアクセスする

これで外部からローカルのOpenSearchにアクセスできるようになったので、実際にLambdaからアクセスできるかを試してみます。

Lambdaのソースコード

今回、検証のために適当にローカルOpenSearch上に準備したdevio_sampleというインデックスにアクセスしてみます。
Lambdaのサンプルコード(ランタイムはNode.14.x)は、以下のようになります。

index.js

const { Client } = require('@opensearch-project/opensearch');

const OPENSEARCH_ENDPOINT = process.env.OPENSEARCH_ENDPOINT || "";
const client = new Client({
  node: OPENSEARCH_ENDPOINT
});

exports.handler = async (event) => {
  const result = await client.search({
    index: 'devio_sample',
    pretty: true
  });
  return result;
};

なお、OpenSearchのクライアントライブラリopensearch-jsを利用しているので、コードをLambdaへデプロイする際はパッケージに含めておきます。

$ npm install https://github.com/opensearch-project/opensearch-js
$ zip -r function.zip ./

また、OPENSEARCH_ENDPOINT という環境変数でOpenSearchのエンドポイントを指定できるようにしているので、Lambdaの環境変数に先程割り当てられたURL https://tex-buildings-sandy-live.trycloudflare.com を設定しておきます。

Lambdaを実行してアクセスしてみる

上記ソースコードのzipがデプロイできたら、実際にLambdaを実行してみます。

無事、ローカルのOpenSearchに格納されたインデックスの検索結果が取得できています!
これにて、Lambda -> ローカルのOpenSearchへのアクセスが実現できました。

おわりに

ローカルに構築されたOpenSearchに対し、Cloudflaredを使ってLambdaからアクセスできるようにしてみました。
開発環境においては、OpenSearch Serviceのインスタンス -> ローカル環境に構築したOpenSearchに切り替えることで、よりコストを抑えた開発が実現できるのではないかと思います。

どなたかの参考になれば幸いです。

参考

ローカルで起動しているElasticsearchにLambdaからアクセスしてみる