GAE + IAP で dbt Docs をホスティングしてみる(へのオマージュ)

qiita.com

Kさんの記事に触発されたので書きます。 この記事で示す手順の良い点は、dbt docsで生成された各種ファイルからHTMLファイルを生成しておくことで、GAEの設定が更に楽になるというところにあります。

実行環境

  • Python 3.9
  • dbt-core==1.1.0
  • dbt-bigquery==1.1.0
  • Cloud SDK

手順

通常通りdbt docs を生成した後、HTMLファイルにまとめます。

$ dbt docs generate -t prod
$ python generate-doc-in-one-static-html-file.py

HTMLを生成するスクリプト(generate-doc-in-one-static-html-file.py)はこちらです。

import json
import re
import os

PATH_DBT_PROJECT = "."

search_str = 'o=[i("manifest","manifest.json"+t),i("catalog","catalog.json"+t)]'

with open(os.path.join(PATH_DBT_PROJECT, 'target', 'index.html'), 'r') as f:
    content_index = f.read()

with open(os.path.join(PATH_DBT_PROJECT, 'target', 'manifest.json'), 'r') as f:
    json_manifest = json.loads(f.read())

# In the static website there are 2 more projects inside the documentation: dbt and dbt_bigquery
# This is technical information that we don't want to provide to our final users, so we drop it
# Note: depends of the connector, here we use BigQuery
IGNORE_PROJECTS = ['dbt', 'dbt_bigquery']
for element_type in ['nodes', 'sources', 'macros', 'parent_map', 'child_map']:  # navigate into manifest
    # We transform to list to not change dict size during iteration, we use default value {} to handle KeyError
    for key in list(json_manifest.get(element_type, {}).keys()):
        for ignore_project in IGNORE_PROJECTS:
            if re.match(fr'^.*\.{ignore_project}\.', key):  # match with string that start with '*.<ignore_project>.'
                del json_manifest[element_type][key]  # delete element

with open(os.path.join(PATH_DBT_PROJECT, 'target', 'catalog.json'), 'r') as f:
    json_catalog = json.loads(f.read())

with open(os.path.join(PATH_DBT_PROJECT, 'index.html'), 'w') as f:
    new_str = "o=[{label: 'manifest', data: "+json.dumps(json_manifest)+"},{label: 'catalog', data: "+json.dumps(json_catalog)+"}]"
    new_content = content_index.replace(search_str, new_str)
    f.write(new_content)

好きな所にGAE用のディレクトリを作ってデプロイの準備をします。先々GitHub Actions等で継続的にデプロイしていくことを踏まえて決めると良いでしょう。

$ mkdir hogehoge # 私はGCPのプロジェクトIDをそのまま流用しています

$ mkdir hogehoge/www  # ダミーでwwwとしているだけです

$ touch hogehoge/app.yaml # 設定ファイル

app.yamlはミニマムこんな感じでしょうか。

runtime: python39

handlers:
- url: /
  static_files: www/index.html
  upload: www/index.html

ディレクトwwwの直下に先ほどのindex.htmlを置いてあげます。かくしてディレクトリ構成はこうなりました。質素ですね。

hogehoge/
├── app.yaml
└── www/
     └── index.html

デプロイしましょう。

$ cd hogehoge

$ gcloud app deploy

終わりです。IAP(Google認証)はKさんのブログに書いてある通りでOKです。

私はGitHub Actionsでdbtを実行しているので、上記の一連のタスクもワークフローに乗せてしまえば人並みの生活が送れそうです(まだやれていない)。

以上です、どうもありがとうございました。