😀

Daprつかってみた(Web APIのイメージでローカルストレージとGCSを同じように扱ってみる)

2021/12/05に公開

この記事は Web API Advent Calendar 2021 の5日目の記事になります

ちなみに4日目は
@sys_zeroさんのPower Automate for desktopの変数に関するTips「JSONにnull値がある場合の選択的置換」でした

今回は、当日まで全く内容について考えられてなかったのですが、ふっと、頭にわいた、個人的に気になっているDaprについて調べて、ローカルストレージとGoogle Cloud Storage(以下GCS)を扱ってみます

なんで今回Dapr?

Daprを使うメリットの1つとして、他のサービスにつなぐ方法をHTTPまたはgRPCにすることができるというのがあります。
この、他サービスとは、Daprのホームページに有る通り、ローカルストレージや、redisやmysqlなどのストレージ、はたまた、クラウド環境になります。
Daprのコンセプト
(https://docs.dapr.io/concepts/overview/ にある図です)

つまり、アプリケーション側は接続先が具体的に何であるかを意識しないでHTTPやgRPCで操作できるというのが嬉しいポイントです。
今まではインフラ層として、アプリケーション側で頑張って抽象化していた部分を、Daprが実装してくれていることにより、設計の手間を減らせそうなのが良さそうだと個人的思っています。
また、言語によってあるサービスがちょっと使いにくいライブラリだったり、そもそもライブラリがないなどがあると思いますが、Daprなら、HTTPで接続するようにしようなどとなるかもしれません。

もう一つ面白い点として、Daprの特徴として一つはアプリケーションとして組み込むライブラリとして動くのではなく、sidecarという形で、実際のアプリケーションと一緒に起動するアプリケーションとして起動します。
そのため、sdkも使わないのであれば、ただただhttp clientまたはgRPCのクライアントを入れるだけでローカルファイルや、redisやmysqlの操作ができるということになります。このあたりは今回紹介しませんが、実際にアプリケーションを作ってみるなどして確認するといいかと思います。
Daprアーキテクチャ
(https://docs.dapr.io/concepts/overview/ にある図です)

デメリットとしては、既存で使えるものが限られる点だと思います。
ただ、足りない部分は自分たちで作成して、Daprのinterfaceに合わせることで、アプリケーションを抽象化できるので、その点は小さい問題点な気もします。(結局作らないといけないなら一緒かなと)

実行環境

アプリケーションまたはOS バージョン
MacOS Monterey(M1) 12.0.1
Docker Desktop 4.3.0
Dapr 1.5.0

インストールについては DaprのGeting Started を参考にしてください。

ローカルストレージを扱う

まずローカルファイルの中身の取得とファイルの作成をやってみます。
Local Storage binding specとだいたい同じ内容です

Daprのコンポーネント作成する

細かい点は説明しませんが、PATHの部分がローカルファイルが置かれる場所になります。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: storage
  namespace: default
spec:
  type: bindings.localstorage
  version: v1
  metadata:
  - name: rootPath
    value: <PATH>

構成としては以下のようになります。

.
└── my-components
    └── test.yaml

上記のアプリケーション起動のコマンドとしては以下です。ファイルを指定せずいけます。

$ dapr run --app-id storage-test --dapr-http-port 3500 --components-path ./my-components

ファイルの作成

ファイルの作成なのでoperationはcreateです。
ちなみに、metadataをつけない場合はuuidでファイルが作成されます

$ curl -i -d '{ "operation": "create", "data": "Hello World", "metadata": {"fileName": "sample.txt"} }' http://localhost:3500/v1.0/bindings/storage

HTTP/1.1 200 OK
Server: fasthttp
Date: Sat, 04 Dec 2021 13:05:16 GMT
Content-Type: application/json
Content-Length: 25
Traceparent: 00-a1f93ae88050c49941bc194378f8bd7d-43cc4ecc7cd8071b-01

{"fileName":"sample.txt"}

コンポーネントで指定した場所に sample.txt が作成されているはずです。
ちなみに再度実行した場合200が返り、裏書きされます。

ファイルの取得

ファイルの中身取得はoperation getです。

$ curl -i -d '{ "operation": "get", "metadata": { "fileName": "sample.txt" }}' http://localhost:3500/v1.0/bindings/storage

HTTP/1.1 200 OK
Server: fasthttp
Date: Sat, 04 Dec 2021 13:21:38 GMT
Content-Type: application/json
Content-Length: 11
Traceparent: 00-f112a8e70c0cd249d2334935e81520ff-d8622ed38d2bfd3d-01

Hello World

こんな感じで取得できます。
もし対象のファイルがない場合は500が返ります。このあたりはもう少し調査してもいいかもです。

今回紹介ありませんが、deleteとlistもできます。

GCSを扱う

ローカルとは違いgcsへのアクセスが必要になるためGCPのservice accountのjsonの情報を記載してくことになります。
基本はGCP Storage Bucket binding spec同じになります。
今回、bucketとservice accountの作成方法は省略しますが、作成しておく必要があります。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: storage-2
  namespace: default
spec:
  type: bindings.gcp.bucket
  version: v1
  metadata:
  - name: bucket
    value: <bucketname>
  - name: type
    value: service_account
  - name: client_email
    value: <client email>
  - name: private_key
    value: "  "

注意するところは上記のmetadataの値はミスっていても動いて、ファイル作成は動いてしまうという点ですね。また、リファレンス先ではパラメータは必須のものが多いのですが検証していったり、自分の経験上これはいらんだろとなったものは、なくても問題なく動きました。

こちらの、componentですが、先程のlocalと同じファイルに記載していっても問題ありません。(k8sのyamlのイメージ)。

ファイルの作成

ファイルの作成なのでoperationはcreateです。
ローカルと同じようにできます。ただファイルに名前をつける際はkeyに指定することになります。

$ curl -i -d '{ "operation": "create", "data": "Hello World", "metadata": {"key": "sample.txt"} }' http://localhost:3500/v1.0/bindings/storage-2

HTTP/1.1 200 OK
Server: fasthttp
Date: Sat, 04 Dec 2021 14:24:52 GMT
Content-Type: application/json
Content-Length: 79
Traceparent: 00-2c99123f4379b2106fe61daa558762ea-34873aa800a6b22c-01

{"objectURL":"https://storage.googleapis.com/<bucketname>/sample.txt"}

コンポーネントで指定した場所に sample.txt が作成されているはずです。
ちなみに再度実行した場合200が返り、裏書きされます。

ファイルの取得

ファイルの中身取得はoperation getです。先ほどと同じようにファイルを指定する場合はkeyを使います。

$ curl -i -d '{ "operation": "get", "metadata": { "key": "sample.txt" }}' http://localhost:3500/v1.0/bindings/storage-2

HTTP/1.1 200 OK
Server: fasthttp
Date: Sat, 04 Dec 2021 13:21:38 GMT
Content-Type: application/json
Content-Length: 11
Traceparent: 00-f112a8e70c0cd249d2334935e81520ff-d8622ed38d2bfd3d-01

Hello World

こんな感じで取得できます。
ローカルと同じようにlistも使えます。

まとめ

twitterでも話題に上がっていて気になっていたんですが、実際使ってみると余計に良いものだなと思うようになりました。
今回bindingのstorage系についてでしたが、pubsubなどもあるので、APIとして各サービスを扱うという点において、是非試してみてください。

Discussion