【GAE + CloudSQL + Rails】bundle exec rails appengine:exec -- bundle exec rails db:migrate時にCloudSQLで接続エラーになる
どうもてぃです。
今回始めてGAEを使います。
gemのwheneverがheroku上で使えなかったので、もういっそのことステージング環境を作ってしまい、あとからそのスナップショットで本番環境を作ろうと企んでいたところ、そもそも初っ端からつまづきました。
環境
まずは参考記事
いろんな記事やリファレンスを参考にしました。
Google App Engine から接続する | Cloud SQL ドキュメント | Google Cloud
Google Compute Engine(GCE)からCloud SQL接続でハマった - Qiita
RailsアプリをGAEにデプロイしCloudSQL, CloudStorageと連携させる - Qiita
GoogleAppEngine+CloudSQL(MySQL)+Rails5環境を作成する - Qiita
GAEにデプロイしたRailsからGoogle Cloud SQL に疎通できない時に確認すること - 俺、サービス売って家買うんだ
約一週間ほど溶かしました。。。
まだ完璧に解決したわけではないですが。
試したこと
Cloud SQLの有効化
こちらにアクセスしてCloud SQL
を有効化します。
ダッシュボードにきたら「APIとサービスの有効化」をクリック。
検索フォームが出てくるので、「Cloud SQL」と入力。
出てきたCloud SQLをクリックし、遷移先でAPIを有効化させたらおk(画像貼るのめんどくさくなった)。
Unixソケットでのプロキシ接続
以下の手順で接続しました。
環境が64bitのLinuxなので
https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64
をwgetする。
$ cd ~; wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy $ chmod +x cloud_sql_proxy $ sudo mkdir /cloudsql; sudo chmod 777 /cloudsql $ ./cloud_sql_proxy -dir=/cloudsql -instances=<INSTANCE_CONNECTION_NAME>
INSTANCE_CONNECTION_NAME
はgcloud sql instances describe [INSTANCE_NAME]
で出てくるconnectionName
を使います(INSTANCE_NAME
はCloudSQL
の名前)。
もしくはブラウザからGCPにアクセスして、プロジェクトのCloudSQL
で該当のSQLインスタンスを見ればわかると思います。
プロキシで接続すると、
2018/11/12 15:40:17 Rlimits for file descriptors set to {&{8500 1048576}} 2018/11/12 15:40:23 Listening on /cloudsql/<INSTANCE_CONNECTION_NAME>/.s.PGSQL.5432 for <INSTANCE_CONNECTION_NAME> 2018/11/12 15:40:23 Ready for new connections 。
と出てきます。
問題なく接続できてるようです。認証もできてるはず。
gcloudでsqlに接続してみる
CloudSQLにgcloudで接続してみます。
$ gcloud sql connect <INSTANCE_NAME> --user=<USER_NAME> Whitelisting your IP for incoming connection for 5 minutes...done. Connecting to database with SQL user [USER_NAME].Password for user <USER_NAME>: psql (9.5.14, server 9.6.6) WARNING: psql major version 9.5, server major version 9.6. Some psql features might not work. SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES128-GCM-SHA256, bits: 128, compression: off) Type "help" for help. USER_NAME名=>
うん、立ち上がります。
大丈夫そう。
ローカルからCloudSQLへマイグレーション
おそらく準備はある程度できているので(app.yaml
も環境変数も作った)、あとはappengine経由でマイグレーションするだけ。
デプロイも終わってる。
$ bundle exec rails appengine:exec -- bundle exec rails db:migrate ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ---------- CONNECT CLOUDSQL ---------- ERROR: Failed to start cloud_sql_proxy 2018/11/12 04:58:03 errors parsing config: googleapi: Error 403: The client is not authorized to make this request., notAuthorized ERROR ERROR: build step 0 "gcr.io/google-appengine/exec-wrapper:latest" failed: exit status 1 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ERROR: (gcloud.builds.submit) build 33763c5f-5791-490b-bade-8e3dda956688 completed with status "FAILURE" rails aborted! AppEngine::Util::Gcloud::GcloudFailed: GCloud failed with result code 1 /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/util/gcloud.rb:175:in `execute' /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/exec.rb:302:in `start' /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/tasks.rb:255:in `start_and_report_errors' /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/tasks.rb:155:in `block in setup_exec_task' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:23:in `block in perform' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:20:in `perform' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/command.rb:48:in `invoke' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands.rb:18:in `<main>' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require' /home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require' /home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency' /home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require' bin/rails:4:in `<main>' Tasks: TOP => appengine:exec (See full trace by running task with --trace)
なんで?
問題はこいつかな。
googleapi: Error 403: The client is not authorized to make this request., notAuthorized
IAM周りを見直し
とりあえずサービスアカウントが作成されているか確認しました。
<プロジェクトID>@appspot.gserviceaccount.com
があるかどうかブラウザで確認。存在してましたネ。
ちなみにgcloud projects get-iam-policy <PROJECT_ID>
で該当のプロジェクトのIAMが取得できます。
もうひとつ足りなかった
CloudSQL用のIAMで権限が足りないようでした。
以下の記事をちゃんと見なおしたら発覚。
qiita.com
<プロジェクト番号>@cloudbuild.gserviceaccount.com
に対してのroleが正しく割り当てられてませんでした。
なので、roleをEditor(編集者)
へ変更。
もう一度マイグレーションしてみる
$ bundle exec rails appengine:exec -- bundle exec rails db:migrate ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ・ ---------- CONNECT CLOUDSQL ---------- cloud_sql_proxy is running. ---------- EXECUTE COMMAND ---------- bundle exec rails db:migrate rails aborted! PG::ConnectionBad: could not connect to server: Connection refused Is the server running on host "localhost" (127.0.0.1) and accepting TCP/IP connections on port 5432? could not connect to server: Cannot assign requested address Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 5432? /app/vendor/bundle/ruby/2.5.0/gems/pg-1.1.3/lib/pg.rb:56:in `initialize' /app/vendor/bundle/ruby/2.5.0/gems/pg-1.1.3/lib/pg.rb:56:in `new' /app/vendor/bundle/ruby/2.5.0/gems/pg-1.1.3/lib/pg.rb:56:in `connect' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:684:in `connect' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:215:in `initialize' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:40:in `new' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:40:in `postgresql_connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:809:in `new_connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:853:in `checkout_new_connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:832:in `try_to_checkout_new_connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:793:in `acquire_connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:521:in `checkout' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:380:in `connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:1008:in `retrieve_connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_handling.rb:118:in `retrieve_connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/connection_handling.rb:90:in `connection' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/tasks/database_tasks.rb:172:in `migrate' /app/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.1/lib/active_record/railties/databases.rake:60:in `block (2 levels) in <main>' /app/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:23:in `block in perform' /app/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:20:in `perform' /app/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/command.rb:48:in `invoke' /app/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands.rb:18:in `<main>' /app/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require' /app/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi' /app/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register' /app/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi' /app/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require' /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require' /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency' /app/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require' bin/rails:4:in `<main>' Tasks: TOP => db:migrate (See full trace by running task with --trace) ERROR ERROR: build step 0 "gcr.io/google-appengine/exec-wrapper:latest" failed: exit status 1 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ERROR: (gcloud.builds.submit) build c15c595c-6d32-4aa0-9411-397d95b3f12e completed with status "FAILURE" rails aborted! AppEngine::Util::Gcloud::GcloudFailed: GCloud failed with result code 1 /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/util/gcloud.rb:175:in `execute' /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/exec.rb:302:in `start' /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/tasks.rb:255:in `start_and_report_errors' /home/user/project/vendor/bundle/ruby/2.5.0/gems/appengine-0.4.6/lib/appengine/tasks.rb:155:in `block in setup_exec_task' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:23:in `block in perform' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:20:in `perform' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/command.rb:48:in `invoke' /home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands.rb:18:in `<main>' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi' /home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require' /home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require' /home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency' /home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require' bin/rails:4:in `<main>' Tasks: TOP => appengine:exec (See full trace by running task with --trace)
一旦 googleapi: error 403
地獄から抜け出しました。
あとはPG::ConnectionBad
の解決のみ。
後日書きます。
追記
すぐに解決しました。
config/database.yml
のproduction
にhost
を設定してなかったせいでした。
app.yaml
構成はこんな感じです。
runtime: ruby env: flex entrypoint: bundle exec rackup --port $PORT skip_files: - ^vendor automatic_scaling: min_num_instances: 1 max_num_instances: 5 cool_down_period_sec: 120 cpu_utilization: target_utilization: 0.6 beta_settings: cloud_sql_instances: <INSTANCE_CONNECTION_NAME> threadsafe: true includes: - secret.yaml
secret.yaml
に必要な環境変数をセットしてます。
database.yml
のpasswordやhost、socketもここに書いてます。
database.yml
がこんな感じ。
・ ・ ・ ・ ・ ・ ・ ・ ・ production: <<: *default host: <%= ENV['POSTGRES_HOST'] %> database: <%= ENV['POSTGRES_DATABASE'] %> username: <%= ENV['POSTGRES_USER'] %> password: <%= ENV['POSTGRES_PASSWORD'] %> socket: <%= ENV['CLOUDSQL_STAGING_SOCKET'] %>
環境変数名が違いますが、 socket
と host
は同じで /cloudsql/<INSTANCE_CONNECTION_NAME>
をセットしてます。
host
を設定し、デプロイ後もう一度試したら念願のマイグレーションが通りました。
ホント長かった。
もうこの手順は忘れません。