1 of 57

Google Cloud Functions

ハンズオン

by soundtricker(大橋)

2 of 57

こんな時はありませんか?

2

3 of 57

作ったアプリ内で購入されたらクーポン送りたい

3

クーポン

4 of 57

エラーが起きたらSlackに通知したい

4

エラー内容

5 of 57

サーバーを窓から投げ捨てたい

5

6 of 57

Google Cloud Functions for Firebase

7 of 57

Google Cloud Functions?

7

8 of 57

GCF?

何かあったら

何かしたい

GCPで

を叶えるもの

8

9 of 57

GCF?

何かあったら

何かしたい

GCPで

9

HTTP Requestが来たら

なんかAPIを呼び出したい

10 of 57

GCF?

何かあったら

何かしたい

GCPで

10

Cloud Storageに�ファイルが追加されたら

加工しBigQueryに追加したい

11 of 57

GCF for Firebase?

何かあったら

何かしたい

11

  • HTTP Request
  • Cloud Pub/Sub
  • Cloud Storage�

NodeJSで書けるならだいたいなんでも

12 of 57

GCFの作り方

コンソール編

ハンズオン1

12

13 of 57

作り方

  1. GCPプロジェクトを作る�
  2. コンソールから環境準備�
  3. コード書く(HTTPトリガー)�
  4. デプロイ

13

14 of 57

1. プロジェクト作る

作り方

適当に作って下さい。

14

15 of 57

2. 環境準備

作り方

1. コンソールでCloud Functionsを表示

2. APIを有効化

15

16 of 57

3. コード書く

作り方

1.関数を作成をクリック

16

17 of 57

3. コード書く

作り方

2. 以下のように設定

    • 名前:任意
    • リージョン:us-central1
    • 割り当てられるメモリ:256 MB
    • タイムアウト:60秒
    • トリガー:HTTP トリガー
    • ソースコード:インラインエディタ
    • ステージバケット:任意で新しいバケットを作ってください。
    • 実行する関数: helloWorld

17

18 of 57

3. コード書く

作り方

3. exports.{名} = function(req, res) {};

HTTPSの場合

exports.helloWorld = function(req, res) {

res.send("Hello from GCF!");

};

18

19 of 57

4. デプロイ

作り方

1. 保存ボタンをクリック ※しばらく待ちます。

19

20 of 57

5. テスト

作り方

2. 画面からやってみる テストタブをクリック

20

21 of 57

5. テスト

作り方

3. 関数をテストをクリック すると関数が実行されて結果が帰ってくる

21

22 of 57

6. テスト2

作り方

  1. ブラウザで叩いてみる
    1. トリガータブをクリック
    2. 表示されているリンクをクリック
    3. https://us-central1-{projectname}.cloudfunctions.net/{functionsname}/{関数名}

22

23 of 57

7. Appendix

作り方

  • messageパラメータをうけとり、それを返却しましょう。�messageパラメータは req.body.messageで取得できます。�
  • messageパラメータがない場合は400を返却しましょう。�status codeは res.status(statusCode)で設定できます。�
  • 新しくhelloWorld2関数を作り別の値を返却するようにし、�URLから起動しましょう。

23

24 of 57

GCFの作り方2

CLI編

ハンズオン2

24

25 of 57

作り方

  • プロジェクトを作る(さっきのでok)�
  • CLIから環境準備�
  • コード書く(Pub/Subトリガー)�
  • デプロイ

25

26 of 57

1. プロジェクト作る

作り方

適当に作って下さい。

さっきのでもOK

26

27 of 57

2. 環境準備

作り方

※ローカルにgcloudコマンドセットアップ済みならば移行は手元で実施してください。�まだセットアップが終わってない場合はCloud Shellを使ってください。

27

28 of 57

3. コード書く

作り方

1. exports.{名} = function(event, callback) {};

Pub/Subの場合

exports.helloWorld3 = function helloWorld3 (event, callback) {

console.log(`My Cloud Function: ${event.data.message}`);

callback();

};

28

29 of 57

2. 環境準備

作り方

0. gcloudコマンドをインストール&セットアップ

1. betaコマンドを追加

29

$ gcloud components install beta

$ gcloud components update�

30 of 57

3. コード書く

作り方

1. 作業ディレクトリを作成

2. ファイルを作成(viじゃなくてもいいです。)

30

$ mkdir ~/function2

$ cd ~/function2

$ vi index.js

31 of 57

4. デプロイ

作り方

1. デプロイ ※結構時間かかります。

31

$ gcloud beta functions deploy helloWorld3 --stage-bucket {さっき作ったやつ} --trigger-topic hello_world�

32 of 57

5. テスト

作り方

1. 以下を叩く

2. ログの確認

32

$ gcloud beta functions call helloWorld3 --data '{"message":"Hello World!"}'

$ gcloud beta functions logs read helloWorld3

33 of 57

6. Appendix

作り方

  • callbackを呼ぶ際にエラーにしましょう。�エラーは callback(1) 、 callback(new Error("HOGE")) などでエラーに出来ます。�
  • Stackdriver LoggingのGCSのログをPub/Subにエクスポートして、�GCFでログ出力しましょう。�

33

34 of 57

GCF

ライブラリ

34

35 of 57

GCFとライブラリ

  • GCFではpackage.jsonを持っているとdependencyを解決してデプロイしてくれます。��package.json

{

"dependencies": {

"uuid": "^3.0.1"

}

}

const uuid = require('uuid');

exports.getUuid = function (req, res) {

res.send(uuid.v4());

};

35

36 of 57

GCF

GCSとライブラリ

ハンズオン3

36

37 of 57

GCSとライブラリ

  • GCSにファイルがアップロードされた時に、ファイルサイズをログに表示するfunctionsを作成します。
  • まずpackage.json ファイルダウンロードするために、GCSのライブラリを入れます。

{

"dependencies": {

"@google-cloud/storage": "^1.4.0"

}

}

37

38 of 57

GCSとライブラリ

  • gcsもpub/subと同じ書き方です。�exports.logSize = function(event, callback){}

const storage = require('@google-cloud/storage')();

exports.logSize = function (event, callback) {

const object = event.data;

if (object.resourceState === 'not_exists') {

callback('This is a deletion event.');

return;

;

} else if (!object.name) {

callback('This is a deploy event.');

return;

}

const file = storage.bucket(object.bucket).file(object.name).download(function(err, contents) {

console.log(`${object.name} file size is ${contents.length}`);

callback(null, "success")

});

};

38

39 of 57

GCSとライブラリ

  1. gcsの更新をトリガーにしてgcfを登録
  2. 設定したgcs バケットにファイルをアップロード
  3. ログにファイル名、ファイルサイズが表示されることを確認�

39

40 of 57

Appendix

GCSとライブラリ

40

41 of 57

GCF

GCFとLinux

41

42 of 57

GCFとLinux

  • GCFは現状Linux上で動いており、linux系のコマンドであれば�nodejs経由で起動できます�
  • 例えばpythonやImageMagickなどは最初から入っており、�nodejs経由で起動することも出来ます。�
  • Linux上で実行可能な形式のファイルであればdeploy時に一緒にアップロードして、起動することも出来ます。�※goのファイルをコンパイルしておいて一緒にデプロイするとか

42

43 of 57

GCFとLinux

const exec = require('child_process').exec;

const fs = require('fs');

const path = require('path');

const storage = require('@google-cloud/storage')();

exports.blur = (event, callback) => {

const object = event.data;

if (object.resourceState === 'not_exists' || !object.name) {

callback()

return;

}

const tempLocalFilename = `/tmp/${path.parse(file.name).base}`;

return storage.bucket(object.bucket).file(object.name).download({destination: tempLocalFilename})

.catch((err) => {return Promise.reject(err);})

.then(() => {

return new Promise((resolve, reject) => {

exec(`convert ${tempLocalFilename} -channel RGBA -blur 0x24 ${tempLocalFilename}`, {stdio: 'ignore'}, (err, stdout) => {

if (err) {

console.error('Failed to blur image.', err);

reject(err);

} else {

resolve(stdout);

}

});

});

}).then(() => {callback();});

};

43

44 of 57

GCF

GCFとLinux

ハンズオン4

44

45 of 57

GCFとLinux

  • GCSに動画ファイルがアップロードされた時に、ffmpegを利用して、�アニメーションgifを作成します。
  • まずpackage.json ファイルダウンロードするために、GCSのライブラリ、�ffmpegを入れるためにffmpeg-static,fluent-ffmpegを入れます。

{

"dependencies": {

"@google-cloud/storage": "^1.4.0",

"ffmpeg-static": "^2.0.0",

"fluent-ffmpeg": "^2.1.2"

}

}

45

46 of 57

GCFとLinux

  • コード

const ffmpeg = require('fluent-ffmpeg');

const storage = require('@google-cloud/storage')();

const ffmpegStatic = require("ffmpeg-static");

const path = require("path");

exports.animationGif = (event, callback) => {

const object = event.data;

if (object.resourceState === 'not_exists') {

callback('This is a deletion event.');

return;

} else if (!object.name) {

callback('This is a deploy event.');

return;

} else if(!object.name.endsWith("mp4")) {

callback(`Not mp4 file ${object.name}`);

return;

}

console.log(`start convert ${object.name}`);

const bucket = storage.bucket(object.bucket);

const file = bucket.file(object.name);

const tempLocalFilename = `/tmp/${path.parse(file.name).base}`;

const output = tempLocalFilename + ".gif";

// 次のページに続く

46

47 of 57

GCFとLinux

  • コード

return file.download({destination: tempLocalFilename})

.catch((err) => {

callback(err);

return Promise.reject(err);

})

.then(() => {

// Convert mp4 to animation gif

return new Promise((resolve, reject) => {

ffmpeg(tempLocalFilename)

.outputOptions([

"-an", "-r", "15", "-pix_fmt", "rgb24", "-f", "gif"

])

.setFfmpegPath(ffmpegStatic.path)

.on('end', () => resolve(output))

.on('error', (err) => reject(err))

.save(output);

});

}).then((result) => {

return bucket.upload(result, {destination: `${path.parse(output).base}`, public: true});

}).then(()=> {

callback();

});

};

47

48 of 57

GCFとLinux

  • 多分メモリーサイズとタイムアウトが足りない可能性があるので短めの動画を試してください。

48

49 of 57

まとめ

49

50 of 57

まとめ

  • GCFは「何かおきたら 何かやる」�を簡単に作る仕組み�
  • うまくやるとクライアントアプリ(Web、Mobile)と�サーバを完全分離できる (リクエストすらいらない)�
  • GCF for Firebaseを使うともっと色々やれる�
  • Firebase AnalyticsとかCrash Reportと使うと�モバイルのイベントに対して様々なことをできる

50

51 of 57

参考資料

51

52 of 57

サーバーを窓から投げ捨てられますね(嘘

52

53 of 57

おまけ

53

54 of 57

Cloud Functions

Local Emulator

54

55 of 57

Local Emulator

  • ハンズオンの通り毎回アップロードして何かやるのは結構大変�
  • デバッグできない、アップロード時間がかかるなど結構めんどくさい�
  • ローカルエミュレーターあるよ�※公式�https://github.com/GoogleCloudPlatform/cloud-functions-emulator

55

56 of 57

Local Emulator

  1. インストール��
  2. 起動��
  3. デプロイ

56

$ npm install -g @google-cloud/functions-emulator

$ functions start

$ functions deploy helloWorld --trigger-http

57 of 57

Local Emulator

  • 実行��
  • ログ

57

$ functions call helloWorld�$ curl http://localhost:8010/YOUR_PROJECT_ID/local/helloWorld

$ functions logs read