CircleCIからGCP App EngineへRailsアプリをデプロイする際、GCP Docker内で
bundle exec rake assets:precompile
が実行される時に
libmysqlclient.so.20が見つからないエラーが出て、大変苦戦した。
CircleCIは、deploymentフェーズの前に、testフェーズなどで
色々とやってくれているので、git commit
されていない(deployには余計な?)
ファイルがcurrent folderに大量生成される。
GCP App Engineのデプロイツールgcloud app deploy
は、
current folderの内容を、git commit
されていないものを含めて、
全てデプロイしてしまう。
下記、まず先に解決方法を記載し、その後、どう調査したかも残しておく。
CircleCIがテストのために使ったファイルを一掃:
git --no-pager diff
git reset --hard
git clean -d -x -f
git status
circle.ymlで設定。
dependencies:
pre:
- gem install bundler
override:
# Don't use --path=vendor/bundle because it will be copied to GCP App
- bundle install --clean --with="test" --without="development production"
開発環境C9 IDEではうまくgcloud app deploy
できるのに、
GitHubにプッシュしたら、CircleCIでdeployがこけたのですが、
理由がなかなか分からなかった。
GCP App Engine用のDockerがビルドされる時に、GCP BUILD OUTPUTに libmysqlclient.soが見つからないというようなエラーが出る。 以下、Ruby 2.3.4を指定した場合のエラーを示しますが、Ruby 2.3.0, 2.4.0, 2.4.1を試しても同様でした。
Step 8 : RUN if test -d app/assets -a -f config/application.rb; then bundle exec rake assets:precompile || true; fi
rake aborted!
LoadError: libmysqlclient.so.20: cannot open shared object file: No such file or directory - /app/vendor/bundle/ruby/2.3.0/gems/mysql2-0.3.21/lib/mysql2/mysql2.so
/app/vendor/bundle/ruby/2.3.0/gems/mysql2-0.3.21/lib/mysql2.rb:31:in `require'
/app/vendor/bundle/ruby/2.3.0/gems/mysql2-0.3.21/lib/mysql2.rb:31:in `<top (required)>'
/app/config/application.rb:7:in `<top (required)>'
/app/Rakefile:4:in `require_relative'
/app/Rakefile:4:in `<top (required)>'
/app/vendor/bundle/ruby/2.3.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)>'
/rbenv/versions/2.3.4/bin/bundle:22:in `load'
/rbenv/versions/2.3.4/bin/bundle:22:in `<main>'
(See full trace by running task with --trace)
前段のGCP BUILD OUTPUTを見ると、
Step 6 : RUN if test -f Gemfile.lock; then bundle install --deployment --without="development test" && rbenv rehash; fi
---> Running in f46082285539
Don't run Bundler as root. Bundler can ask for sudo if it is needed, and
installing your bundle as root will break this application for all non-root
users on this machine.
Fetching gem metadata from https://rubygems.org/.........
Fetching version metadata from https://rubygems.org/..
Fetching dependency metadata from https://rubygems.org/.
Using rake 12.0.0
Using concurrent-ruby 1.0.5
Using i18n 0.8.1
Using minitest 5.10.1
ここのUsing
が怪しい。本来ならば、Installing
を期待する。
最初は、GCP Ruby dockerが巧妙に
gemsを蓄えているのだと思ったのだが、よく考えるとそんなことはやるはずがない。
Dockerfileを見ても怪しいところはなく、
libmysqlclient-devがちゃんとインストールされている。
つまり、libmysqlclient-dev
とmysql2 gem
が組み合わさっていなくて、
libmysqlclient-dev
のDockerでインストールされていたら、
mysql2 gem
がCircleCIから混入したと怪しまれる。
こうなったら、BUILD OUTPUTを熟読するしかないと覚悟しつつありました。 先頭から凝視すると:
----------------------------- REMOTE BUILD OUTPUT ------------------------------
starting build "XXXXXXXXXX"
FETCHSOURCE
Fetching storage object: gs://XXXXXXXXXX.appspot.com/asia.gcr.io/XXXXXXXXXX/appengine/XXXXXXXXXX:latest#XXXXXXXXXX
Copying gs://XXXXXXXXXX.appspot.com/asia.gcr.io/XXXXXXXXXX/appengine/XXXXXXXXXX:latest#XXXXXXXXXX...
|
Operation completed over 1 objects/44.0 MiB.
BUILD
Already have image (with digest): gcr.io/cloud-builders/docker
Sending build context to Docker daemon 127.1 MB
上の 127.1 MB は大きいすぎる!
開発環境からデプロイするときはこんなもん:
Operation completed over 1 objects/133.0 KiB.
BUILD
Already have image (with digest): gcr.io/cloud-builders/docker
Sending build context to Docker daemon 865.8 kB
つまり、865.8 kBくらいが正常なのだ。
やはり、CircleCIから何かしら想定外のデータをGCP App Engineに送りつけているのだ。
次に、CircleCIの依存解決で使われた、標準的なbundleコマンドを確認する。
bundle install --path=vendor/bundle
つまり、gemsがcurrent folderの./vendor/bundleにインストールされ、 その結果、GCP App EngineのDockerにコピーされてしまったのだ。
AWS EBのデプロイツールeb deploy
は、通常git commit
されてものしかデプロイしない。
Herokuへのデプロイは、git push
で行うので、当然git commit
されてものしかデプロイしない。
AWS EBとHerokuは、gitでバージョン管理されているものしかデプロイできないのに対して、 GCP App Engineは、その限りではない。