googlecloud


Google App Engineにnode.jsアプリを持っていくときのメモ

環境: windows10 

  • Python2.7.9以降のPython2系をインストールしてパスを通す。既にしていた。
  • Google Cloud SDK をインストールする。 D:\tool\Cloud SDK\ にインストールした。
  • gcloud init →これでメアド、OAuthログイン、ターゲットプロジェクトが設定される。
  • gcloud components update を実行する
PS C:\Users\uimac> gcloud version
Google Cloud SDK 221.0.0
bq 2.0.35
core 2018.10.12
gsutil 4.34
  • ".py"ファイルはPython2.7に関連付けておく(ダブルクリックで実行できるようにしておく)
  • gsutilのOAuthはgcloudとは別になっている。
    gsutil config
    を実行してログインして使えるようにする。はずなんだが、SSLのエラーが出て全然できない。諦める。 無くてもオンラインコンソールもあるし全然大丈夫。
  • 3万円分くらいのボーナスが無料でついてきたので、将来のことを考えて、 無料枠のUSのリージョンではなくて、基本的に東京リージョンにする。 →後でリージョンを変更するのはできないし、リージョンまたぐアプリをやるのは大変らしいので、  最初から東京を使う。大丈夫3万も使いきれない。たぶん。
  • 課金レポートを出力する設定をする。(怖いから先にやっとくべき)
    • ここでCloudStorageに"バケット"を作成することとなる
    • 課金レポート出力の設定はプロジェクトをまたいで設定されるようだ。
    • つまりBプロジェクトの課金レポートのストレージバケットは、設定を行ったAプロジェクトで作ったものとかになる。

  • 課金レポートを作成した後、
    とりあえず、helloworldくらいはやって、app.yamlを自分のプロジェクトに作ってデプロイできるようにしておく。
  • helloworldやればわかるが、gcloudコマンドでデプロイする
    • デプロイすると、CloudStorageに  asia.artifacts.projectid.appspot.com  というバケットが勝手に作られる
    • どうやらこの中にデプロイしたブツが入っているようだ

  • gcloudコマンドで一度デプロイするとデプロイ先を覚えられる。 別プロジェクトにデプロイするには
    gcloud app deploy --version [YOUR_VERSION_ID] --no-promote --project [YOUR_PROJECT_ID]
    "--project"を指定する。または、gcloud initを再度実行して、ターゲットプロジェクトを変更する。

[ローカル開発環境での使用]
  • https://cloud.google.com/docs/authentication/getting-started
    によってアプリケーションの認証情報を作成する(jsonファイルをダウンロード)
  • GOOGLE_APPLICATION_CREDENTIALS にjsonファイルを登録
  • これでローカルで実行している自作アプリから直接cloud storageやcloud datastoreがいじれるようになる

[サービス/stagingなどについて]
  • サービスという単位で、staging用や本番用といった、別々のデプロイが可能。
    app.yamlで何もserviceを指定しなかったら、"default"に対してデプロイされ、
    [projectid].appspot.comで見れる。
    app.yamlで
    service staging
    という指定をすると、デプロイしたものは、staging-dot-[projectid].appspot.com で見れる
  • デプロイ済のサービスは、ウェブコンソールのAppEngine→サービスからも確認できる。

  • staging.[projectid].appspot.com というバケットが勝手に作られているので、
    statingにデプロイしてこのURLでアクセスできるのかと思いきや、
    appspot.comドメインである限り、staging-dot-[projectid].appspot.comというURLでしかアクセスできない模様
    https://cloud.google.com/appengine/docs/standard/python/how-requests-are-routed

[cloud datastore/cloud storage]
  • https://www.apps-gcp.com/gcp-storage-service/
    値段とかは、ここによくまとまっている。他にもbigtableとcloud sqlがあるが、俺はたぶんdatastore/storageにしか用はない。

  • cloud datastoreのほうがちょい高い。小さいデータを入れるようかな?datastoreにはblobは1MB/個くらいしか入らない模様。
    NoSQLだし、redisみたいなもんか?
    redisも使えるけど料金が高そう。

  • cloud storageは メディアデータみたいなちょいデカいデータの保存用。ファイルみたいな扱いで保存されるような印象。
    つまり一度保存して再度アクセスするためにdatastoreに保存先URLを記録しておく必要がある。
  • 結論:両方使おう。
[cloud datastore]
  • https://cloud.google.com/datastore/docs/concepts/entities?hl=ja
    ここの真ん中よりちょい下の、「プロパティと値の型」のところに保存できるデータ形式と容量などが書いてある。
  • 「地理的座標」っていうのがあるのか。すごい
  • ローカル開発環境を整えて、npm install --save @google-cloud/datastoreする。
    それから↓をコピペしてnode.jsで実行すると、とりあえず動く。
    https://www.npmjs.com/package/@google-cloud/datastore
  • サンプルでは「task」という変数が使われているが、これはentityの方言のようなので、「entity」で覚える。
[cloud storage]
  • env_variables:
      GCLOUD_STORAGE_BUCKET: YOUR_BUCKET_NAME
  • をapp.yamlに設定。
    env:flexというのはnode.js環境の場合は、flexible environmentというやつでしかそもそも動かないらしいので
    たぶん設定しなくてもflexになっている。
  • body-parser というのをpostされてきたjsonをパースするために使っている。
    こちら、よくあるurlparameterみたいな形式(?)のpostにも対応させるには以下のようにする。
// https://github.com/expressjs/body-parser
app.use(bodyParser.urlencoded({extended: false}))
// application/jsonをパースする設定
app.use(bodyParser.json())
  • multipartのpostに対応させるにはmulterを入れる。
  • multer というのはmultipart/form-dataのpostを分解するやつらしい。なんとbody-parserではblobに対応していない。
  • multer は文字列もbinaryも送れるので、これだけでよい気もする。が、GETとかも使うので一応body-parserも入れておく。
  • multerの設定はstorageのチュートリアルを参照。


  • さらにクライアントサイドのpure jsからXMLHttpRequestでPOSTするには以下のようにする。
    サーバーからの返却値はjsonを期待するようにした。
    GETのほうはググれば割と出てくるので割愛。

    // HTMLフォームの形式にデータを変換する
    function encodeHTMLForm(data) {
        let params = [];
        for (let name in data) {
            let value = data[name];
            let param = encodeURIComponent(name) + '=' + encodeURIComponent(value);
            params.push(param);
        }
        return params.join('&').replace(/%20/g, '+');
    }

    /**
     * POSTリクエスト
     * json用. サーバーではbody-parseで解釈する
     */
    Util.POST = function (methodName, data, callback) {
        let xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            const DONE = 4;
            const HTTP_OK = 200;
            if (this.readyState == DONE) {
                callback(this.status == HTTP_OK ? null : this.status, this.response);
            }
        };
        xhr.onerror = function () {
            console.error(xhr.responseText)
        }
        xhr.open('POST', methodName);
        xhr.responseType = 'json';
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.send(encodeHTMLForm(data));
    }
    
    /**
     * POSTリクエスト
     * バイナリファイルなどを含んだmultipart用. サーバーではmulterで解釈する
     */
    Util.POSTMultipart = function (methodName, data, callback) {
        let form = new FormData();
        for (let name in data) {
            form.append(name, data[name]);
        }
        let xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            const DONE = 4;
            const HTTP_OK = 200;
            if (this.readyState == DONE) {
                callback(this.status == HTTP_OK ? null : this.status, this.response);
            }
        };
        xhr.onerror = function () {
            console.error(xhr.responseText)
        }
        xhr.open('POST', methodName);
        xhr.send(form);
    }

リクエストは Google のグローバル供給インフラストラクチャを利用しているため、Cloud Storage からの直接の提供が便利です。アプリケーションは画像のリクエストに応答する必要がありません。これにより、CPU サイクルが他のリクエスト用に開放されます。

Comments