LoginSignup
0
1

More than 5 years have passed since last update.

AppEngine 使ってバッチ実行環境をクラウドにもっていくメモ

Posted at

AppEngine とは

使いどころ

  • 実験的な内容をサーバで直ちに動かしたい。取り急ぎ、スマホで画面見たいなど。
  • 本番には向かない。

便利なところ

  • node とか python とかもろもろインストールすることなく、直ちに試せる。
  • 直ちにサーバで動かせる。
  • 直ちに一般公開できる。

一方で、不便なところ

  • サーバ上のコード、生成物などは自分のみしか触れない(/home/自分/ の下しか置けない)。
  • サーバに置いたから誰かバッチ実行して、みたいなことはできない。
  • そうしたいなら git で共有して、その人のアカウント環境で実装してもらう。
  • 本番 deploy には時間がかかるので、頻繁にデプロイするのには向かない。:8080 で自分だけの実行なら時間はかからない。
  • ログやデータをローカルに保持できない。

ワード

  • サービス: AppEngine では各種機能をマイクロサービスとしてデプロイすることになる。デプロイの単位。ソースコード+設定で構成。
  • バージョン: ソースコードは複数のスナップショットを持てる。これがバージョン。デプロイ時にどのバージョンを使うか指定する。
  • インスタンス: サービス x バージョン でデプロイする際に、実際に起動する仮想サーバ。
  • スケーリング: 自動、手動、基本がある。基本的には無しでも。
  • 無料の場合の制限: 5 サービス/アプリ、 15 バージョン/アプリ
  • 有料の場合の制限: 105 サービス/アプリ、210 バージョン/アプリ
  • Standard Environment / Flexible Environment: マシンを細かく指定したいか。通常は Standard で。

導入手順

想定(下記を実現してみる)

  • AppEngine でバッチ実行をする。(Node.js v8)
  • 実行の引数を Web 画面で指定し、実行のログをリアルタイムに受け取る。(Node Express, Firebase Realtime Database)

手順

  • GCP でプロジェクトを作り、App Engine の画面に行く。
  • Google Cloud Shell 起動(画面右上の >_ アイコン)。
  • git clone してソースを持ってくる。その中には下記が含まれている。
    • app.js: メインで動く、express のファイル。
    • app.yaml: デプロイ時の設定
    • asset/log.js: Firebase Realtime Database 経由でログを受け取るJS
    • firebase-config.json: Firebase Realtime Database を使うためのコンフィグ
    • package.json: npm install するための設定
  • clone したディレクトリに移動。
  • npm install
  • node app
  • 右上にある 8080 でプレビューで画面確認。

とりあえず起動

git pull
npm install
node app
  • その後、右上にある 8080 でプレビューで画面確認。

デプロイ

# 最新に更新
git pull

# デプロイ(けっこう時間かかる)
gcloud app deploy

# ログ
gcloud app logs tail
  • ダッシュボードでもエラーログみれる。

ファイルの中身

  • app.js
'use strict';

const util = require('util');
const path = require('path');
const firebase = require('firebase/app');
require('firebase/database');
const firebaseConfig = require('./firebase-config');

// base
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({limit: '5mb', extended: true}));

// static files
app.use(express.static(path.join(__dirname, 'asset')));

// 起動画面
app.get('/', function (req, res) {
    res.send(`<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://www.gstatic.com/firebasejs/5.3.1/firebase.js"></script>
    <script>
        var config = ${JSON.stringify(firebaseConfig)};
    </script>
    <script src="logging.js"></script>
</head>
<body>
<form action="execute" method="post">
    <textarea name="data" cols="120" rows="20"></textarea><br/>
    <input type="submit" value="送信">
</form>
<pre id="log"></pre>
</body>
</html>`);
});

app.post('/execute', function (req, res) {
    // ログ出力準備
    const logRef = firebase.database().ref('logRef');
    logRef.set(null); // ログ初期化
    const logger = {};
    logger.log = (...args) => {
        args = args.map(a => typeof a === 'object' ? util.inspect(a, false, null) : a);
        logRef.push().set(args.join(' '));
        console.log(args.join(' '));
    };
    logger.error = (...args) => {
        logger.log('ERROR', ...args);
        console.error(...args);
    };
    // いったん返す(ログ初期化後)
    res.redirect('/');
    // Dialogflow 準備
    (async function () {
        try {
            // データ受け取り
            let str = req.body.data;
            // データ処理
            // ...
            // ログ出力
            logRef.push().set('ログ出力!');
        } catch (e) {
            logRef.push().set('ERR: ' + util.inspect(e, false, null));
        }
    })();
});

if (module === require.main) {
    const server = app.listen(process.env.PORT || 8080, () => {
        const port = server.address().port;
        console.log(`App listening on port ${port}`);
    });
}

module.exports = app;
  • app.yaml
runtime: nodejs8

env_variables:
  SOME_VAR_NAME: "SOME_VAR_VALUE"
  • asset/log.js: Firebase Realtime Database 経由でログを受け取るJS
firebase.initializeApp(config);
$(function () {
    let $log = $('#log');
    firebase.database().ref('logUpdateIntentsRef').on('child_added', function(data) {
        $log.text($log.text() + data.val() + "\n");
    });
});
  • firebase-config.json: Firebase Realtime Database を使うためのコンフィグ
{
  "apiKey": "xxx",
  "authDomain": "xxx.firebaseapp.com",
  "databaseURL": "https://xxx.firebaseio.com",
  "projectId": "xxx",
  "storageBucket": "xxx.appspot.com",
  "messagingSenderId": "xxx"
}
  • package.json: npm install するための設定
{
  "name": "xxx",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "^4.16.3",
    "firebase": "^5.3.1"
  }
}

app.yaml の書き方

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1