LambdaからBigQueryを実行する

# はじめに
LambdaからBigQueryのクエリを発行します。その調査記録です。
基本はAWSを使用していますが、定期的にGCPのBigQueryを参照する機会がありました。
簡単にLambdaで実行すると便利かと思いました。

# 環境の概要
LambdaのPythonから、GCPのSDKを使用します。
GCPのSDKはレイヤーに保持します。
AWS側に、GCPの認証を設定する必要があります。

<img width="695" alt="スクリーンショット 2019-11-16 17.55.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/ddde73d8-3ad7-03fb-4542-255ab1fc7f4f.png">

SDKと言っているのは、Pythonのクライアントライブラリーのことです。
https://googleapis.dev/python/bigquery/latest/generated/google.cloud.bigquery.client.Client.html

# 手順
## 前提条件
AWSアカウントを所有している。
GCPアカウントを所有している。APIからBigQueryを使える。
BigQueryテーブルは作成済み。
AWSのアクセスキーを所有している

## Lambda関数を作成する。
BigQueryを実行するのみのPythonコードです。まずは、これを動かします。

- Lambda関数の設定は以下です。
  - 新規作成
  - Python3.8
  - アクセス権限は自動生成のCloudWatch Logsのみ。
  - タイムアウトは30秒にしました。
  - レイヤーと環境変数は後ほど。
  - <>は自分の値を設定します。

```python
import json
from google.cloud import bigquery

def lambda_handler(event, context):
    client = bigquery.Client()
    sql = """
        SELECT *
        FROM `<my-project>.<my-dataset>.<my-table>`
        LIMIT 10
    """
    
    # Run a Standard SQL query using the environment's default project
    results = client.query(sql).result()
    for row in results:
        print(row)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```
## Lambdaのレイヤーに登録するための、GCPのSDKを作成する。
LambdaのPythonで`import bigquery` を使用するために、SDKをレイヤーに追加します。
pipで取得してzipで固めます。
CloudShellが使えるようになったので、以下の赤枠のボタンからポチっと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/be3f7d8d-e6a4-71e7-e42a-190a712e75cf.png)

実行手順を記載します。<>の箇所は、自分の値を設定します。

```sh
# pipのインストール
curl -O https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py
```

ここ、CloudShellの初期設定そのままでpip install ...だとpipが見つからず・・
pip3 install ...とすると、うまくいきませんでした😭
ですので、pipをインストールしています。

```sh
# sdkのインストール&zip化
pip install google-cloud-bigquery -t ./python/
zip -r google-cloud-bigquery.zip python
# protobufが必要なため追加
pip install protobuf --upgrade -t ./python/
zip -r google-cloud-bigquery.zip ./python/google/protobuf
```
```sh
# s3に保存
aws s3 mb s3://<my-bucket>
aws s3 cp google-cloud-bigquery.zip s3://<my-bucket>
```

## 作成したライブラリをLambdaのレイヤーに登録する。
Lambdaに戻ります。

- レイヤーを作成します。
<img width="794" alt="スクリーンショット 2019-11-24 11.18.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/e0f7ab07-824d-f951-46e4-f4ca20ffb470.png">

ランタイムは、`Python 3.7`、`Python 3.8`を追加しました。

- 関数にレイヤーを追加します。
<img width="1165" alt="スクリーンショット 2019-11-24 11.11.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/0cf28b1a-a445-b77a-fa42-c2839c3190b2.png">

  - レイヤーを選択して、`レイヤーの追加`を押します。
   
    名前は、「お客様のレイヤー」から選択。バージョンは作成したものを選択。
<img width="629" alt="スクリーンショット 2019-11-24 11.22.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/204e7abe-fc34-7c62-b247-3523bd656f9a.png">

  - レイヤーが追加されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/3f8ae026-3377-c227-9e01-5923814d7ea0.png)

レイヤーを追加すれば、S3のファイルは削除してしまって大丈夫です。

## GCPの認証ファイルを取得する。
- 認証を追加する必要があります。

https://cloud.google.com/docs/authentication/production

- jsonのサービスアカウントキーを作成します。

    上記リンク中の`[サービス アカウントキーの作成] ページに移動`から。
    役割は「BigQuery管理者」を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/2bc55e0c-6da3-2421-e6ca-2604a3717dfa.png)

## GCPの認証ファイルを、Lambdaに登録する。
jsonは`New File`から、テキストをコピー＆ペーストで追加しました。
環境変数`GOOGLE_APPLICATION_CREDENTIALS`を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155165/2f4ac161-1436-2001-f6f2-b97f34ea77c3.png)

# テスト実行
Lambdaコンソールからテスト実行できました！

# つまった点
protobufが無いとエラーが出て困りました・・・
StackOverflowで事例を検索して解決しました。

# おわりに
いろいろこれでいいのかと思うところはありますが、実行出来たので掲載しました！

- SDKはpython直下に置くべきか、site-packagesに置くべきか。
Pythonのバージョンが固定されないよう、Python直下にしました。

- SDKの作り方はこれでよいのか。
zipに追加するところ

- GCPの認証ファイルはもっと隠せないのか。
環境変数、KMS、パラメータストアなどで。

- 2020.12.16
  - CloudShellで実行する記載にしました。動作確認しました。