ECS FargateのタスクからBigQueryへクエリを実行する

こんにちは、香田です。

今回はECS FargateのタスクからBigQueryへクエリを実行する方法について紹介していきます。

最終的にタスクで定義されたコンテナからbqコマンドでクエリ実行できるように設定していく流れとなります。

サービスアカウントキーの作成

はじめにECS FargateのタスクからBigQueryへクエリ実行できるようにする為、GCPにてサービスアカウントキーを作成します。

GCPの[IAMと管理]、[サービスアカウント]より[サービス アカウントの作成]を選択します。

[サービスアカウント名]を入力し作成をクリックします。

ここではロールに[BigQuery管理者]と[ストレージ管理者]を設定しています。

問題なければ[続行]、[完了]とクリックします。

作成したサービスアカウントを選択し、[キー]、[鍵を追加]、[新しい鍵を作成]より[JSON]を選択し作成します。

ダウンロードされたJSONファイルは以降の手順で使用します。

BigQuery テーブルの作成

次に検証用のBigQueryテーブルを作成します。

BigQueryの一般公開データセットより表のサイズが小さいbigquery-public-data:samples.shakespeareテーブルを自身のプロジェクトにコピーしテーブルを作成します。

検証用のデータセットを作成します。

bq mk samples

自身のプロジェクトにテーブルをコピーします。

bq cp \
bigquery-public-data:samples.shakespeare \
samples.shakespeare

ECS 環境の準備

ECS クラスターの作成とECS タスク定義で利用するCloudWatch Logs、パラメータストアを作成します。

ECS クラスターを作成します。

aws ecs create-cluster --cluster-name ecs-cluster

ECS タスク用のCloudWatch Logs ロググループを作成します。

aws logs create-log-group --log-group-name ecs-fargate-bigquery

ECS タスクよりBigQueryを参照できるように、認証情報の保存先としてパラメータストアを利用していきます。

ダウンロードしたサービスアカウントキーをbase64で文字列にしSecureString形式でパラメータストアへ保存します。

aws ssm put-parameter \
--name "/gcp/ecs-fargate-bigquery" \
--type "SecureString" \
--value $(base64 <サービスアカウトキー ファイルパス>)

IAM ロールの作成

次にタスク実行 IAM ロールを作成します。

ECSタスクにてコンテナイメージ取得、CloudWatch Logsへログ保存等を許可する為に利用されるIAM Roleになります。

AWS IAM コンソールより[ロールの作成]を選択し、[信頼されたエンティティの種類を選択] セクションで、[Elastic Container Service] を選択します。

[ユースケースの選択]で、[Elastic Container Service Task]を選択し、[次のステップ: アクセス権限]を選択します。

[Attach アクセス権限ポリシー]に[AmazonECSTaskExecutionRolePolicy]を選択し、[次にステップ:タグ]、[次のステップ:確認]と選択します。

[ロール名]にecsTaskExecutionRoleと入力し[ロールの作成]をクリックします。

次にパラメータストアを参照できるようにインラインポリシーを追加します。

作成したロールを選択し[インラインポリシーの追加]より、パラメータストアを参照できるよう下記のようなポリシーを作成し付与します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:GetParameters"
            ],
            "Resource": [
                "arn:aws:ssm:<リージョン>:<アカウントID>:parameter/gcp/ecs-fargate-bigquery"
            ]
        }
    ]
}

Dockerfileの作成

BigQueryへクエリ実行する為にサンプルスクリプトを用意します。

bq_query.sh という名前でファイルを作成します。

スクリプトで参照しているGCP_SERVICE_ACCOUNTGCP_PROJECT_IDはECS タスク定義によって環境変数として取得可能となります。

#!/usr/bin/env bash
echo ${GCP_SERVICE_ACCOUNT} | base64 -d >/tmp/service-accounts.json
gcloud auth activate-service-account --key-file=/tmp/service-accounts.json
gcloud --quiet config set project ${GCP_PROJECT_ID}

bq query \
--nouse_legacy_sql \
'SELECT * FROM `samples.shakespeare` LIMIT 10'

作成したスクリプトを実行できるようにcloud-sdkのイメージを元にDockerfileを作成します。

FROM google/cloud-sdk:latest

ENV APP_HOME /app
WORKDIR $APP_HOME
COPY ./bq_query.sh ./

ECRへイメージ登録

次にイメージをビルドしECRへ登録していきます。

ECRへログインします。

export ECR_URI_BASE=$(aws sts get-caller-identity --query Account --output text).dkr.ecr.ap-northeast-1.amazonaws.com

aws ecr get-login-password | docker login --username AWS \
--password-stdin $ECR_URI_BASE

ECR リポジトリを作成します。

aws ecr create-repository --repository-name ecs-fargate-bigquery \
--image-tag-mutability IMMUTABLE

イメージをビルドし、ECR リポジトリへ登録します。

docker build -t ecs-fargate-bigquery:latest .
docker tag ecs-fargate-bigquery:latest $ECR_URI_BASE/ecs-fargate-bigquery:latest
docker push $ECR_URI_BASE/ecs-fargate-bigquery:latest

ECS タスク定義の登録

次にECS タスク定義を作成します。

下記をコピーしecs-fargate-bigquery.jsonという名前で保存します。

タスク定義で指定されているimageAWS アカウントIDenvironmentGCP プロジェクトIDの箇所は適宜修正してください。

{
    "family": "ecs-fargate-bigquery",
    "executionRoleArn": "ecsTaskExecutionRole",
    "networkMode": "awsvpc",
    "containerDefinitions": [
        {
            "name": "ecs-fargate-bigquery",
            "environment": [
                {
                    "name": "GCP_PROJECT_ID",
                    "value": "<GCP プロジェクトID>"
                }
            ],
            "secrets": [
                {
                    "name": "GCP_SERVICE_ACCOUNT",
                    "valueFrom": "/gcp/ecs-fargate-bigquery"
                }
            ],
            "image": "<AWS アカウトID>.dkr.ecr.ap-northeast-1.amazonaws.com/ecs-fargate-bigquery:latest",
            "linuxParameters": {
                "initProcessEnabled": true
            },
            "command": [
                "bash",
                "bq_query.sh"
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "ecs-fargate-bigquery",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "bq_query"
                }
            },
            "essential": true
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512"
}

ECS タスク定義を登録します。

aws ecs register-task-definition \
--cli-input-json file://$PWD/ecs-fargate-bigquery.json

ECS タスク実行

登録したタスク定義を利用しタスクを実行していきます。

起動タイプとしてFARGATEを指定し、ECS タスクを実行します。

awsvpcConfigurationsubnetssecurigyGroupsは適宜設定してください。

デフォルトで作成されているVPCのサブネットとセキュリティグループを利用しても問題なく実行できるはずです。

aws ecs run-task --cluster ecs-cluster \
--task-definition ecs-fargate-bigquery:1 --count 1 \
--launch-type FARGATE \
--network-configuration \
"awsvpcConfiguration={subnets=[subnet-xxx,subnet-xxx,subnet-xxx],securityGroups=[sg-xxx],assignPublicIp=ENABLED}"

タスク実行後、CloudWatch Logsのログを確認しBigQueryのクエリ実行結果が確認できれば成功です。

aws logs tail --follow ecs-fargate-bigquery

さいごに

ECS FargateのタスクからBigQueryへクエリを実行する方法いかがでしたしょうか?

AWS環境からGCPのBigQueryへデータをロードしたり、クエリ実行するといったケースはよくあると思います。

ECS FargateのコンテナにてBigQueryを利用する際、本記事が参考になれば幸いでございます。

最後までご覧いただきありがとうございます。

SNSでもご購読できます。