[GCP]Cloud Functions + Flaskで動的にHTMLを作成する
「Webページを公開したいが、ほとんど使わないものにはあまり費用をかけたくない。」
そんなときにはGCP「Cloud Functions」やAWS「Lambda」などのサーバレス技術を活用すれば、基本的に固定費はかからず、アクセス数に応じた課金だけでWebページを配信することができます。
サーバレスで固定のHTMLを配信する方法はよく見かけますが、動的にWebページを作成する方法はあまり見かけなかったので、この記事では Cloud Functions + Flask を使って、アクセス時のパラメータでWebページの内容を動的に変更する方法を紹介します。
※ここではCloud Functionsをデプロイするまでの「手順」の説明となります。GCP、Python、Flaskに関する技術的な内容はご自身で学習してください。
AWSのLambdaを使って実現する方法はこちらで紹介しています。
対象読者
- 動的なWebコンテンツ(Webアプリ)を、費用を抑えながら公開したい
- Python、Flaskに関して多少の知識があるのが望ましい
GCPプロジェクトを作成する
GCP コンソール(https://console.cloud.google.com/)にアクセスし、Webコンテンツを公開するためのプロジェクトを作成する。
①プロジェクト名の横の三角マークをクリックし、プロジェクトの選択を表示する。
②「プロジェクトの選択」で「新しいプロジェクト」を選択する。
③「新しいプロジェクト」でプロジェクト名や組織を設定して作成する。
以降は、ここで作成したプロジェクトに設定を行っていく。
プロジェクトに請求アカウントを設定する
Cloud Functionsでも料金は発生する可能性があるため、プロジェクトに請求アカウントを設定しておく必要がある。
①「プロジェクトの選択」で作成したプロジェクトを開く。後で必要になるので、このときプロジェクトIDの値を確認しておく。
②GCPの検索ボックスに「請求」と入力し「請求アカウント」を開く。
③この時点では「このプロジェクトには請求先アカウントがありません」と表示されるので、「請求先アカウントをリンク」をクリックする。
④任意の請求先アカウントを設定する。
コンテンツ用ファイルを作成する
WebコンテンツはGCP上のFlaskで生成して表示させる。
今回のサンプルでは、以下のファイル構成でGCP上にFlask用のファイルを作成する。
- ~/func1/ … ホームディレクトリにWebアプリ用のディレクトリを作成しておく
- main.py … Webアプリケーションのプログラム
- templates … Flaskのテンプレートファイル用のディレクトリ
- template1.html … テンプレートファイル その1
- template2.html … テンプレートファイル その2
①ファイルの作成はCloud Shellで行います。GCP コンソールのメニューからCloud Shellを起動する。
②Cloud Shellを起動すると、シェルの「$」の前のカッコ内はさきほど作成したプロジェクトのID(上記で確認した値)になっているはず。
もしもプロジェクトIDになっていない場合は、Cloud Shellで下記のコマンドを実行する。
このときに承認要求が出てきたら「承認」を選ぶ。
$gcloud config set project プロジェクトID(上記で確認した値)
main.pyを作成する
③ホームディレクトリにfunc1ディレクトリを作成するため、Cloud Shellで以下のコマンドを実行する。
$mkdir ~/func1
④func1ディレクトリ内にmain.pyを作成するため、Cloud Shellで以下のコマンドを実行してテキストエディタを開く。
$nano ~/func1/main.py
⑤テキストエディタに、下記「main.pyの内容」の内容をコピペする。
main.pyの内容
from flask import render_template, Flask
app = Flask(__name__)
@app.route("/", methods=["GET"])
def webapp(request):
# URLのパラメータ「tno」でテンプレートファイルを切り替える
template_no = request.args.get('tno')
if template_no == "2":
# URLのパラメータ「id」をテンプレートファイルに埋め込む
return render_template('template2.html', id=request.args.get('id'))
else:
# URLのパラメータ「id」をテンプレートファイルに埋め込む
return render_template('template1.html', id=request.args.get('id'))
if __name__ == "__main__":
app.run(debug=False, host='0.0.0.0', port=80)
⑥貼り付けたら、キーボードで Ctrl + x → y → Enter の順に操作し、テキストエディタを終了させる。
以上でmain.pyが作成される。
template1.htmlを作成する
⑦~/func1ディレクトリにtemplatesディレクトリを作成するため、Cloud Shellで以下のコマンドを実行する。
$mkdir ~/func1/templates
⑧templatesディレクトリにtemplate1.htmlを作成するため、Cloud Shellで以下のコマンドを実行してテキストエディタを開く。
$nano ~/func1/templates/template1.html
⑨テキストエディタに、下記「template1.htmlの内容」をコピペする。
template1.htmlの内容
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>template1</title>
</head>
<body>
<h1>テンプレートファイル1</h1>
受け取ったidは {{id}} です。
</body>
</html>
⑩貼り付けたら、キーボードで Ctrl + x → y → Enter の順に操作し、テキストエディタを終了させる。
以上でtemplate1.htmlが作成される。
template2.htmlを作成する
⑪templatesディレクトリにtemplate2.htmlを作成するため、Cloud Shellで以下のコマンドを実行してテキストエディタを開く。
$nano ~/func1/templates/template2.html
⑫テキストエディタに、下記「template2.htmlの内容」をコピペする。
template2.htmlの内容
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>template2</title>
</head>
<body>
<h1>テンプレートファイル2</h1>
受け取ったidは {{id}} です。
</body>
</html>
⑬貼り付けたら、キーボードで Ctrl + x → y → Enter の順に操作し、テキストエディタを終了させる。
以上でtemplate2.htmlが作成される。
デプロイする
①Cloud Shellで以下のコマンドを実行して、Cloud Functionsをデプロイする。
$cd ~/func1
$gcloud beta functions deploy webapp --runtime python37 --trigger-http
②以下のような確認メッセージ(2種類)が表示されたら、どちらもyを入力する。
API [cloudfunctions.googleapis.com] not enabled on project [xxxxxxxxxxx]. Would you like to enable
and retry (this will take a few minutes)? (y/N)?
Allow unauthenticated invocations of new function [webapp]? (y/N)?
③以下のようなエラーメッセージが表示されたら、メッセージ内のURLをクリックする。Cloud Build APIのページが表示されるので「有効にする」をクリックすると1分程度で有効になり、ページが切り替わる。APIが有効になったら、再度デプロイのコマンドを実行する。
有効化した直後にコマンドを再実行すると同じエラーメッセージが出ることがある。その場合は数分待ってからコマンドを実行する。
ERROR: (gcloud.beta.functions.deploy) OperationError: code=7, message=Build failed: Cloud Build API has not been used in project xxxxxxxxxxxx before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=xxxxxxxxxxxx then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
デプロイに成功すると以下のようなメッセージが表示される。
この「url」欄がデプロイしたCloud FunctionsのURLになる。
availableMemoryMb: 256
buildId: xxxxx
buildName: projects/xxxxxxxxxxx/locations/us-central1/builds/xxxxx
dockerRegistry: CONTAINER_REGISTRY
entryPoint: webapp
httpsTrigger:
securityLevel: SECURE_OPTIONAL
url: https://us-central1-samplefunction-xxxxxx.cloudfunctions.net/webapp
ingressSettings: ALLOW_ALL
labels:
deployment-tool: cli-gcloud
name: projects/samplefunction-xxxxxx/locations/us-central1/functions/webapp
runtime: python37
serviceAccountEmail: samplefunction-xxxxxx@appspot.gserviceaccount.com
sourceUploadUrl: xxxxxx
status: ACTIVE
timeout: 60s
Cloud Functionsにアクセスする
上記で発行されたURLにアクセスすれば、デプロイしたCloud Functionsを利用できる。
今回のサンプルでは、URLに「tno」、「id」のパラメータを指定することで表示するWebページの内容が以下のように動的に変わる。
- tno
- パラメータに「2」を指定すると、テンプレートファイルとして「template2.html」を使用する。パラメータがそれ以外の値なら「template1.html」を使用する。
- id
- テンプレートファイル内の{{id}}の部分を、このパラメータに指定した値で置き換える。
例えば、「template2.html」を使用して、テンプレートファイル内の{{id}}の部分を「123」に置き換える場合には、URLを以下のように指定する。
https://us-central1-samplefunction-xxxxxx.cloudfunctions.net/webapp?tno=2&id=123
さいごに
以上の様に、Cloud Functionsを使えば動的なWebコンテンツをサーバレスで配信できるので、Webサーバを稼働し続けるまでもないようなWebアプリには便利ですね。
今回紹介したソースファイルが、ご自身のコンテンツ配信アプリの参考になれば幸いです。
お疲れ様でした。
ディスカッション
コメント一覧
まだ、コメントがありません