LoginSignup
0
1

More than 3 years have passed since last update.

【Google Cloud Platformの使い方】GCP Storage にファイルの出し入れ(python3/Web API)

Last updated at Posted at 2020-05-04

今日は、Google Cloud Storage にファイルをupload するところを復習したので、そのメモを書きます。

準備

データはBucket というラベルの単位で管理します。ここにファイルをホイホイ入れたり出したりします。

簡単に使う分にはCloud Storage のクイックスタートをフォローするだけで十分です。

bucket の作成

コマンドラインからも作れますが、console.cloud.google.com から行ったほうが便利です。何度も作るものではないと思うので。

コンソールのStorage のブラウザから、「バケット作成」にたどり着けます。下記の画面では、私が作った(塗りつぶした)bucket のほかに、最初から xxxx.artifacts.projectid.appspot.com という名前のbucket がありました。これは開くと分かりますが、Cloud Build で作成したdocker image が置かれていました。(今回は関係ありません)

image.png

アクセス権の設定

どうやらbucket 単位でアクセス権を設定することができるようです。
全てのユーザに与えたり、特定にユーザにしたりできます。
個別のユーザだけでなく、allUsers, allAuthentificatedUsers が選べます。
おそらく入門ガイドにある「機能の使用」や「アクセスの制御」をじっくり理解しなければならないのだと思いますが、今回は精読をスキップして、以下のようにデフォルトのサービスアカウントに権限を割り当てて、そのアカウントのキーを使用しました。

サービスアカウントとキー

CREDENTIAL の扱い方については、いろいろな方法が用意されていますが、私はもともとこのプロジェクトにデフォルトで作成されているサービスアカウントを使うことにしました。
「IAMと管理」の「サービスアカウント」をみると、10000000000-compute@developer.gserviceaccount.com のようなCompute ENgine default service account がありました。

image.png

  • GCPで動かすときはこのアカウントが使われるらしい。ので、これに「ストレージオブジェクト管理者」のロールを与えます。さらに、作成したbucket にも権限を与えます。 (←これは違うかも。今は、キーファイルを使って運用しています。。。)
  • ローカルで動かすときは、このサービスアカウントの鍵を作成し、これを環境変数GOOGLE_APPLICATION_CREDENTIALSに設定して利用します。

鍵は「サービスアカウント」のページの編集から鍵生成の画面に入れます。流れに従って鍵を生成すると myproject-0123456789012345.json のようなファイルが生成されるので、これを保存します。環境変数に設定します。

export GOOGLE_APPLICATION_CREDENTIALS=/...your_dir/myprojectid-0123456.json

サービスアカウントにbucket へのアクセス権を付与

bucket へのアクセスするには、使用するサービスアカウントがその権限を持っているかで制御します。今は、自分が作ったbucket に使用するサービスアカウントを追加しました。

先ほどと同じストレージブラウザで対象となるbucket を選択し、「バケットの権限を編集」を起動します。「ユーザの追加」から先ほどのサービスアカウントを選択し、「ロールの追加」でCloud Storage の「ストレージオブジェクト管理者」を選択して保存しました。

image.png

その他いろいろごちゃごちゃやったので、いまいちクリアにはなっていないので、もしかしたら少し違うかもしれませんが、私はこれで動いています。

サーバー間での本番環境アプリケーションの認証の設定を参考にしました。

python によるファイルの出し入れの実装

google-cloud-storage を pip でインストールします。
https://pypi.org/project/google-cloud-storage/
ここでは全てpython3 で実装と動作確認を行っています。

Storage にアクセスするClient

pythonの実装では、まず、Storage へのClient を作成します。
CREDENTIAL の設定ができていれば、以下でclient が作成されるはずです。直接にkeyファイルを指定するにはstorage.Client.from_service_account_json()も使えますが、最近は上記のように環境変数を利用するほうがサーバとローカルとで同じ関数で書けるので使わなくなりました。

import google.cloud.storage as storage
from os import environ
def test_bucket():
    print("GOOGLE_APPLICATION_CREDENTIALS={}".format(environ.get("GOOGLE_APPLICATION_CREDENTIALS")))
    client = storage.Client()
    for bucket in client.list_buckets():
        print(bucket)

今一つbucket を作っていたので、以下のようになります。

GOOGLE_APPLICATION_CREDENTIALS=myserveraccountkey.json
<Bucket: asia.artifacts.my-project.appspot.com>
<Bucket: my-bucket>

file のupload

あとは、例文にあるように実装するだけです。が、APIの解説ではupload_from_file の引数がfile_obj ですが、私が動かしている範囲ではfile のpath を引数にしないとダメなようです。また、この状態だと、同じファイル名だと上書きを行っています。

import google.cloud.storage as storage
from os import path

def upload_file(local_fpath:str, bucket_name:str, remote_fpath:str):
    client = storage.Client()

    bucket = client.lookup_bucket(bucket_name)
    assert isinstance(bucket, storage.bucket.Bucket)

    bucket = client.get_bucket(bucket_name)

    if not path.isfile(local_fpath):
        return ""
    blob = bucket.blob(remote_fpath)
    if blob is not None:
        blob.upload_from_filename(local_fpath)
        url = "https://console.cloud.google.com/storage/browser/{}/{}".format(bucket_name, remote_fpath)
        return url
    return ""

file の download

同様にしてdownload もできます。ここでもdownload_to_fileの引数はファイルのパスで動いています。

import google.cloud.storage as storage
def download_file(bucket_name:str, remote_fpath:str, local_fpath:str):
    client = storage.Client()
    bucket = client.lookup_bucket(bucket_name)
    blob = bucket.blob(remote_fpath)
    if blob is not None:
        blob.download_to_filename(local_fpath)

最低限のことはできるようになりました。

WEB APIの利用

実はpython API で実装している中身はREST APIを使って通信をしているらしいです。今回は、ファイルの存在だけ確認しました。使い方は、APIリファレンスのobject/listに書かれています。

GET https://storage.googleapis.com/storage/v1/b/<bucket-name>/o

解説ページでパラメータの動作確認ができる

この解説ページのある"try it"で簡単に試すことができます。

image.png

ここでは簡単に動きました。Storage のbucket の所定のprefix (フォルダ)にあるはずのファイル名が返ってきました。

OAUth 2.0 Playground (開発者向けの動確ページ)

ですが、実際にターミナルで動かすにはまた一苦労です。OAuth のaccess token が必要でした。

OAuthを利用したリクエストは、OAUth 2.0 Playgroundで試すことができます。token を作成し、http request を試すことができます。token 発行までの流れはここの手順に従っていけば良く、gcloud auth login と同じようにアカウントが認証します。

image.png

WEB APIで確認

ここで実行したリクエストをcurl でも動作することを確認しました。my-bucket-name というbucket にあるtest/dir01 以下にあるファイル名を取得します。access token は先に取得したもので、ya29.で始まる文字列でした。

curl 'https://storage.googleapis.com/storage/v1/b/my-bucket-name/o?prefix=test%2Fdir01' \
    --header 'Authorization: Bearer ya29.accesstokenislooooooooooooooooong' \
    --header 'Accept: application/json' \
    --compressed

{
  "kind": "storage#objects",
  "items": [
    {
      "kind": "storage#object",
      "id": "mqtt-log-test/test/dir01/my-filename/1234567890123456",
      "selfLink": "https://www.googleapis.com/storage/v1/b/my-bucket-name/o/test%2Fdir01%2Fmy_filename",
      "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/my-bucket-name/o/test%2Fdir01%2Fmy_filename?generation=1588578408260925&alt=media",
      "name": "test/dir01/my-filename",
      "bucket": "my-bucket-name",
      "generation": "1234567890123456",
      "metageneration": "1",
      "contentType": "application/x-tar",
      "storageClass": "STANDARD",
      "size": "192852",
      "md5Hash": "vLES9qETsDyglngtaBsrdw==",
      "crc32c": "XxXxXx==",
      "etag": "CL3K493bmekCEAE=",
      "timeCreated": "2020-05-04T07:46:48.260Z",
      "updated": "2020-05-04T07:46:48.260Z",
      "timeStorageClassUpdated": "2020-05-04T07:46:48.260Z"
    }
  ]
}

便利なgsutil

実は急いでダウンロードしたときはgsutil を使っています。早くて便利だ。

gsutil -m cp gs://bucket_name/......./* .

所感

とりあえずファイルの出し入れはできるようになりました。また、権限の問題も最低限のところはクリアできた感じです。自分はpython の実装も十分に楽ですが、REST APIの方がもっと楽だという話も聞きます。

ぱらぱら見ていると、
- データを暗号化できる
- ユーザごとにアクセス権や暗号化キーを設定できる
など、APIドキュメントや解説を見ていても、いろいろ使い方あるようです。

ふー。
(2020/05/04)

追記

  • (2020/05/05) 実際にbucket にファイルをupload するとき、"dir01/dir02/file"ならOKですが、"dir01/dir02//file" はNGでした。
  • (2020/05/06) サービスアカウントにあった長い数字はPROJECT NUMBER らしい。これはシェルからは gcloud projects describe ${PROJECT_ID} --format='get(projectNumber)' で取得できる。
  • (2020/05/06) 権限のところ、勘違いがあったかもしれないので、取り消し線を入れました。
  • (20200615) gsutil を追加
0
1
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
0
1