2017年7月9日日曜日

GAE環境下でのペンドリングとデプロイ

前回記事(GAE環境下での Echoフレームワークのエラー)で、EchoフレームワークはGAE(GoogleAppEngine)環境下ではバージョン指定をするという話を書きました。今回は続編で、Go言語の機能であるベンドリング(vendoring)を利用し、もっと簡単にパッケージ管理を行います。さらにベンドリング使用時、GAEデプロイに関する注意点も書いていきます。
ベンドリングと Glide
ペンドリング(Vendoring)は、プロジェクト毎の外部ライブラリを管理する仕組みです。Go言語バージョン1.5から利用可能になりました。

簡単に解説すると、プロジェクトのディレクトリに vendorというディレクトリを作成し、vendor下にプロジェクトで使用する外部ライブラリーを配置します。これにより利用するライブラリを、プロジェクト毎に管理することができます。


このペンンドリングを簡単に管理できる、パッケージ管理ツールが幾つかあります。有名なツールを挙げます(☆はgithubの星の数)。 最も有名なのは Godep のようです、Go言語がベンドリングに対応する前からあるそうです。古いので環境を汚したりとか、最近あまり更新されない等あるそうです。そして最も人気なのは、Glide です。機能範囲も最も大きいいようです。今回は Glide を使用します。
参考:Go Package Manager Comparison

Glideの使用方法は、いろいろなところで解説されています。詳しい解説は、そちらを参考にしてください。

参考
Go言語 / golang 入門 必見!! パッケージ管理ツール Glideの使用方法を詳しく解説
【GO言語のパッケージ管理:決定版】「Glide」を使ってみよう

まず Glideをインストールします。マシンはMacですので、brew でインストールします。

$ brew install glide

次にGlideの設定ファイル(glide.yaml)を作成するため、プロジェクトのディレクトリで次のコマンドを実行します。

$ glide create

実行すると、いろいろ設定ウィザードが表示されます。取り敢えず最初のウィザードで No(N) を選ぶと、プロジェクトを検索し依存関係を記述した glide.yaml を生成します。 生成した glide.yaml は、次のようになります。

package: sample
import:
- package: github.com/labstack/echo
  subpackages:
  - middleware

ここで、依存するパッケージは github.com/labstack/echo なのを確認します。またバージョンを 3.0.2 に指定する必要があるので、次のようにversionを記述します。

package: sample
import:
- package: github.com/labstack/echo
  version: 3.0.2
  subpackages:
  - middleware

vendorディレクトリを作成し、依存するライブラリをインストールします。

$ glide install

ライブラリはインストールされましたが、指定したバージョンはまだインストールされていません。ここでライブラリのアップデートを行います。

$ glide up

これによって、バージョン3.0.2が設定されました。

ペンドリング使用時のプロジェクトの位置
GAEのベンドリング使用時、プロジェクトのディレクトリは GOPATH 配下に設置する必要があります。GOPATH下でない場合、vendorディレクトリが GAEのSDKで認識されないようです。

※ プロジェクト下のファイルは、EchoフレームワークのGAEレシピで紹介されたサンプルです(Google App Engine Recipe)。
プロジェクトのディレクトリでターミナルを開いて、ローカル開発用サーバを起動してみましょう。

$ dev_appserver.py app.yaml

エラー無く、稼働できることを確認できると思います(EchoフレームワークのGAEレシピのサンプルデータ一覧URLは、http://localhost:8080/users になります)。

GAEへのデプロイ
GCLOUDコマンド(参考:Google Cloud SDK への移行)で、ベンドリングしたアプリをGAEにデプロイしようとするとエラーで処理が止まります。具体的には次のようなエラーが表示されます。
$ gcloud app deploy app.yaml --version 1
Services to deploy:
:::: 省略 :::::
Updating service [default]...failed.                                                                                             
ERROR: (gcloud.app.deploy) Error Response: [9] Deployment contains files that cannot be compiled: Compile failed:
2017/07/08 18:00:00 go-app-builder: Failed parsing input: parser: bad import "syscall" in vendor/golang.org/x/sys/plan9/env_unset.go

このエラーに関しては、GAEの設定ファイル(app.yaml) に次のようにデプロイしないライブラリを指定すると良いそうです。

nobuild_files:
- vendor
参考:golang環境でFailed parsing input: parser: bad import "syscall" というエラーが出るときのメモ

しかし再度コマンドを発行すると、同様のエラーが出てデプロイが失敗します。

現状ではGCLOUDコマンドは、上手くベンドリングに対応していないようです。このため一つ前のツールである、GOAPPを使用します。GOAPPは brew でもインストール可能なようです。

$ brew install goapp

ダンロードで goappツールを導入する場合は、GAE SDK ダンロードページOr, you can download the original App Engine SDK for Go. から行います。

そしてデプロイします。

$ goapp deploy -application sample -version 1 app.yaml
デプロイが成功しました。

※ GAEの設定ファイル(app.yaml) の nobuild_files が無い場合、goappでも同様のエラーが出ますので、記述する必要があります。

最後に
GOPATH下にプロジェクト・ディレクトを設置する場合、シンボリックリンクを検討することもあるかと思います。シンボリックリンクでの設置では、デプロイは可能ですが、なぜか開発用サーバはエラーが出て起動できません。この辺、注意してください。

GAE SDK for Go は、Goの機能に追いついていない所や動作がおかしな点があるのかもしれません。一応、現状でまとめてみました。


※追記(2017/07/28)
6月末にリリースされた SDK 1.9.55 以降、Go1.8をベータサポートしているそうです。このため、app.yaml の api_versionを次のように指定すると、ベンドリングを使用しなくても Echoフレームワークが動作します。

api_version: go1.8
ただし、ローカル開発用サーバでは現在動作しません。またデプロイには、GCLOUDコマンドではなく、GOAPPコマンドを利用する必要があります。