Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vochicong/6f01618be5aae42b9e71be4cfbca9be4 to your computer and use it in GitHub Desktop.
Save vochicong/6f01618be5aae42b9e71be4cfbca9be4 to your computer and use it in GitHub Desktop.
Libraries not found in GCP Docker when CircleCI deploying to GCP App Engine

CircleCI, GCP App Engineでライブラリが見つからないエラー

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されていないものを含めて、 全てデプロイしてしまう。

下記、まず先に解決方法を記載し、その後、どう調査したかも残しておく。

解決

Deployする前のクリーニング

CircleCIがテストのために使ったファイルを一掃:

git --no-pager diff
git reset --hard
git clean -d -x -f
git status

CircleCIのbundleのpathを変更

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-devmysql2 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は、その限りではない。

References:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment