5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ElixirAdvent Calendar 2017

Day 9

Elixir で Microsoft Azure の BLOB Storage を操作する

Last updated at Posted at 2017-12-08

時は2017年、クラウドストレージやオブジェクトストレージといったものが、当たり前のように使われる時代になりました。特に、Amazon, Microsoft, Google等、パブリッククラウドサービスの事業者が提供するオブジェクトストレージサービスは、可用性・信頼性・スケーラビリティ、そして価格(TCO)の面で、オンプレに比べて大きなアドバンテージがあると言えるでしょう。

今回、私が仕事で使っている組み合わせである、Elixir と Azure BLOB Storage との組み合わせをご紹介します。

Microsoft Azure BLOB Storage について

スケーラブルな非構造化データ用オブジェクトストレージです。詳しくは公式をご覧ください。

比較?

AWSやGCPとの比較にあたっては、一概には甲乙付けがたいのですが、Azureは他と比べてSLAが高めに設定されている点が、エンタープライズ利用を強く意識しているのかな?と思っています。

object-storage-aws-azure-google-rightscale-100719437-large.jpg

(Deep dive on AWS vs. Azure vs. Google cloud storage options | Network World より転載)

SLA 99.95% (AWS, Google) と 99.99% (Azure) の差は、年間のサービス停止時間が最大15,768秒 か 3,154秒 かの違いです。

ま、細かいことは気にせず、先に進みましょう。

ExAzure

azukiapp/ex_azure: Azure wrapper for Elixir using :erlazure.

Erlangで利用可能な Azure Storage Services のAPIライブラリである erlazure の、Elixir用ラッパーです。

インストール

公式のREADME.md に書かれている通り・・・ではなく、そちらは書き方がちょっと古いので注意。以下に、本稿執筆時点で動作する書き方で、インストール手順を示します。

dependencies として定義

mix.exsdeps/0 内のリストに以下のエントリを加えます。

{:ex_azure, "~> 0.1.0"}

Phoenix Framework の場合、以下のようになります。

  defp deps do
    [
      {:phoenix, "~> 1.3.0-rc"},
      {:phoenix_pubsub, "~> 1.0"},
      {:phoenix_ecto, "~> 3.2"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_html, "~> 2.10"},
      {:phoenix_live_reload, "~> 1.0", only: :dev},
      {:gettext, "~> 0.11"},
      {:cowboy, "~> 1.0"},
      {:ex_azure, "~> 0.1.0"}
    ]
  end

OTPアプリケーションとして登録

mix.exsapplication/0 内のリスト内、extra_applications キーに対応する値のリストに、 :ex_azure を加えます。(存在しない場合はキーごと作ります。)

Phoenix Framework の場合、以下のようになります。

  def application do
    [
      mod: {MyApp, []},
      extra_applications: [:logger, :ex_azure]
    ]
  end

認証情報を設定

use Mix.Config されているファイル (Phoenix Framework の場合は config/*.exs ) にて、account と access_key の情報が受け取れるようにします。

以下は公式の例で、それぞれの情報を環境変数から取得します。

config :ex_azure,
    account:    System.get_env("AZURE_ACCOUNT"),
    access_key: System.get_env("AZURE_ACCESS_KEY")

なお、 access_key の取得は、Webブラウザを利用して、 portal.azure.com より、Storage accounts > ${Storage Account名} > Access Keys から行います。

使い方

最低限、以下の3つの処理及び実装方法を押さえておけば :ok でしょう。

List

コンテナ container_name 内のオブジェクトに関するリストを取得します。

{:ok, blobs} = ExAzure.request(:list_blobs, [container_name])

Get

container_name コンテナから object_name オブジェクトをダウンロードします。

{:ok, {:ok, file}} = ExAzure.request(:get_blob, [container_name, object_name])

Create

local_object_path からデータを読み取り、 container_name コンテナに object_name という名前でオブジェクトを保存します。

{:ok, _created} = ExAzure.request(:put_block_blob,
  [container_name, object_name, File.read!(local_object_path)])

戻り値の created は、created というStringが入っているだけなので、捨てて良いです。

便利な自作ヘルパーモジュール

list_blobs の戻り値は、このような構造の Dict になっています。

%{body:
  [
    {
      :cloud_blob,
      'some_object_name.jpg',
      [],
      [],
      [
        last_modified: 'Sun, 29 Oct 2017 02:44:06 GMT',
        etag: '0x8D51E76ECA421B3',
        content_length: 125182,
        content_type: 'application/octet-stream',
        content_encoding: [],
        content_language: [],
        content_md5: 'PUgbs4kkHJWBpitHhGWsgw==',
        cache_control: [],
        blob_type: :block_blob,
        lease_status: :unlocked,
        lease_state: :available
      ],
      []
    },
    ...
  ]
}

このうち欲しい情報は限られているので、それを取得する get_info/3 や、URL文字列を構築するための build_url/2、オブジェクトをダウンロードした上でディスク上への保存まで行う download/3 などを含む、便利なモジュールを自作しました。よろしければご自由にどうぞ。

defmodule MyApp.AzureBlob do
  use MyApp.Web, :model

  def get_info(x, container_name, acc \\ [])

  def get_info([h|t], container_name, acc) do
     acc = if elem(h, 0) == :cloud_blob and elem(h, 1) |> List.to_string() == container_name do
       acc ++ elem(h, 4)
     else
       acc
     end
     get_info(t, container_name, acc)
  end

  def get_info([], _container_name, acc) do
    acc
  end

  def build_url(object_name, container_name) when is_binary(object_name) and is_atom(container_name) do
    Application.get_env(:my_app, :object_storage)[:base_url]
      <> "/"
      <> Application.get_env(:my_app, :object_storage)[:containers][container_name]
      <> "/"
      <> object_name
  end

  def download(object_name, container_name, dirname) when is_binary(object_name) and is_binary(container_name) and is_binary(dirname) do
    {:ok, {:ok, file}} = ExAzure.request(:get_blob, [container_name, object_name])
    :ok = File.write(Path.absname(dirname <> "/" <> object_name), file)
    :ok
  end

end

erlazure

gullitmiranda/erlazure: Windows Azure Erlang bindings

ここで、ExAzure がラップする、Erlang の erlazure に関しても少し見てみましょう。
Elixir からも利用可能ですが、使い勝手の上では、 erlazure はプロセスとして予め明示的に立ち上げておく必要があるという点が大きく異なります。

{:ok, pid} = :erlazure.start(account, key)

そして例えば Create 操作をする場合は、以下の要領となります。

{ok, _created} = :erlazure.put_block_blob(pid, container_name, object_name, Binary)

ExAzure の方が若干シンプルですね。

まとめ

Elixir で Microsoft Azure の BLOB Storage を利用する手法として、 ExAzure をご紹介しました。
erlazure のラッパーであるため、今回ご紹介したもの以外にも、様々な関数が実行できるはずです。また、今回
BLOB Storage にフォーカスしましたが、erlazure はそれだけでなく、Queue StorageTable Storage にも対応しており、この点は ExAzure に関しても同様なのではないでしょうか。
Microsoft Azure の BLOB Storage、あるいは 各種Storage Service を利用される際は、ぜひ使ってみて下さい。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?