Azure Blob Storageを操作する ~無印~

今回はAzure Blob Storage SDKを使って、Python3で簡単なファイル共有ツールを実装してみたいと思います。

BLOB Storageはざっくり言うとオブジェクトストレージ。ここで使っているブロックBLOBは、容量の観点で見れば普通のオンラインストレージ(ファイル)よりも安上がりです。まあS3みたいなやつ。
ちょっとしたファイルを保管しておきたいとか、参照の性能を要求しないバックアップに使うとか、他のアプリケーションのバックエンドに使いたい場合に便利です。

OneDriveやGoogle Driveなどのいわゆるオンラインストレージと比較してAPIもシンプルで使いやすい反面、Office/Windows連携や検索機能などオフィス用途の機能や画像管理、ユーザ招待型のファイル共有機能などの付加価値的な機能はありません。
Azureにはファイルストレージのサービスもあるので、SMBで接続したい場合などにはそちらを使えばいいのですが、とにかくシンプルに容量があればいい、という場合にはブロックBLOBのほうが使いやすいです。

ここでは、ストレージとして使うために基本的と思われるアップロードとダウンロードを試します。
謹製のGUIクライアントも提供されていますが、スクリプトから叩けると便利ですよね。ということでMSから提供されているPython向けSDKで実装します。

環境はPython3.6+Windows 10 Pro、Python 3系のみで検証しています。
長くなってしまったので分けますが、もうちょっと賢い実装は別記事で。

もくじ:

はじめに

Azureのストレージサービスを使うには、ストレージアカウントなるものが必要です。
ストレージアカウント毎にキー(Base64的な文字列)が発行され、今回使うブロックBLOBや、その他ファイル、ページなどのリソースにアクセスする際の認証に必要となります。

ストレージアカウントはAzure Portalから作成できます。色々設定項目はありますが、デフォルトで大丈夫です。アカウントにもいくつか種類がありますが、デフォルトの汎用v2にしておけば特に困ることはないと思います。

キーは「アクセスキー」の画面で管理できます。後ほど使うのでどこかに保存しておいて下さい。

Blob Storage

スキーマを感覚的に図にするとこんな感じ。

各アカウントに複数のコンテナを作ることができ、コンテナの中にBLOBを格納します。
URIはこんな感じ。

コンテナの中はフラットになっており、サブディレクトリなどのツリー構造はありません。

コンテナはPortalの「BLOB SERVICE」-「コンテナー」の画面から作成できます。
もちろんAPI経由でも作ることができますが、今回は特定のコンテナを使うので何か作っておきます。
上に書いたURIもエンドポイントとして表示されていますね。

BLOBを公開すれば普通のhttpでもアクセスできるようになりますが、ここではオンラインストレージとして使いたいので非公開のプライベート(デフォルト)にしておきます。
非公開の場合は、BLOBへのアクセスがアカウント毎にキーで制御されますので、最低限アカウント名とキーがあればデータの読み書きが可能です。

SDK

MSからSDKが提供されているので、Python向けのものを使います。もちろんC#など他の言語もサポートされており、概念的には同じで、使い方もよく似ています。
もともとAzure StorageはREST API(http/https)を持っていますが、SDKはそれをラップするもののようです。

SDKはいつも通りpipで簡単にインストールできます。

いくつか依存モジュールがあるので、環境によってはちょっと時間がかかるかもしれません。

ファイル同期ツール

今回作成するのは、ローカルのファイルシステム上の特定のディレクトリにあるファイルと、Azure上のコンテナを同期するツールです。

ストレージアカウント名とキーさえ知っていればどこからでも使えるものができるはずです。
Azure Portalからコンテナの情報を見たり、BLOBをダウンロード・アップロードすることができるのでツールが多少バグっても大丈夫。

やや注意が必要な点として、上記のようにBLOBはフラットな構造になっている(コンテナを入れ子にできない)ので、配置はちょっと工夫する必要があります。
今回は最も単純に、ローカルのディレクトリ直下にあるファイルのみを対象にすることにします。
サブディレクトリ対応は次の記事で。

実装の実体はWeb APIなので普通にhttp/httpsを使える環境ならば大丈夫ですが、ここでは認証つきプロキシ環境も想定することにします。

BLOBの基本操作

今回のスクリプトです。_blob_clientクラスを定義しています。
原則的に例外はクラスの中で捕捉せず、問題があれば止まるようにします。

今回使うAPI (azure.storage.blobモジュールBlockBlobServiceクラス)はこんな感じ。

メソッド用途
BlockBlobService()ブロックBLOBサービス
.list_containers()コンテナ一覧の取得
.list_blobs()BLOB一覧の取得
.create_blob_from_path()ローカルパスからBLOBをアップロード
.get_blob_to_path()BLOBをローカルパスへダウンロード
.delete_blob()BLOBの削除

以下により詳細な使い方を記載しておきます。

Block BLOB Serviceへの接続

コンストラクタに必要な設定を辞書(dict)でまとめて渡します。
# 辞書にする必要はないのですが、まあ基本的なパラメータが明確になると思いますので。。。
Azure上のコンテナ("container")と同期対象のローカルディレクトリ("home_path")のパスを指定します。

基本となるのはBLOBストレージを扱うためのBlockBlobServiceクラスです。

必要な項目を指定してBlockBlobServiceクラスのインスタンスを作成します。上にも書きましたが、アカウント名とキーを正しく指定すれば接続可能です。
内部的に使用するプロトコルはprotocolで指定しますが、デフォルトでhttpsになっています。

このBlockBlobServiceオブジェクトの各メソッドを呼び出してコンテナやBLOBを操作します。

認証つきプロキシを通す場合には、BLOBの操作を行う前にset_proxy()メソッドを使っておきます。

上記のクラスはストレージ内の任意のコンテナにアクセスできるので必須ではありませんが、今回は専用にコンテナを用意するので、コンストラクタで保存しておきます。
せっかくなのでちゃんとアクセスできるかチェックします。

list_containers()メソッドがコンテナオブジェクトのリストを返してくるので、指定された名前のコンテナがあるかどうか確認します。

一覧表示

_blob_client.fetch_remote()メソッドでBLOB一覧の取得を実装しています。

list_blobs()メソッドはコンテナ名を指定すると、BLOB情報に相当するオブジェクトを指すリスト(正確にはジェネレータ)を返してきますので、BLOB名(blob.name)のみを取り出しています。

アップロード

_blob_client.upload()メソッドでBLOBのアップロードを実装しています。
create_blob_from_path()メソッドにコンテナ名とBLOB名、ローカルファイルへのパスを指定してアップロードします。

今回は対称のディレクトリ直下のすべてのファイルをアップロードします。ディレクトリがあった場合は単純に無視される実装です。BLOB名はファイルと同じにしています。
アップロードされていないファイルのみをアップロードする実装はまた次回。

ダウンロード

_blob_client.download()メソッドでBLOBのダウンロードを実装しています。

get_blob_to_path()メソッドにコンテナ名とBLOB名、ローカルファイルへのパスを指定して同期的にダウンロードします。ローカルファイルが既に存在する場合は上書きされます。

今回は対象のコンテナにある全てのBLOBがダウンロードされる実装です。ローカルにないファイルのみをダウンロードする実装はまた次回。

削除

_blob_client.clear()メソッドでBLOBの削除を実装しています。

delete_blob()メソッドにコンテナ名とBLOB名を指定することで同期的に削除します。今回は対象のコンテナにある全てのコンテナを削除する実装です。

テスト

さて、今回作成したスクリプトをテストしてみたいと思います。
_blob_clientクラスをインスタンス化して、各メソッドを呼ぶと、ちゃんとAzureのブロックBLOBストレージを操作できていることがわかりますね。

次回に続きます。