GAE/Goが好きなのでだいたいGAEでやっちゃおうとするんですけど、せっかくなのでCloud Functions使ってみたいじゃないですか。
すげー雑に、かんたんなことはGCFでやりましょう、となる。知らんけど。ある1つのトリガーに対して連鎖的に外部APIをトリガーしたいとき、みたいなシンプルで軽い用途に向いている、的な雰囲気だと思う。
% mkdir -p ~/tmp/gcftest
% cd ~/tmp/gcftest
% gcloud components update
% gcloud projects create otiai10-gcftest
% vi hello.js
% cat hello.js
exports.hello = (req, res) => {
res.send(`Hello World!`);
}
% gcloud functions deploy hello --trigger-http --project otiai10-gcftest
API [cloudfunctions.googleapis.com] not enabled on project
[otiai10-gcftest]. Would you like to enable and retry? (y/N)? y
Deploying function (may take a while - up to 2 minutes)...failed.
ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Function load error: File index.js or function.js that is expected to define function does not exist in the root directory.
% ls -la
% mv hello.js function.js
% gcloud functions deploy hello --trigger-http --project otiai10-gcftest
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
entryPoint: hello
httpsTrigger:
url: https://us-central1-otiai10-gcftest.cloudfunctions.net/hello
status: ACTIVE
timeout: 60s
updateTime: '2018-04-27T06:15:24Z'
versionId: '2
regionがus-central1になってるのがアレですが、
% curl https://us-central1-otiai10-gcftest.cloudfunctions.net/hello
Hello World!% %
やるじゃん... 2分でできた。
以下、いろいろためす
とりあえずprojectの指定めんどいので
% gcloud config set project otiai10-gcftest
% gcloud functions --help
% gcloud functions call --help
% gcloud functions call hello
executionId: dnaermtmefak
result: Hello World!
%
% gcloud functions list
NAME STATUS TRIGGER REGION
hello ACTIVE HTTP Trigger us-central1
% gcloud functions describe hello
% gcloud functions delete hello
Resource
[projects/otiai10-gcftest/locations/us-central1/functions/hello] will
be deleted.
Do you want to continue (Y/n)? y
Waiting for operation to finish...done.
Deleted [projects/otiai10-gcftest/locations/us-central1/functions/hello].
% gcloud functions call hello
ERROR: (gcloud.functions.call) ResponseError: status=[404], code=[Not Found], message=[Function hello in region us-central1 in project otiai10-gcftest does not exist]
%
% gcloud functions deploy --help
--entry-point=ENTRY_POINT
By default when a Google Cloud Function is triggered, it executes a
JavaScript function with the same name. Or, if it cannot find a
function with the same name, it executes a function named function. You
can use this flag to override the default behavior, by specifying the
name of a JavaScript function that will be executed when the Google
Cloud Function is triggered.
% gcloud functions deploy testtest \
--region ap-northeast1 \
--entry-point hello \
--trigger-http
ERROR: (gcloud.functions.deploy) ResponseError: status=[400], code=[Bad Request], message=[The request has errors
Problems:
region asia-northeast1 is not supported.
あ、Tokyoにまだ来てないのか...
% gcloud functions deploy testtest \
--entry-point hello \
--trigger-http
% curl https://us-central1-otiai10-gcftest.cloudfunctions.net/testtest
Hello World!
やるじゃん...!
シークレットの受け渡しどうする
外部APIを叩かせるにはそのAPIシークレットをもたせる必要があるよなー、と思い。環境変数かな?と思ったけどそうではないのかな。
めんどくさそう。jsonでいいや。
const secrets = require("./secrets.json");
exports.leton = (req, res) => {
res.send(secrets);
}
% gcloud functions deploy leton --trigger-http
% curl https://us-central1-otiai10-gcftest.cloudfunctions.net/leton
{"name":"Hiromu OCHIAI","age":17}
%
秘密が漏れてしまった。ソースコード管理・共有時はsecrets.json
をignoreするなりすればよいのだろうけど、アーキテクチャ的にプロジェクトのrootディレクトリをGCSに上げてるっぽいし、なんかちょっと気になるなと思った。ので質問してみた。
既出だったらすみません。GCFに、なんらかのシークレットを渡したい(だいたいの場合たぶん外部APIのトークンとか)場合のベストプラクティスって紹介されてますか?
環境変数かなと思ってググったらRuntime-Config とかいうやつにぶちあたったんですが、betaっぽいし、今の所普通にデプロイ対象ディレクトリ配下にsecrets.json
みたいなの作ってdeployしてます。
Functionかー。多少悩ましいねー
最近、適当にSecret ManagerのDemoアプリみたいなのを作ってみたりしていた https://github.com/sinmetal/gcpsm
IAP, App Engine, Cloud KMS, Cloud Datastoreを使っている
App Engineの時は、インスタンス起動時に取りに行って、メモリに持っておけばいいやーと思っていたけど、Functionですごい細かく起動する場合にこういうことするとLatencyとコストが多少気になるかも?
意外と無い。
意外とふわふわしてるんですね。KMSとかoverkillなので当面 secrets.json
でいいや、という気持ちにおちつきました :wink:
ありがとうございます :bow:
認証などどうする
世界中にオープンでいくらでもリクエストできるのはおかしい。限られた者からの呼び出しだけ許すにはどうすればよいか。
「CloudStorageへの権限をチェックする」という機構を使って、CloudFunctionsにおける認証機構を実現している。だるい。 これもsecrets.json
的な感じでまずは実装してしまおうと思う。
雑感
- 慣れたらサクッと作れてよさそう
- とりあえず東京来てくれたのむ
DRYな備忘録として