Google AppEngine - Managed VM

Managed VM是Google App Engine所推出的PaaS - AppEngine服務的延伸,透過Linux Container的技術與AppEngine frontend的搭配,讓整個AppEngine的功能無限延伸。

本服務仍在Beta階段,但是整體的服務概念已經大致完成,筆者也正在著手測試穩定性與可用性當中,有興趣的朋友可以一起參加Google的測試...

準備Managed VM環境

安裝boot2docker

您可以到boot2docker的官方下載點,下載boot2docker以供安裝。安裝後,即可執行boot2docker的指令,並解僵boot2docker環境啟動...

boot2docker init
$ boot2docker up
$ $(boot2docker shellinit)

安裝google cloud sdk

Mac環境下,透過curl即可下載安裝google cloud sdk...,其他環境可以參考Google官方說明

curl https://sdk.cloud.google.com | bash

安裝完cloud sdk之後,需要下載開發人員預覽版本的指令庫...

gcloud components update app

認證與設定專案

替您的google cloud sdk認證

gcloud auth login

接著會出現或是開啟認證用的url,完成認證流程即可。接下來則是將Google專案資訊設定至SDK環境...

gcloud config set project [project-id]

準備開發 - 以express為範例

安裝相關套件

$ sudo npm install express-generator -g

建置express專案

$ express -e myapp
$ cd myapp

增加app.yaml設定檔

app.yaml是AppEngine環境的設定檔,目的是提供frontend instance (appengine)與backend instance (managed vm)之間的呼叫介面,以下面設定為例,即是讓所有的路由均由app.js提供服務...

version: 2
runtime: nodejs
vm: true
api_version: 1
module: default

manual_scaling:
  instances: 1

handlers:
- url: /.*
  script: app.js

註:新版本managed vm中app.yaml設定有些微調整,原runtime: custom需改為runtime: nodejs,另外曾ㄐㄧㄚ module: default的設定來指定module。

建立"Dockerfile"檔案

Dockerfile是作為未來部署Managed VM環境的依據,您可以依照希望執行的Backend狀態來庭整這個設定檔。在此,我們只有單純把docker賦予node.js的環境,因此僅僅使用Google所提供的base image即可...

FROM google/nodejs-runtime

如果對Docker有興趣,您可以到docker hub檢視Google node.js runtime的docker build file (參考),可以了解實際Managed VM執行的環境與狀態...

編輯package.json,引入appengine模組

在package.json中加入appengine的dependency,該套件提供了與AppEngine整合的一些操作方法,讓應用程式得以與Google其他服務互動。

{
  "name": "test",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.12.0",
    "cookie-parser": "~1.3.4",
    "debug": "~2.1.1",
    "ejs": "~2.3.1",
    "express": "~4.12.0",
    "morgan": "~1.5.1",
    "serve-favicon": "~2.2.0",
    "appengine" : "git://github.com/GoogleCloudPlatform/appengine-nodejs.git"
  }
}

修改express設定檔

加入appengine的import

var appengine = require('appengine');

並且於app.use部分加入appengine middleware模組

app.use(appengine.middleware.base);

建立系統預設路由 - /_ah/*

加入Managed VM的health check routes

app.get('/_ah/health', function(req, res) {
  res.set('Content-Type', 'text/plain');
  res.send(200, 'ok');
});

app.get('/_ah/start', function(req, res) {
  res.set('Content-Type', 'text/plain');
  res.send(200, 'ok');
});

app.get('/_ah/stop', function(req, res) {
  res.set('Content-Type', 'text/plain');
  res.send(200, 'ok');
  process.exit();
});

修改啟動port至8080

開啟bin/www檔案,將預設port修改為8080

var port = normalizePort(process.env.PORT || '8080');

預先測試

在未佈署到docker環境錢,該專案可以在npm install安裝完相依套件後,使用npm start測試是否可以正常執行。

npm install && npm start

可以如此測試是因為Docker build file中有指定docker instance開立起來後,是以npm start來喚起所要執行的專案... 因此我們可以使用這個方式來測試該專案到container中是否可以正常執行...

本地端執行Managed VM

本地端執行Managed VM時,需要搭配boot2docker已經開啟的狀態下,切換到專案目錄中,執行下面指令:

$ gcloud preview app run .
Module [default] found in file [/private/tmp/test/app.yaml]
INFO: Looking for the Dockerfile in /private/tmp/test
INFO: Using Dockerfile found in /private/tmp/test
INFO     2015-03-04 15:53:04,198 devappserver2.py:726] Skipping SDK update check.
INFO     2015-03-04 15:53:04,293 api_server.py:172] Starting API server at: http://localhost:62335
INFO     2015-03-04 15:53:04,365 containers.py:259] Building docker image managedvm-project.default.2 from /private/tmp/test/Dockerfile:
INFO     2015-03-04 15:53:04,365 containers.py:261] --------------------  DOCKER BUILD  --------------------
INFO     2015-03-04 15:53:04,366 dispatcher.py:186] Starting module "default" running at: http://localhost:8080
INFO     2015-03-04 15:53:04,370 admin_server.py:118] Starting admin server at: http://localhost:8000
INFO     2015-03-04 15:53:04,873 containers.py:280] # Executing 3 build triggers

INFO     2015-03-04 15:53:04,874 containers.py:280] Trigger 0, ADD package.json /app/
INFO     2015-03-04 15:53:04,874 containers.py:280] Step 0 : ADD package.json /app/
INFO     2015-03-04 15:53:04,879 containers.py:280] ---> Using cache
INFO     2015-03-04 15:53:04,879 containers.py:280] Trigger 1, RUN npm install
INFO     2015-03-04 15:53:04,879 containers.py:280] Step 0 : RUN npm install
INFO     2015-03-04 15:53:04,917 containers.py:280] ---> Using cache
INFO     2015-03-04 15:53:04,918 containers.py:280] Trigger 2, ADD . /app
INFO     2015-03-04 15:53:04,918 containers.py:280] Step 0 : ADD . /app
INFO     2015-03-04 15:53:04,937 containers.py:280] ---> Using cache
INFO     2015-03-04 15:53:04,937 containers.py:280] ---> cd272a90bc21
INFO     2015-03-04 15:53:04,938 containers.py:280] Successfully built cd272a90bc21
INFO     2015-03-04 15:53:04,948 containers.py:292] --------------------------------------------------------
INFO     2015-03-04 15:53:04,948 containers.py:304] Image managedvm-project.default.2 built, id = cd272a90bc21
INFO     2015-03-04 15:53:04,948 containers.py:534] Creating container...
INFO     2015-03-04 15:53:05,104 containers.py:560] Container ef5775aa5d26ade2d524dd44d0cf6a18fa6c5c7aa100ccb3f925e3af30e5b72a created.
INFO     2015-03-04 15:53:06,407 module.py:1692] New instance for module "default" serving on:
http://localhost:8080

INFO     2015-03-04 15:53:06,435 module.py:737] default: "GET /_ah/start HTTP/1.1" 200 2
INFO     2015-03-04 15:53:06,435 health_check_service.py:101] Health checks starting for instance 0.

佈署Managed VM

如開發上一切都順利,接下來可以執行部屬的動作,透過docker preview app deploy來作佈署...

$ gcloud preview app deploy .
11:53 PM Host: appengine.google.com
{bucket: vm-containers.managedvm-project.appspot.com, path: /containers}

Updating module [default] from file [/private/tmp/test/app.yaml]
Pushing image to Google Cloud Storage...managedvm-project
Sending image list
Pushing repository gcr.io/_m_managedvm-project/managedvm-project.default.2 (1 tags)
Image 541923dd11eb already pushed, skipping
Image 11971b6377ef already pushed, skipping
...(skip)
Image b62c4c483651 already pushed, skipping
Pushing
Buffering to disk:  2.56 kB
Image successfully pushed===================================>]  2.56 kB/2.56 kB 0s
Pushing
Buffering to disk: 9.834 MB
Image successfully pushed===================================>] 9.834 MB/9.834 MB 0ss
Pushing
Buffering to disk: 2.629 MB
Image successfully pushed===================================>] 2.629 MB/2.629 MB 0ss1s
Pushing tag for rev [c7685fe2aad2] on {https://gcr.io/v1/repositories/_m_managedvm-project/managedvm-project.default.2/tags/latest}
11:54 PM Host: appengine.google.com
11:54 PM Application: managedvm-project (was: None); version: 2
11:54 PM
Starting update of app: managedvm-project, version: 2
11:54 PM Getting current resource limits.managedvm-project
11:54 PM Scanning files on local disk.
^@11:54 PM WARNING: Performance settings included in this update are being ignored because your application is not using the Modules feature. See the Modules documentation for more information. Python: https://developers.google.com/appengine/docs/python/modules/ Java: https://developers.google.com/appengine/docs/java/modules/ Go: https://developers.google.com/appengine/docs/go/modules/ PHP: https://developers.google.com/appengine/docs/php/modules/.
11:54 PM Cloning 291 application files.
11:54 PM Uploading 51 files and blobs.
11:55 PM Uploaded 51 files and blobs.
11:55 PM Starting deployment.
11:55 PM Checking if deployment succeeded.
11:55 PM Deployment successful.
11:55 PM Checking if updated app version is serving.
11:55 PM Will check again in 5 seconds.
...(skip)
11:57 PM Checking if updated app version is serving.
11:57 PM Enough VMs ready (1/1 ready).
11:57 PM Completed update of app: managedvm-project, version: 2

測試

當deploy完成後,則可以透過appengine的url規則(如下)來存取您的服務:

https://[your-project-id].appspot.com

進階

Managed VM提供scale的方法,設定上很簡單,只要在app.yaml中指定所要擴充的最高數量在"manual_scaling"中即可:

version: 2
runtime: custom
vm: true
api_version: 1

manual_scaling:
  instances: 5

handlers:
- url: /.*
  script: app.js

在使用manual_scaling時候,主機的調降需要由user自己動作,而如果在系統的設計上已經有考慮到交易的安全性,那使用全自動的scale方式也相當方便:

version: 2
runtime: custom
vm: true
api_version: 1

automatic_scaling:
  min_num_instances: 2
  max_num_instances: 20
  cool_down_period_sec: 60
  cpu_utilization:
    target_utilization: 0.5

handlers:
- url: /.*
  script: app.js

附註一

由於Google Managed VM改版,設定檔部分需要稍作調整,如果您看到下面這樣的訊息...

$ gcloud preview app deploy app.yaml
WARNING: The [version] field is specified in file [/path/to/your-project/app.yaml].  This field is not used by gcloud and should be removed.
ERROR: The version [test] declared in [/path/to/your-project/app.yaml] does not match the current gcloud version [20150428t143637].
ERROR: (gcloud.preview.app.deploy) Errors occurred while parsing the App Engine app configuration.

此時,您需要修改app.yaml,將"version: your-version"的部分移掉,重新執行deploy應該就可以正常deploy了!

附註二

筆者曾遇到Managed VM在Local執行時候連線到docker時候無法連線,錯誤訊息是因為SSL認證問題...,這時可以檢查您的Python是否為3.x或是2.7.9以上版本,如果是的話,可以試著透過brew將python移除,讓python版本回到2.7.6,或是透過您的方法將python版本降版到2.7.8以下,應該就可以正常執行部屬。

results matching ""

    No results matching ""