2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

S3 から Google Drive へ Lambda を使ってファイルアップロード

Posted at

はじめに

この記事では、AWSのLambdaを使用してAmazon S3からGoogle Driveにファイルをアップロードする方法を紹介します。
Google Drive APIを活用することで、プログラム的にドライブ内のファイル操作が可能になります。

S3 から Google Drive へ Lambda を使ってファイルアップロード

Google プロジェクトの作成

画面を見ながら操作したい方は、こちらを参考して作業を進めて下さい。

  1. Google Drive API を有効にする

    • Google Cloud Platformで新しいプロジェクトを作成し、Google Drive APIを有効にします。
  2. Google Cloud でサービスアカウントを作成する

    • Google Cloud Platformでサービスアカウントを作成し、必要な権限を付与します。
  3. サービスアカウントの秘密鍵を作成(jsonダウンロード)

    • 作成したサービスアカウントで秘密鍵(JSON形式)を生成し、ダウンロードします。
  4. Google Drive の共有するフォルダにサービスアカウントを紐付ける

    • Google Driveで共有するフォルダを作成し、サービスアカウントをフォルダに紐付けます。URLの一番最後のキーも取得します。

S3

  1. バケットを作成する

    • AWS S3で新しいバケットを作成します。
  2. ファイルを配置する

    • 作成したバケットにアップロードするファイルを配置します。

Lambda

  1. Lambda Layer を作成する

    • Lambda でgoogle-apiのライブラリを使用するために、ローカル環境でセットアップします。
    $ mkdir python && cd python
    $ pip install google-api-python-client -t .
    $ pip install oauth2client -t .
    $ zip -r python.zip python/
    
    • 作成したpython.zipをLambda Layerにアップロードします。
  2. Lambda 関数を作成する

    • 新しいLambda関数を作成し、作成したLambda Layerをアタッチします。
    • IAMロールにS3のアクセス権を設定します。(必要な権限のみ)
    • service-account-key.jsonをアップロードして、lambda_function.pyと同じ階層に配置します。
    • service-account-key.jsonに**サービスアカウントの秘密鍵を作成(jsonダウンロード)**で取得したjsonの内容をコピペして下さい。
    • 以下のソースコードをlambda_function.pyに貼り付けます。
    import os
    import boto3
    from googleapiclient.discovery import build 
    from googleapiclient.http import MediaFileUpload 
    from oauth2client.service_account import ServiceAccountCredentials 
    
    def create_s3_client():
        """S3クライアントを作成する"""
        return boto3.client('s3')
    
    def download_file_from_s3(s3, bucket, key, local_path):
        """S3からファイルをダウンロードする"""
        s3.download_file(Bucket=bucket, Key=key, Filename=local_path)
    
    def create_google_drive_service():
        """Google Driveサービスを作成する"""
        scope = ['https://www.googleapis.com/auth/drive.file'] 
        keyFile = 'service-account-key.json'
        credentials = ServiceAccountCredentials.from_json_keyfile_name(keyFile, scopes=scope)
        return build("drive", "v3", credentials=credentials, cache_discovery=False)
    
    def upload_file_to_google_drive(service, file_name, local_file_path, folder_id):
        """Google Driveにファイルをアップロードする"""
        mime_type = get_mime_type(local_file_path)
        file_metadata = {"name": file_name, "mimeType": mime_type, "parents": [folder_id]}
        media = MediaFileUpload(local_file_path, mimetype=mime_type, resumable=True)
        service.files().create(body=file_metadata, media_body=media, fields='id').execute()
    
    def get_mime_type(file_path):
        """ファイルのMIMEタイプを取得する"""
        ext = os.path.splitext(file_path.lower())[1][1:]
        if ext == "jpg":
            ext = "jpeg"
        return "image/" + ext
    
    def handle_file_processing(bucket, key, folder_id):
        """ファイルの処理を行うメインの関数"""
        local_path = "/tmp/" + os.path.basename(key)
        s3_client = create_s3_client()
        google_drive_service = create_google_drive_service()
    
        try:
            download_file_from_s3(s3_client, bucket, key, local_path)
            upload_file_to_google_drive(google_drive_service, os.path.basename(key), local_path, folder_id)
        finally:
            clean_up_local_file(local_path)
    
    def clean_up_local_file(file_path):
        """ローカルファイルを削除する"""
        if os.path.exists(file_path):
            os.remove(file_path)
    
    def lambda_handler(event, context):
        try:
            bucket = os.environ.get('S3_BUCKET_NAME', 'default-bucket-name')
            key = event.get('key')
            folder_id = event.get('folder_id')
    
            print(f"Received file from S3: Bucket={bucket}, Key={key}, FolderID={folder_id}")
            handle_file_processing(bucket, key, folder_id)
        except Exception as e:
            print(f"Error in lambda handler: {e}")
            raise e
    
  3. テスト実施

Lambda 関数の作成後、適切に機能するかを確認するためにテストを行います。
以下の手順に従ってテストを実施してください。

  • テストイベントを作成する

    • Lambda関数のページで「テストイベント」を選択し、「新しいテストイベントを作成」をクリックします。

    • テストイベントに名前を付け、以下のJSON構造をボディにコピーします。

      {
          "folder_id": "ここに取得したfolder_idを入力",
          "key": "sample.png"
      }
      
      • 「folder_id」の値は、「Google Drive の共有するフォルダにサービスアカウントを紐付ける」セクションで取得したfolder_id(フォルダのURLの一番最後のキー)を使用します。
      • 「key」の値は、S3バケット内のテストしたいファイル名を指定します。
  • テストを実行する

    • テストイベントを保存した後、Lambda関数ページの「テスト」ボタンをクリックしてテストを実行します。
  • 結果を確認する

    • テスト実行後、結果がLambda関数ページの下部に表示されます。成功した場合、指定したファイルがGoogle Driveの指定したフォルダにアップロードされていることを確認してください。
    • エラーが発生した場合は、ログ出力を確認し、問題の原因を特定して修正します。

テストを通じて、Lambda関数が正しく機能していることを確認できます。
特に、Google Drive APIとの連携やS3からのファイルの取得など、各ステップが正しく動作しているかをチェックしてください。

まとめ

この記事では、Google Drive APIを利用して、AWS LambdaとS3を組み合わせたファイルアップロードのプロセスを紹介しました。
サービスアカウントの設定からLambda関数の作成まで、具体的な手順を説明しました。
これにより、Google Driveへの自動化されたファイルアップロードが可能となり、より効率的なファイル管理が実現できます。

参考

  • Lambda(Python)でGoogle Driveへファイルアップロード: Qiita
  • Google Drive API の概要: Google Developers
  • Google Workspace API の有効化: Google Developers
  • AWS Lambda Layerの作成方法をわかりやすく解説【Python3.9】: Qiita
2
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?