えいのうにっき

a-knowの日記です

GAE/Go アプリケーションを Go 1.11 に移行するためにやったこと

先日公開した Web API サービス Pixelaは、Google App Engine 上で Go Web Application として動いている。Go のバージョンには特に気を使わずに開発をしてたんだけど、GAE で Go の 1.11 がサポート(まだ β だけど)されたこと、そして Go 1.11 であれば GAE Standard Environment で System Package として imagemagick が使えそう(svg → png 変換がしたい)ということもあって、Go 1.11 へのモチベーションが俄然上がったので、今回移行してみた。このエントリは、その際にやったことのまとめメモ。

Before

  • Go 1.9.4
  • パッケージ管理はなにもしてない状態(ひどい)

After

  • Go 1.11.1
  • パッケージ管理に Modules を使用

やったこと

goenv の導入、Go 1.11.1 のインストール

これまではずっと開発機に直接 Go をセットアップしてたんだけど、もし今回の移行が難しくなりそうだったらいつでも Go のバージョンを切り替えられるようにしておきたいなと思ったので、まずはこれから。

$ brew install goenv

以下は ~/.bash_profile などに追記。

export PATH="$HOME/.goenv/bin:$PATH"
eval "$(goenv init -)"

そして、Go 1.11.1 のインストール。

$ goenv install 1.11.1
$ goenv global 1.11.1
$ goenv versions
  system
* 1.11.1 (set by /Users/a-know/.goenv/version)

gcloud のアップデート

$ gcloud components update

app.yaml への変更

gist.github.com

api_version は deprecated とのこと。

init() から main() への書き換え

もともとは以下のようなコードを書いて置いていた。

gist.github.com

1.11 からは init() ではなくなるとのことなので、main() に変更。

Modules の導入

まず最初に、環境変数へのセットが必要。

export GO111MODULE=on

そして初期化。

$ go mod init

なんかこれだけだと、中身がほぼ空の go.mod ファイルができただけだったんだけど、ビルドとテストを実行したらそれっぽく設定できた。

$ go build
$ go test -v -cover .
$ cat go.mod
module github.com/a-know/pixela

require (
   github.com/favclip/testerator v0.0.0-20180606025010-04c1c0fc2a5a
   github.com/go-chi/chi v3.3.3+incompatible
   github.com/google/uuid v1.0.0
   github.com/pkg/errors v0.8.0
   go.mercari.io/datastore v1.3.0
   golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4 // indirect
   google.golang.org/api v0.0.0-20181026000445-511bab8e55de // indirect
   google.golang.org/appengine v1.2.0
)

appengine.Main() の呼び出しの追加

ここまでの対応で動くかなと思ったんだけど、Datastore に読みにいくところで The process handling this request unexpectedly died. This is likely to cause a new process to be used for the next request to your application. (Error code 203) というエラーになってしまっていた。

いろいろ調べたところ、結論としては google.golang.org/appengine パッケージを使っている場合には main パッケージで appengine.Main() を呼び出す必要があるようだった。

gist.github.com

公式ドキュメントの Quick Start は最低限の構成すぎて、Datastore とかへのアクセスが無くこの呼び出しも省略されてしまっていた。。

これにより、アプリケーションがちゃんと動くようになったことを確認できた。

Go 1.11 への単純移行は簡単

結局、app.yaml やコードへのほんのちょっとの変更と、Modules の導入くらいで簡単に移行できてしまった。今のところ順調に動いている。

ただ、Migrating your App Engine app from Go 1.9 to Go 1.11We strongly recommend using the Google Cloud client library or third party libraries instead of the App Engine-specific APIs. とあるけれど、今回これに対しては特になにもしておらず、引き続き google.golang.org/appengine パッケージを使っている。

特に Datastore へのアクセス周りは Access Cloud Datastore through the datastore package. とあるように、 datastore パッケージを使うようにしなければいけないんだろうけど、ちょっとそれはまた別の機会にしっかり腰を据えて取り組んでみようと思っている(go.mercari.io/datastore を使っているから、若干ラクだったりするかな......とか思ったりもしている)。

なので今回は本当に単純に、Go 1.11 ランタイムで動かすようにしました、という、それだけ。

追記(2018-10-30)

GAE/Go アプリケーションを Go 1.11 に移行するためにやったこと - えいのうにっき

僕は11/1以降に一回トライしてみる予定(試すだけ試して多分レスポンスが悪化するのでapplyはしない予定

2018/10/29 18:28
b.hatena.ne.jp

そう。移行をして数日経って、ダッシュボードを眺めていると、どうも微妙に効率が落ちている気はしていた。

スピンアップするインスタンス数も、普段より1,2台多いかんじ。僕は上述のとおり、System Package として imagemagick が使えそうというメリットがあるためもう少し様子をみたいと思うけど、特にそういったメリットがない人は 1.11 への移行は少し様子を見てもいいかもしれない。

追記(2018-11-03)

今日、何気なくデプロイしようと思ったら、今まで出てなかったはずの ERROR: (gcloud.app.deploy) INVALID_ARGUMENT: script field for handler '/heartbeat' must be set to 'auto' for runtime go111. というエラーが出てデプロイできなくなっていた。

適当にググっても特にこれといって情報は出てこなかったので、高度な勘を働かせ、app.yaml の以下の記述を、

- url: /heartbeat
  script: _go_app
  secure: always

以下のように変更することでデプロイできるようになった。

- url: /heartbeat
  script: auto
  secure: always

これがβリリースか......!ってなったけど、まぁ解決したのでよかった。

おまけ

便利。

参考