Serverless NEGを使ってApp Engineにカスタムドメインをワイルドカードマッピング
ご存知の通り、Google App Engineにデフォルトで割り当てられるドメインは{project_id}.appspot.com
ですが、{version}-dot-{service}-dot-{project_id}.appspot.com
でアクセスすればバージョンやサービスを指定できます。App Engineにカスタムドメインを割り当てていても同じことができて、{version}.your_custom_domain.com
のようにすれば、(dispatch.yamlをいじっていなければ)デフォルトサービスの指定したバージョンにアクセスできます。自分のチームでは開発ブランチの動作確認などに使っています。めっちゃ便利です。
しかし、App Engineの公式ドキュメントにはとても恐ろしいことが書いてあります。
カスタム ドメインを使用すると、一部のリージョンで App Engine がアプリのユーザーに送信するレスポンスに、著しいレイテンシが発生することがあります。リージョンは以下のとおりです。
(…)
asia-northeast1
つまり、東京リージョンでは「著しいレイテンシ」が発生するらしいです。ぴえん。
この問題自体は知っていたのですが、正直そこまで爆速レスポンスも求められてないし仕方ないかなと思っていました。そんな中、こんなツイートを見かけました。
そういえば東京リージョンが来たくらいから話題になっていた App Engine の custom domain latency の問題はついに Serverless NEG を使えば良いということで Won't Fix (Infeasible) になっていたhttps://t.co/P8vAORIsGl#gcpug
— _ (@apstndb) February 19, 2021
Serverless NEGを使うしかない、というオチにはあまり納得感がありませんが、Serverless NEGいじってみたいな〜と思っていたところなのでちょうどよいお題が生えました。そこで今回は、Serverless NEGを使ってApp Engineにカスタムドメインをマッピングしてみようと思います。ただそれだけでは面白くないので、表題の通り上述のようなサブドメインによるバージョン切り替えをServerless NEGを使っても実現できるか試してみましょう。
なお、Serverless NEGの細かい説明はしませんので(できませんので)以下の記事を参考にして下さい。
また、Serverless NEG作成の大まかな流れはこちらを参考にしました。
Google のグローバルなロードバランサーとサーバーレスサービスの色々な組み合わせ
準備
ドメインは取得済みとします。Freenomだと無料で取得できます(サイトは不安になるほど重いです)。
App Engineのデプロイ
バージョンの切り替えがレスポンスからわかるようにしています。
from flask import Flask
import os
app = Flask(__name__)
@app.route('/')
def hello():
return f'GAE version: {os.environ.get("GAE_VERSION")}'
デフォルトサービス用のapp.yaml
を書いて複数のバージョンをデプロイして下さい。
静的IPの予約
ロードバランサーのIPを予約しておきます。また、お手持ちのドメインが予約したIPに向くように各自のDNSサービスで設定しておいてください。
gcloud compute addresses create ${IP_NAME} \
--ip-version=IPV4 \
--global
ワイルドカードSSL証明書の登録
固定ドメインの場合はGCPのマネージド証明書を使えばいいのですが、今回は任意のバージョン名をサブドメインとして使うため、ワイルドカード証明書が必要です。ワイルドカード証明書はGCPで管理してくれないので、各自Let’s Encrypt等で発行しておいて下さい。それをGCPに登録します。
sudo gcloud compute ssl-certificates create ${CERTIFICATE_NAME} \
--certificate=path/to/your/fullchain.pem \
--private-key=path/to/your/privkey.pem \
--global
ロードバランサーの作成
正直詳しくは知らないんですが、トラフィックをNEGに流したりする用途でバックエンドサービスというものが必要みたいです。後で作るServerless NEGはこいつに紐付けます。
gcloud compute backend-services create --region=asia-northeast1 ${BACKEND_NAME}
URLからどのバックエンドサービスに流すかを決めるためのurl-mapを作ります。今はバックエンドサービスは1つなのであまり気にしないで大丈夫です。default-service
にさっき作ったバックエンドを指定しています。
gcloud compute url-maps create --default-service=${BACKEND_NAME} ${URL_MAP_NAME}
ロードバランサーへのhttp/httpsリクエストをurl-mapに送るようにします。httpはSSL証明書がおかしいときなどに問題を切り分けやすくするため追加しています。おそらく必須ではないです。httpsはSSL証明書リソースの名前を指定する必要があります。
gcloud compute target-http-proxies create ${HTTP_PROXY_NAME} \
--url-map=${URL_MAP_NAME}
gcloud compute target-https-proxies create ${HTTPS_PROXY_NAME} \
--url-map=${URL_MAP_NAME} --ssl-certificates=${CERTIFICATE_NAME}
最後にforwarding ruleを追加します。http/httpsで2つ作ります。
gcloud compute forwarding-rules create ${HTTP_FORWARDING_NAME} \
--address=${IP_NAME} \
--target-http-proxy=${HTTP_PROXY_NAME} \
--global \
--ports=80
gcloud compute forwarding-rules create ${HTTPS_FORWARDING_NAME} \
--address=${IP_NAME} \
--target-https-proxy=${HTTPS_PROXY_NAME} \
--global \
--ports=443
NEGの作成
いよいよNEGを作ります。
gcloud beta compute network-endpoint-groups create ${NEG_NAME} \
--region=asia-northeast1 \
--network-endpoint-type=SERVERLESS \
--app-engine-app \
--app-engine-url-mask=‘<version>.${YOUR_DOMAIN}’ \
--app-engine-service=default
肝は--app-engine-url-mask
です。ここでバージョンの振り分けを実現するのですが、公式ドキュメントだとApp Engine側にもカスタムドメインを設定している場合の例しかないのでわかりにくい部分です。
今の指定だと、例えばカスタムドメインがkabuku-custom.jp
でGCPのプロジェクトがkabuku-sample-proj
だった場合、develop.kabuku-custom.jp
へのリクエストがdevelop-default-dot-kabuku-sample-proj.appspot.com
に飛ばされます。App Engineのサービスは--app-engine-service
で指定しています。
最後にNEGをバックエンドサービスに追加して完成です。
gcloud beta compute backend-services add-backend sample-backend-service \
--global \
--network-endpoint-group=${NEG_NAME} \
--network-endpoint-group-region=asia-northeast1
動作確認してみましょう。develop
バージョンだと
となって、sample-version
だと
うまくいきました!ちなみに、存在しないバージョンを指定するとちゃんと404になります。App Engineにドメインを割り当てたときはトラフィックのあるバージョンに勝手にフォールバックしてしまっていたので地味にうれしいです。
まとめ
App Engineだけの構成と比べると正直「やることが……やることが多い……!!」感は否めませんが、最初からServerless NEGを使っておくと後からWebSocketを使いたくなったとき1などにヌルっと同一ドメインでCloud Runを乗っけたりできるので、レイテンシー回避以外のメリットもあります。ただ、ロードバランサーの費用に見合うかはどうかは要件次第ですね。最初からCloud Runで全部組むのが早いかもしれません。
以上、やってみた記事でした。書いた人はこいつ。
- App Engine standardだと使えないので…… ↩
その他の記事
Other Articles
関連職種
Recruit