astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

KeycloakとKeycloak Gatekeeperを用いてWordPressにログイン画面を作成する

初めまして、7月にAstamuseにjoinしました、植木です。
ICPのエンジニアを担当しております。
私は、普段なら桜が咲いて楽しみが増える季節ですが、コロナの影響もあり外出を控えないといけないと思うと残念で仕方がない今日この頃でございます。

はじめに

今回は、Keycloakについて紹介する記事です。 https://www.keycloak.org/resources/images/keycloak_logo_480x108.png
弊社のICPで導入に向けて作業を進めており、非常に便利でしたので筆をとるに至りました! 下記のような方は是非見ていただいて、参考にしていただけると幸いです。

  • Keycloakを知らない方
  • ざっくり概要を知りたい方
  • 導入を検討する方

概要

Keycloakとは、 OpenID / SAML の認証方式を用いて、「認証」「認可」を行うことができるOSS のミドルウェアです。 安全性をKeycloakが管理を担ってくれるため、アプリケーションはユーザーアクセス管理を意識することから解放され、余計な処理が不要になるため、コードがシンプルになります。 その他、シングルサインオン(1アカウントで複数のアプリケーションへのログイン)、ソーシャルログイン(FacebookやGoogle+などの、外部のIdPを使用してのログイン)にも対応しており、既存のアプリケーションにも容易に導入できます。

ICPで導入に至った経緯

機能開発や新規のプランごとに、ユーザや所属する組織に対する権限情報が増え行くことは、火を見るよりも明らかであると言えるでしょう。 例えば、API開発であれば、一般ユーザーAさんがアクセスできるエンドポイントは参照権限のみで、管理者ユーザーのBさんは参照加えて、作成/更新/削除も可能にする、といったような仕様を常に心に止めて開発する必要があります。
ICPでも同じ悩みを抱えており、1. (既存もしくは新規に)認証/認可サーバを作成する, 2. 認証/認可ミドルウェアを使用することを検討し、結論としては2を選択しました。
1に関してはSilhouette(シルエットと読みます)というライブラリを検討し、見送りました。理由は、SilhouetteはPlay Frameworkをベースとしており、リクエストが届いた際にエントリポイント単位で、認証ロジックを挟むといった形になっているため、Play Framework以外での実装となっているアプリケーションは対応できなかったためです。

起動方法

まずはローカル環境で試したいという方には、jboss/keycloakのdockerを用いて起動するが手軽でおすすめです。後の解説ではこれを使用します

# 例:最初の管理者ユーザを id=admin, password=adminで作成する場合。今回は8888ポートにしました。
$ docker run --rm --name keycloak -p 8888:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak

直接サーバで動作させる場合は、tarボールをダウンロードしてきて、./standalone.sh を実行します。 Keycloak - Downloads

Keycloakの管理ページ、設定項目について

http://localhost:8888/にアクセスすると、KeycloakのWelcomeページをはじめに確認できます。

KeycloakのWelcomeページ画像
KeycloakのWelcomeページ
「Administration Console」から、管理者ユーザでログイン(今回の例ではadmin/admin)すると管理者用ページが現れ、下記のようなメニューがあることが確認できます。
Keycloakの管理者用ページ画像
Keycloakの管理者用ページ

  • 1. Realm Settings
    Realmというのはプロジェクトのワークスペースのようなものです。Masterというのがはじめに作成されています。ユーザのログイン方法やテーマのなどの設定ができます

  • 2. Clients
    Keycloakへアクセスするクライアント(アプリケーション)の設定を行います。

  • 3. Roles
    権限の名前がRoleになります。このMapping(RoleとGroups/Usersを組み合わせる)設定することで、権限制御ができます RealmにおけるRoleを設定できます。先ほどの2.ClientsでもRole設定があり、スコープが少し違います

  • 4. Groups
    ユーザーをひとまとまりにする単位です

  • 5. Users
    ユーザーの管理を行います

アプリケーション(Clients)の管理方法

Keycloakがアプリケーションの管理する方法として、大きく分類して2つの方法があります。
アプリケーションにKeycloak用のライブラリを組み込むクライアントアダプターパターンと、
Keycloak Gatekeeperを使用するクライアントプロキシパターンがあります。
クライアントアダプターパターンの、詳しい設定内容についてはこちらがわかりやすいです。 www.atmarkit.co.jp クライアントプロキシパターンには、リバースプロキシ(Apache、Nginx)にOpenID Connectのモジュールを組み込む方法もあります Keycloakで実用的なリバースプロキシ型構成を構築してみよう (1/4):Keycloak超入門(7) - @ITwww.atmarkit.co.jp

ICPでは、

  • クライアントアダプターの場合は、対応されていないアダブターを自作する必要があることがわかったため(ICPの場合は、Play Framework用)
  • クライアントプロキシパターン(Nginx)の場合は、Nginx Plus(有償)である必要がある
  • クライアントプロキシパターン(Apache)の場合は、NginxからApacheへの切り替えコストがかかる といった理由から、Keycloak Gatekeeperを選びました。Keycloak Gatekeeperはマイクロサービスを意識してシングルバイナリで動作し、Dockerコンテナ内で動かすことも想定して設計されていると感じており、期待の意味も込めて、クライアントプロキシ(Keycloak Gatekeeper)を選択しました。

この記事では、以降、Keycloak Gatekeeperを中心に書いていきます。

Keycloak Gatekeeperを用いてクライアントプロキシを試してみよう

Keycloakを用いる場合ユーザーはKeycloakで用意しているのログインページを使用するようになります。
Keycloak Gatekeeperのバックエンドにアプリケーションが配置されるようにし、認証/認可を判断したものだけがアプリケーションへ到達できるようなハンズオンをやってみましょう。
下記に、ハンズオンのために必要最低限の設定を書いたdocker-composeを用意しました。Mac OSでのみで動作します(Docker for Mac向けのhost.docker.internalを使用しているため)
github.com 下記を打つとWordPress、Keycloak、Keycloak Gatekeeperが起動します。 ※ 今回はWordPressへ到達までが目的なので、DBの設定などは入れていません

$ docker-compose up

f:id:astamuse:20200326165148p:plain
docker-compose後の起動イメージ

WordPressは読者の認証認可を想定するアプリケーションに読み替えていただけるとわかりやすいと思います

次に、テストユーザを追加しましょう

ユーザ追加ページ画像
ユーザ追加ページ
パスワードの初期値を適当に決め、設定します。
テストのためパスワードリセット画像
テストのためパスワードリセット

設定ができたら、Keycloak Gatekeeperのアドレスhttp://localhost:3000/へアクセスしてみましょう。初回なので、ログインページへリダイレクトされることが確認できます。

Keycloakのログインページ画像
Keycloakのログインページ
先ほど登録したユーザでログインしてみると、OIDC認証されWordPressのページ http://host.docker.internal:8880/ へリダイレクトされてきたことが確認できたと思います。
このような手軽さから、既存のアプリケーションに対して使用する場合でも、プロキシパスをKeycloak Gatekeeper経由に変更さえすれば、認証を担ってくれることがメリットと言えます。
リダイレクトされWordPressへ到達した様子の画像
リダイレクトされWordPressへ到達した様子

テーマについて

今回試したログインの際、テーマはKeycloakのデフォルトでしたが、Freemakerで作成したテーマを配置すれば、切り替えが可能です。
テーマはログインテーマだけでなく、アカウント管理、管理コンソール、電子メール、ウェルカムページのカスタマイズが可能です
新規に配置する際にはすぐに反映されるのですが、更新の場合はデフォルトでテーマファイルのキャッシュが効いているため、注意が必要です。
テーマに関しては、下記が参考になりました。 keycloak-documentation.openstandia.jp qiita.com

認証後の付与情報について

Keycloak Gatekeeperを通過しアプリケーションへ向かう際に、X-Auth系のヘッダが付与されるため、アプリケーションレベルでユーザを扱うことができるようにするため、Username(ログイン時のID), Email, 姓名などKeycloakで設定したユーザ情報が送られるようになっています。
また、上記以外にも、独自で定義したフィールドに値を詰めて渡すといったこともできるため自由度は高いと言えるでしょう。

最後に

ここまで読んでみていかがでしたでしょうか?
Keycloakは多機能で、今回紹介できた部分はほんの一握りでしたが、ざっくり分かっていただけていたら幸いです。 弊社では上記のように OSS を使って問題解決が開発がしたいエンジニアや、デザイナー、プロダクトマネージャーなど絶賛大募集中です。少しでもご興味を持っていただけたら、お気軽にカジュアルランチからでも構いませんので、下のバナーや @yoshixmk へ DM 等でご連絡いただければと思います。

企業ロゴの「ロゴパネル」の作り方

f:id:astamuse:20200324153227j:plain

こんにちは。デザイン部の橋本です。

アスタミューゼでは事業規模が大きくなるにつれて、取材をしていただく機会やEXPOなどのイベントに出展する機会が増え、それに伴って広報活動も活発になってきたので企業ロゴのロゴパネルを作ることになりました。

ロゴパネルとは企業ロゴを大きくパネル化したもので、写真撮影の時に手に持って撮影するだけで、企業ロゴの認知度を上げることができるものです。

f:id:astamuse:20200319170731j:plain
完成したアスタミューゼのロゴパネル

使わない時はオブジェとして置いておくだけで、なんだかちゃんとした会社っぽい雰囲気を出してくれます!

しかもデータを作成・入稿するだけでお値段は一枚数千円からとコスパも良好。今回はそんなロゴパネルの作り方についてのお話しです。

ロゴパネルの作り方

1. 印刷業者を決める

まず、ロゴパネルをどこに発注するのか決めます。完成したパネルを思い浮かべて、要件を固めましょう。 パネルが折れないように厚みが欲しい、表面をマット加工にしたい、サイズはだいたいこれくらい…など、使用目的に合わせてなんとなくで大丈夫です。

アスタミューゼのロゴは横長なので、大きめのA1サイズで作成することに決定。(※他の企業さんを調べてみるとA2サイズで作成することが多いみたいでした。)

ある程度厚みが欲しかったのと、表面をマット加工にしたかったので、いくつか業者さんを比較して、今回はアクセアさんに発注することにしました。

アクセアさんの場合、厚さは5mmと7mmから選択できるので、7mmに決定。両面貼りも可能でしたが、片面貼りで問題ないので、片面貼りにするところまでこの時点で決めてしまいました。

2. Illustratorでデータを作る

ではデータを作成していきましょう。

ロゴの周りを囲むように、切り取り線(カットパス)を作ります。この線に沿ってパネルが切り出されるので、ロゴから適度な余白を取ることと、線がガタつかないように気をつけて作っていきます。

  1. Illustratorを起動してA1サイズ(841×594mm)のアートボードに、アスタミューゼのロゴデータを置く
  2. オブジェクト>パス>パスのオフセット で余白部分を作成
  3. パスファインダーで合体して パスの背景→白、パスの線→黒 にする
  4. オブジェクト>パス>単純化 で不要なアンカーポイントを削除

f:id:astamuse:20200324163107j:plain
1. アスタミューゼのロゴデータ(760×113mm)を置く

パスのオフセットは20mm〜40mmを目安に調整すると良いと思います。アスタミューゼはフォントが細めなので、それに合わせて余白も少なめの22mmにしました。

f:id:astamuse:20200324161706j:plain
2. オブジェクト>パス>パスのオフセット で余白部分を作成

f:id:astamuse:20200324164038j:plain
3. パスファインダーで合体して背景と線の色を変更

f:id:astamuse:20200324164600j:plain
4. パスの単純化でアンカーポイントを削減

単純化した後は多少パスがガタついたり、取り除ききれなかった不要なアンカーポイントが残っていたりすると思いますので、パスの調整を行います。このパスを綺麗にする作業くらいしか正直やることがないので、データ作成は本当にあっという間です。

パネルを発注する前に、出来上がったデータを等倍で印刷して、サンプルを作ってみます。

f:id:astamuse:20200324111511j:plain
等倍印刷したロゴ

切り取り線に沿ってハサミを入れて、セロハンテープでくっつけて……できました!

f:id:astamuse:20200324104104j:plain
ロゴパネルのサンプル

良い感じです。気になったところを微調整した後、いよいよデータ入稿です。

3. データを入稿する

ではデータを入稿していきましょう。

アクセアさんのWEB入稿を使うので、アクセアさんのアカウントがない場合は作成してください。 アカウントを作成したら、新規データ入稿よりデータを入稿していきます。

2020年3月現在、アクセアさんのデータ入稿の流れは5ステップです。

  1. 注文内容入力
  2. 配送先入力・支払方法選択
  3. ファイルアップロード
  4. 注文内容確認
  5. 注文完了

1.の注文内容入力では、入稿タイトルと印刷内容を聞かれます。 今回は入稿タイトルをアスタミューゼロゴパネルとし、印刷内容を下記のようにしました。

項目 印刷内容
仕様 切り抜きパネル
用紙 ポスター部分:フォト半光沢紙、パネル:発泡ポリスチレン(厚さ7mm)
加工 切り抜き加工あり
個数 1
サイズ A1(841×594mm)
その他ご要望 ラミネート(マット)加工のオプション付き

あとは配送先と支払い方法を指定し、データをアップロードして完了です。

そしてデータを入稿して数日後、ロゴパネルが社内に届きました。とってもスピーディーな対応で大満足です!

今回発注したロゴパネルの料金は9,460円(税込)でした。店舗に受け取りに行くとあと1000円ほどお安くなるみたいです。

ロゴパネルを作成するくらい事業規模拡大中のアスタミューゼでは、一緒に働いてくれる仲間を募集しています。 採用サイトもありますので、是非ご覧ください!

初めてBigQueryを触って学んだ節約トピックを紹介するよ

みなさんこんにちは。たぶんアプリケーションエンジニアのkjです。

私にはもうすぐ1歳半になる娘がおりまして、リモート勤務の傍ら、ホンヨンデー!って訴えてきます。 その表情、振る舞いが愛おしく(親バカ)、スキマ時間をとって本を読んでいます。

ちなみに、娘の最近のお気に入りはハッピーセットのオマケでついてきた「小学館の図鑑 危険生物」

f:id:astamuse:20200315225806p:plain
お気に入りの本は「小学館の図鑑NEO 危険生物」一度手にとったら、もう離さないよ!

こちら、世界の様々な人食いザメや凶暴なピラニアなどが掲載され、海にはアブナイ生き物がいるよ!気をつけてね!と紹介されているダイジェスト本です。

自分の娘ながら嗜好が理解できません。。。

閑話休題

突然ですが、BigQueryって便利ですよね!最近は業務でbqコマンドをよく使っています。bqコマンドとは、ざっくりというと、Google社が提供しているCloudSDKに内包されている、BigQueryのデータを操作するためのコマンドです。コマンドの裏側ではPythonが動いており、GoogleCloudのAPIを叩いています。

ちなみに私、前職はコテコテのJavaエンジニアで、システムはオンプレやろ!って世界に住んでおました。 「くらうど??ナニソレ オイシイノ?」ってところから、都度都度調べながらBigQueryを触っております。 今回は、自分の理解の整理がてら、bqコマンド(+ときどきBigQuery)について、トピックをご紹介したいと思います。

本日のポイント

本日触れないこと

  • BigQuery, GCPとはなにか
  • bqコマンドのインストール方法について。こちらは公式サイトを参照してね!

その他注意書き

  • 以下、bqコマンドでこんなことできるぞ!とドヤりますが、実はBigQueryのWebコンソールにて特殊な操作することなく表示されるものが多いです。

    ですので、BigQueryにこなれている方は、コマンドでもできるんだフーンとしていただければ。まぁでも、コマンドでできた方がいろんなツールと連携しやすいので、知っておいて損はないよね!

  • 2020年3月時点での内容になりますので、将来変わる可能性もあります。
  • GoogleCloud Japanのブログにて弊社が紹介されております。むしろそちらをご覧ください。

    cloud.google.com

BigQueryの料金について把握する

さて、はじめてBigQueryを触るにあたって、まず気になったのが料金です。ネットにはクラウドサービスでウン万円溶かしたって記事は事欠きません。ちなみに私、しらないお店はお金にビビって入れないタイプです。

なので、どういう時に課金される、されない、もしくはどれくらい課金されるか、を調べました。 結論、扱うデータサイズによりますが、よっぽどな操作をしない限りは大丈夫かと思っています。 2020年3月時点でざっと把握したカンジは以下となります。(なお、正確な情報は公式サイトをご参照ください)

課金タイプは2種類

BigQueryの課金パターンとして以下2つとなります。カッコ内の金額は参照値。実際は操作内容やリージョン、契約内容、無料枠などによって変わってきます

  • 保存しているデータ量に応じて課金(月に$0.020/GB @ US multi-region)
  • クエリを実行した際に読み込んだデータ量に応じて課金($5.00/TB @ US multi-region)

    ただし、読み込んだ1テーブルあたり最小サイズは10MBで、以降1MB単位(端数は四捨五入)で課金。つまり1テーブル読み込むごとに10MBが課金対象となる

なお、BigQueryでは内容によってはクエリ無料のものがあります。全部あげるとキリがないですが、私がよく使う無料枠のものは以下のようなものになります。(以下、保存データに関する課金は考慮していません)

  • bq ls, bq show などのデータを直接参照しない閲覧コマンド
  • bq head, bq cp によるフィルタリングや加工を伴わない照会コマンド。(コピーは照会とは違うけど、readしても課金されないよ!という意味でここに)
  • bq mk, bq rm などのテーブル作成、および削除。

    bq queryで実行するCREATE (OR REPLACE) TABLE, DROP TABLEなども、テーブルをSELECTしていなければ課金されないよ!

一方で有料となるクエリは以下のようなものがあります。詳細は以降で一部紹介します。

  • bq query にてテーブルをSELECTするもの
  • bq query にて、「INSERT INTO 〜〜 SELECT 〜 FROM 〜〜」のようにテーブルSELECTしてレコード挿入するもの
  • bq query にて、「UPDATE SET 〜〜」や「DELETE 〜〜」するもの。

bqコマンドを色々触ってみる

さてここまでウンチクを記載してましたが、実際のデータを参照しながらbqコマンドを触ってみたいと思います。

プロジェクトの作成、CloudSDKのインストール

詳細の手順は公式サイトをご参照ください。 なお公式サイトでは、サンプルデータセットを利用したクイックスタートも載っています。GCPの1年間の無料クレジットがある方はこちらを試すのもありかと思います。

また、以降のクエリはStandardSQLを前提にしています。bqコマンドの設定方法は以下をご確認ください。 cloud.google.com

bqコマンドのヘルプをみてみる

bqコマンドにはヘルプが用意されています。とりあえずbqだけ打ってみると(ただし、CloudSDKインストール後、初めて実行する場合はアカウントの設定等、諸々初期設定が行われる場合があります)

$ bq
Python script for interacting with BigQuery.
USAGE: bq.py [--global_flags] <command> [--command_flags] [args]

Any of the following commands:
  cancel, cp, extract, get-iam-policy, head, help, init, insert, load, ls, mk, mkdef, partition, query, rm, set-iam-policy, shell, show, update, version, wait

cancel          Request a cancel and waits for the job to be cancelled.

# (以下省略)

という風に、bqで指定できるサブコマンドとその概要が表示されます。ちなみに上記出力の最後に以下のような表示があるはずです。

Run 'bq.py --help' to get help for global flags.
Run 'bq.py help <command>' to get help for <command>.

試しにbq --helpを打ってみると、

$ bq --help
Python script for interacting with BigQuery.
USAGE: bq.py [--global_flags] <command> [--command_flags] [args]

Global flags:

/<PATH TO SCRIPT>/bq.py:
  --api: API endpoint to talk to.
    (default: 'https://www.googleapis.com')
  --api_version: API version to use.

# (以下省略)

という風に、違う内容が表示されました。(ちなみにbq helpを打つとbqと同じ結果が表示されます)

つまり、bqコマンドには大きく2種類のヘルプがあります。bqの後に続けるサブコマンドに関するヘルプと、bqコマンドのフラグに関するヘルプです。 前者についてはWebドキュメントにも詳細が記載されているので利用する機会は少ないのですが、フラグについてはWebドキュメントに記載されていないものもあり、中には便利なものがあります。是非見てみてください。

動作環境

$ sw_vers
ProductName:  Mac OS X
ProductVersion: 10.15.3
BuildVersion: 19D76

$ bq version
This is BigQuery CLI 2.0.54

今回扱う確認用データセットの作成

まずはデータセットを作成して、検証用のデータを登録します。

$ bq query <<-EOF
> CREATE TABLE test_kj.sample
> AS
>     SELECT 1 AS id, 'a' AS key1, 'aa' AS key2, 'aaaa' AS key3, 'aaaaaaaa' AS key4
> UNION ALL
>     SELECT 2 AS id, 'b' AS key1, 'bb' AS key2, 'bbbb' AS key3, 'bbbbbbbb' AS key4
> UNION ALL
>     SELECT 3 AS id, 'c' AS key1, 'cc' AS key2, 'cccc' AS key3, 'cccccccc' AS key4
> UNION ALL
>     SELECT 4 AS id, 'd' AS key1, 'dd' AS key2, 'dddd' AS key3, 'dddddddd' AS key4
> EOF
Waiting on bqjob_r1367xxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1 ... (0s) Current status: DONE
Created 【Project Name】.test_kj.sample

ちなみに「Waiting on」の後に表示されている文字列(上記のbqjob_r1367xxxx....)が、そのクエリを実行しているジョブIDになります。ジョブIDは後でその処理を照会する場合に利用します。

データの照会

テーブルの確認、データの確認にはそれぞれbq show, bq headを利用します。

$ bq show test_kj.sample
Table 【Project Name】:test_kj.sample

   Last modified        Schema        Total Rows   Total Bytes   Expiration   Time Partitioning   Clustered Fields   Labels
 ----------------- ----------------- ------------ ------------- ------------ ------------------- ------------------ --------
  14 Mar 17:58:23   |- id: integer    4            124
                    |- key1: string
                    |- key2: string
                    |- key3: string
                    |- key4: string

$ bq head test_kj.sample
+----+------+------+------+----------+
| id | key1 | key2 | key3 |   key4   |
+----+------+------+------+----------+
|  3 | c    | cc   | cccc | cccccccc |
|  1 | a    | aa   | aaaa | aaaaaaaa |
|  2 | b    | bb   | bbbb | bbbbbbbb |
|  4 | d    | dd   | dddd | dddddddd |
+----+------+------+------+----------+

なお、bq headでデータを読み込んだ場合は課金されませんが、bq queryでテーブルを読み込んだ場合は課金対象となります。--dry_runオプションをつければ、クエリを実行することなく、実行した場合に何byte読み込むかを確認できます(下記の例では124byte)。

$ bq query --dry_run "SELECT * FROM test_kj.sample"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 124 bytes of data.

--dry_runオプションをつけ忘れた場合、後で読み込んだbyte数を確認するには、ジョブIDがわかっていればbq show -j <ジョブID>で確認できます。

$ bq show -j bqjob_r1367xxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1
Job 【Project Name】:bqjob_r1367xxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1

  Job Type    State      Start Time         Duration                      User Email                    Bytes Processed   Bytes Billed   Billing Tier   Labels
 ---------- --------- ----------------- ---------------- --------------------------------------------- ----------------- -------------- -------------- --------
  query      SUCCESS   14 Mar 17:57:16   0:00:00.927000   account@【Project Name】.iam.gserviceaccount.com   0                 0              1

Created 【Project Name】.test_kj.sample

上記はsampleテーブルを作成した際のジョブIDを指定したものです。今回のCREATE TABLEの場合は「Bytes Processed」、「Bytes Billed」が0であることが確認できます。(「Billing Tier」は、過去は利用されていたけど現時点では課金に利用されていない項目のようです)

bq head で使える表示オプション

bq headコマンドの表示結果はテーブル形式で人にとっては見やすいですが、コマンドで連携したり、ファイルに出力する場合には扱いづらいです。この場合はbqコマンドのオプションである--formatを利用できます。 例えば、CSV形式にする場合は以下のように--format=csvを指定します。

$ bq head --format=csv test_kj.sample
id,key1,key2,key3,key4
3,c,cc,cccc,cccccccc
1,a,aa,aaaa,aaaaaaaa
2,b,bb,bbbb,bbbbbbbb
4,d,dd,dddd,dddddddd

json形式も指定できます。改行やインデントがない--format=jsonの他、人に見やすくインデントされた--format=prettyjsonもあります。 たとえば、

$ bq head test_kj.sampleo_long
+----------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+
|                                            value1                                            |                                         value2                                          |
+----------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+
| toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo LONG!! | sample2                                                                                 |
| sample1                                                                                      | toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long! |
+----------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------+

テーブル形式の場合、1レコードのある値が長いと、その値で1列の幅が調整されてしまい見づらいですが、

$ bq head --format=prettyjson test_kj.sampleo_long
[
  {
    "value1": "toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo LONG!!",
    "value2": "sample2"
  },
  {
    "value1": "sample1",
    "value2": "toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo long!"
  }
]

インデントしたjson形式なら多少は見やすくなります。

その他bqのオプションとして、デフォルト表示件数100件を変更できる-n <表示件数>オプション 1 があります。またbq headのオプションとしては、表示する列を指定できる-c <カラム1>,<カラム2>,...オプション、表示開始のレコード位置を指定できる-s <表示開始インデックス>オプション(-s 0とすれば、1行目から表示される)があります。 --formatオプションとこれらを組み合わせれば、テーブルをちらっと閲覧したいケースは大方カバーできるかと思います。

SELECT文に関するトピック

ここまでbq headを推してきましたが、SELECT文を使ってレコードをフィルタしたり、値の変換等、諸々操作したい場合もあるかと思います。 SELECTするにあたって、表示する列を限定することで課金額を節約できます。

たとえば、以下のように、とりあえずSELECT *すると、、、

$ bq query --dry_run "SELECT * FROM test_kj.sample"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 124 bytes of data.

全ての列の全データが課金対象になります。

なお計算式は以下の通り。データ型によるサイズは BigQuery の料金  |  Google Cloud を参照。

id=1のレコードについて、

  • id列はinteger型なので、8 byte
  • key1列はstring型の'a'なので、2 + 1 = 3 byte
  • key2列はstring型の'aa'なので、 2 + 2 = 4 byte
  • key3列はstring型の'aaaa'なので、 2 + 4 = 6 byte
  • key4列はstring型の'aaaaaaaa'なので、 2 + 8 = 10 byte

id=1のレコードの読み込んだbyte数は 8 + 3 + 4 + 6 + 10 = 31 byte

id=2,3,4も同様に計算して、全4レコードを読み込んだbyte数は 31 + 31 + 31 + 31 = 124 byte

ところが、実際に閲覧したい列はidとkey1のみだったとすると、この2つの列に絞ってSELECTすることで、

$ bq query --dry_run "SELECT id, key1 FROM test_kj.sample"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 44 bytes of data.

となり、元のクエリと比べて読み込みサイズが3分の1になりました! この場合は (id列の 8 byte + key1列の 3 byte) * 4 レコード = 44 byte

まぁこの例の場合だと大したサイズではないので有り難みは全くないのですが、何百万、何千万件と扱うデータサイズが大きくなるとじわじわと懐に響いてきます。

あと、公式ドキュメントにも記載されていますが、WHEREやLIMITによるレコードの絞り込みは課金に影響しません。

$ bq query --dry_run "SELECT id, key1 FROM test_kj.sample WHERE id = 1"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 44 bytes of data.

$ bq query --dry_run "SELECT id, key1 FROM test_kj.sample LIMIT 1"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 44 bytes of data.

ただ、私個人的な体感ですが、LIMITで表示件数を絞るとクエリの応答速度が速くなるようです。 特にbqコマンドのデフォルト表示件数は100件ですが、LIMIT 100があると応答速度が速くっているカンジがします。(もちろん、クエリ結果の件数が多い場合です) なので、結果件数が多い場合は、bqコマンドの-nオプションと合わせてLIMITの数を合わせるとよいでしょう。

ちなみに余談ですが、SELECT COUNT(*)SELECT COUNT(1)はSELECT文ですが、課金されません。

$ bq query --dry_run "SELECT COUNT(*) FROM test_kj.sample"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 0 bytes of data.

$ bq query --dry_run "SELECT COUNT(1) FROM test_kj.sample"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 0 bytes of data.

テーブルのレコード件数は、課金されないbq showで確認できるから、ですかね。中々粋なことをしてくれます。

しかし、列を指定すると課金されます。

$ bq query --dry_run "SELECT COUNT(id) FROM test_kj.sample"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 32 bytes of data.

こっちはCOUNT(DISTINCT <列名>)とすると、単純なレコード数ではなくなるから、ですかね??

あるテーブルの全レコードを削除するぞ。もちろん課金なしで

ちょっと長くなってきました。ここからはちょっとした小ネタを紹介します。

テーブルの全レコードを削除する場合、普通のDBと同じ感覚でDELETE FROMを実行すると、、、

$ bq query --dry_run "DELETE FROM test_kj.sample"
Error in query string: DELETE must have a WHERE clause at [1:1]

という風に、DELETE文を実行する場合はWHERE句が必須だよ!と怒られます。仕方ないのでトートロジーな条件を入れてあげると、、、

$ bq query --dry_run "DELETE FROM test_kj.sample WHERE TRUE"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 124 bytes of data.

てカンジで、全レコードのサイズが課金対象になります。

$ bq query --dry_run "DROP TABLE test_kj.sample"
Query successfully validated. Assuming the tables are not modified,
 running this query will process 0 bytes of data.

テーブルそのものを削除する場合は課金されないのに、全レコード削除は課金対象なんかい!と。世知辛い世の中ですね。

ところで、我々はテーブルの削除と作成は課金されないことを知っています。ならば、これを上手く活用する方法はないか?と。

結論、あります。 jqコマンド 2 を利用すれば楽にできるので、それを紹介します。 なお、jqコマンドの説明は省略しますが、一言でいうとJSONフォーマットをよしなに扱えるコマンドです。詳細はぐぐってください。(だんだんテキトーになってきたな)

$ bq show --format=json test_kj.sample | jq .schema.fields > table_schema_sample.json
$ bq rm -f test_kj.sample
$ bq mk --schema table_schema_sample.json test_kj.sample
Table '【Project Name】:test_kj.sample' successfully created.

1つ目のbq show ... | jq ...にて、テーブルのスキーマに関するjson表記を取得して、それをリダイレクトしてファイルに保存しています。ここでbqコマンドに--forma=jsonオプションを指定しているのがポイントです。こうすることで、jqコマンドで必要な情報のみフィルタできます。 2つ目のbq rmで全レコードを削除したいテーブルを削除しています。 3つ目のbq mkにて、テーブルスキーマを記載したjsonファイルを指定して空テーブルを作成しています。

これにより、課金なしで全レコードを削除することを実現しています。ちなみにNOT NULL制約はスキーマの定義に記載されるので、テーブル作成した際にも再現できます。パーティション等については未確認なのであしからず。。。

まぁそもそも全レコードを削除する、というユースケースが実際あるのか?と。ここでは疑問に思ってはいけません。

間違えてクエリを発行してしまった!中断や!

bq queryをよく叩く方にはあるあるかと思いますが、実際は実行したくなかったのに--dry_runオプションをつけ忘れてしまい、クエリが走りだします。 コンソール上にRunningのメッセージが表示されるので、慌ててCTRL + Cで止めて「危なかったー!ヒヤリハットやったわ!」ってなりますよね??

いえ、それアウトですから。

実際はコンソールにRunningが表示された時点で、手元のマシンでCTRL + Cで止めたとしても、GCPにクエリの要求が届いておりクエリは処理されたままになります。 GCP側のクエリそのものを中断するにはbq cancel <ジョブID>を打ってあげる必要があります。

ちなみに、ジョブをキャンセルしても課金される可能性があります。それでもキャンセルを実行するのは、GCPを安く利用させてもらっている分、不要なマシンリソースを解放する心遣いですね。

その他

BigQueryにあまり慣れてない時によく参照したドキュメントはこちらです。

cloud.google.com cloud.google.com

あとは、上記のドキュメントから左側の目次から気になったのをピックアップすれば、色々と知れるのでおすすめです。

さいごに

ここまで、bqコマンドに触って知ったウンチクを色々記載しましたが、みなさんの参考になるものがあれば幸いです。


  1. bqコマンドの結果の件数が思ったより少ないときは、このデフォルト100件に引っかかっている場合が多いです。例えば、bq ls <データセット名> でテーブル一覧を出力したり、bq query "SELECT 〜〜"でレコードを出力した時に100件しか表示されていない場合は、-n <表示件数>オプションを設定してみてください。

  2. https://stedolan.github.io/jq/

Copyright © astamuse company, ltd. all rights reserved.