Perl Mojolicious Framework on Google App Engine Managed VMs


PaaS サービスの [Google App Engine](https://cloud.google.com/appengine/) には、現状 beta だが [Managed VMs](https://cloud.google.com/appengine/docs/managed-vms/) という機能が備わっている。これは App Engine のプラットフォーム上で Docker コンテナを動かすもので、実質的には App Engine 上で任意の言語を用いて開発できることを意味する。実際、 Google も [nodejs を展開するサンプルを公開](https://cloud.google.com/solutions/nodejs/)しており、比較的手軽に動かすことができた。

そこで試しに、 Perl の Mojolicious フレームワークを App Engine 上に展開し実行してみた。

# 今すぐ試す

ツール類（docker とか gcloud とか GCP のプロジェクトとか）は準備しておいて下さい。

    $ git clone git@github.com:aql/perl-appengine-sample.git
    $ cd perl-appengine-sample
    $ gcloud preview app --project "foo-bar" deploy .

かんたん。

# Managed VMs の仕様

任意の言語を動かす際には Custom Runtime を利用する。このとき、 App Engine はアプリケーション実行に関して何らサポートを行わないので、 App Engine 側とやりとりするために、幾つかのルールを守ってやる必要がある。

* <https://cloud.google.com/appengine/docs/managed-vms/custom-runtimes#developing_code_for_custom_runtimes>

とりあえずテストなので

* アプリケーションは 8080 番ポートを Listen する
* /_ah/* でヘルスチェックの応答をする

というだけをやってある。 [GoogleCloudPlatform/appengine-nodejs-quickstart](https://github.com/GoogleCloudPlatform/appengine-nodejs-quickstart.git) を真似ただけ。

# ランタイム Dockerfile

アプリケーション付属の Dockerfile 一発で良いと思うが、 [google/nodejs](https://registry.hub.docker.com/u/google/nodejs/), [google/nodejs-runtime](https://registry.hub.docker.com/u/google/nodejs-runtime/) を真似て、ランタイム部分の設定を分けてみる。

    FROM google/debian:wheezy
    
    RUN apt-get update -y && apt-get install --no-install-recommends -y -q curl python build-essential git ca-certificates
    RUN mkdir /perl
    RUN curl https://raw.githubusercontent.com/tokuhirom/Perl-Build/master/perl-build | perl - 5.20.2 /perl
    
    ENV PATH /perl/bin:$PATH
    
    RUN curl -L https://cpanmin.us | perl - App::cpanminus
    RUN cpanm Carton
    
    RUN mkdir /app
    WORKDIR /app
    
    ONBUILD ADD cpanfile /app/
    ONBUILD RUN carton install
    ONBUILD ADD . /app
    
    EXPOSE 8080
    CMD []
    ENTRYPOINT ["carton", "exec", "--", "perl",  "/app/app.pl"]
    
    
* perl-build で perl をインストール
* cpanm をインストール
* Carton をインストール

[hiko/perl-runtime:1.0 として Docker Hub に入れておいた](https://registry.hub.docker.com/u/hiko/perl-runtime/)。

これをベースにして docker build すると、同ディレクトリ内の cpanfile を読み込んで carton install し、その後同ディレクトリ内をコンテナ内に展開する、という動作をする。 ONBUILD すごい。

# アプリケーション

アプリケーションを作る。リポジトリは [GitHub](https://github.com/aql/perl-appengine-sample) をご覧ください。

## app.yaml

    version: 1
    runtime: custom
    vm: true
    api_version: 1
    
    manual_scaling:
      instances: 1
    
    handlers:
    
    - url: /(.*\.(html|css|js))
      static_files: static/\1
      upload: static/(.*\.(html|css|js))
    
    - url: /favicon.ico
      static_files: static/favicon.ico
      upload: static/favicon.ico
    
    - url: /.*
      script: app.pl

まるでルーティング定義で app.pl を呼びそうな config だが、 static 配信設定でないものは全て単純に 8080 番に飛ばされそうな予感がする（ので app.pl でもなんでも良い気がする）。

## Dockerfile

    FROM hiko/perl-runtime:1.0

さっきのベースになるコンテナを指定しているだけだが、直書きしても良い。

## cpanfile

    requires 'Mojolicious';

## app.pl

    use Mojolicious::Lite;
    
    get '/' => { text => 'Hello world from Perl!' };
    
    get '/_ah/health' => { text => 'ok' };
    get '/_ah/start' => { text => 'ok' };
    get '/_ah/stop' => sub {
        my $self = shift;
        $self->render( text => 'ok' );
        exit;
    };
    
    app->start( 'daemon', '-l', 'http://*:8080' );


# デプロイ

## ローカル実行

    $ gcloud preview app run .
    
一瞬難なく立ち上がったように見えるが、 localhost:8080 で Listen し始めたよメッセージの **あとで** Docker コンテナのビルドをやっているので、少し気長に待つのが良い。
    
## デプロイ

    $ gcloud preview app deploy .

# その他のいろいろ

[ログはどこに出すと良いとか、いろいろ書いてありますので、読みましょう](https://cloud.google.com/appengine/docs/managed-vms/custom-runtimes#developing_code_for_custom_runtimes)。

「いろいろ」と書いた割に、要求は大して多くない。

# 結論

うごきます。かんたんに。

# 細かい話

Managed VMs は GAE で Docker コンテナを動かす、と書いたけれど、細かく言うと多分以下のような感じだと思う。

* Managed VMs は GAE 環境を GCE 上に展開する
* これにより GAE 環境を拡張して使いたい要望に応えられる
* その一環として Docker コンテナを動かすことも出来る

# なぜ GAE か？

自動スケールが手軽にできるとかいろいろありますが、結局は **そこに山があるからです。**

# 今後の展望

今回は Mojolicious を動かしたが、見ればわかる通り、たぶん「ルール」さえ守れば、なんでも動かせそう。

Enjoy!