GCPのAppEngineでRedmineを起動したときのメモ


はじめに

職場でRedmine使って色々管理している流れで、ちょっと自宅でお試し環境を作りたくなり、ついでにGCPのAppEngineも試したかったので、AppEngine上でRedmineを実行してみた際の手順をまとめてみました。

参考

環境

  • ローカルにgcloudコマンドラインツールを入れるのが面倒だったので、GCPのコンソールから支えるCloudshellから操作を行いました。
  • データベースにはCloud SQLを使って構築したPostgreSQL11を使っています。
  • mysqlを使わなかった理由: Cloud Shell環境でgem install mysql2が失敗したから。(mysql-develが必要なのだが、Cloud Shell環境にインストールするのは難しそうだとハナから諦めました。)
  • AppEngineはFlexible環境を使いました。
  • 標準環境を使わなかった理由: Ruby2.5の環境がなかったから。

手順

まずは、プロジェクトを作成します。

Cloud Shellなら、gcloudコマンドがすぐに使えて楽。

shell
# ここでは"testtest-001"という名前のプロジェクトを作っています。
gcloud projects create testtest-001 --name testtest-001

# 作ったら、カレントプロジェクトに設定してあげます。
gcloud config set project testtest-001

次に、データベースのインスタンスを作成

PostgreSQL 11のインスタンスには仮想サーバのサイズ指定が必要とのことで、cpuとmemoryサイズを指定しています。(1cpu, 4GB memoryにしておきました。)

shell
gcloud sql instances create test-redmine-001 --no-backup --database-version=POSTGRES_11 --root-password=PASSWORDYYYYMMDD --region=asia-northeast1 --cpu=1 --memory=4G

できたか確認します。

shell
gcloud sql instances describe test-redmine-001

一応、コンソールからも確認してみたところ、
「課金を有効にしますか?」
的な事を聞かれます。
躊躇したくなりますが、無料トライアル期間中なので、OKしてしまった。
(無課金では試せません。あしからず。。)

Cloud SQL APIを有効にします。

全てコマンドでできました。

shell
# まず、Cloud SQL Admin APIのサービス名を確認
gcloud services list --available | egrep "SQL"

# => 結果から、sqladmin.googleapis.comをコピーしまして。

# まず、Cloud SQL Admin APIを有効化
gcloud services enable sqladmin.googleapis.com

# => 以下のような結果になればOK
# Operation "operations/[なんかのID]" finished successfully.

続いてCloud Build APIも有効化します。

SQL Admin APIの際とほとんど似たような手順(名前を確認して有効化)ですね。

shell
gcloud services list --available | egrep "build"
=> cloudbuild.googleapis.com
gcloud services enable cloudbuild.googleapis.com

そしたら、CloudBuildのサービスアカウントに編集者権限を付与

ここ、Cloud Build APIを有効化しておかないと、「そんなアカウントはありません」エラーとなりますのでご注意を。

shell
gcloud projects add-iam-policy-binding [プロジェクトID] --member=serviceAccount:[プロジェクト番号()]@cloudbuild.gserviceaccount.com --role=roles/editor

# 例
# gcloud projects add-iam-policy-binding testtest-001 --member=serviceAccount:[email protected] --role=roles/editor

# ※プロジェクト番号は以下のコマンドの結果で調べられます。(一番右の数字。。PROJECT_IDじゃないので気をつけましょう。)
gcloud projects list
# 出力例>
# PROJECT_ID    NAME          PROJECT_NUMBER
# testtest-001  testtest-001  123456789012
# testtest-003  testtest-003  345678901234

いよいよ、redmineの本体を準備。

まずはgithubからredmine本体を取得。

shell
# githubからcloneします。
git clone https://github.com/redmine/redmine.git

そしてdatabase.ymlの設定

shell
# redmineのディレクトリに移動
cd redmine
# database.yml.exampleをコピーしてdatabase.ymlを作る(自信ある方はゼロから作っても大丈夫。)
cp config/database.yml.example config/database.yml

# コピーできたら、database.ymlの編集です。
# production環境の接続設定だけいじりました。
vi config/database.yml
# 中身は次のセクションを参照してください。

database.ymlの中身はこちら。

database.yml
production:
  adapter: postgresql
  database: redmine
  host: '/cloudsql/testtest-001:asia-northeast1:test-redmine-001'
    # <= "/cloudsql/" に
   # <= "gcloud sql instances describe インスタンス名"で取得したconnectStringの値をつなげるのです。
  username: postgres
  password: "PASSWORDYYYYMMDD" # <= postgresユーザのパスワード

次、デプロイに便利なappengineを追加

appengineはGCP環境にrubyアプリをデプロイするための便利Gemです。
bundle addしてから、bundle installします。

shell
# まずはappengineをGemfileに追加。(直接編集しても良い。)
bundle add appengine

# そして、bundle installといきます。
# (これやらなかったら、あとのデプロイ(gcloud app deploy)で失敗した。。)
bundle install

そして、appengineにデプロイしてもらうためのapp.yamlを作ります。

チュートリアルには作る場所がはっきり書かれてない気がしますが、アプリケーションのルートディレクトリに作ります。
(githubからクローンした人は、redmineディレクトリ直下です。)

app.yaml
# まずはチュートリアルからもらった内容をそのまま書いてしまいます。
entrypoint: bundle exec rackup --port $PORT
env: flex
runtime: ruby

env_variables:
  SECRET_KEY_BASE: [SECRET_KEY]

beta_settings:
  cloud_sql_instances: [YOUR_INSTANCE_CONNECTION_NAME]

そして、上のファイルの[SECRET_KEY]を以下のコマンドの結果で上書きします。

shell
bundle exec rails secret

# 出力例=>
881cf9bd..... 長いのとセキュリティ上良くないので以後省略。。すみません。

さらに、[YOUR_INSTANCE_CONNECTION_NAME]
をインスタンス接続名で上書き。
(/cloudsql/は書きません。)

以下実際に設定してみたサンプルです。

app.yaml
# 実設定入れてみた感じ。
entrypoint: bundle exec rackup --port $PORT
env: flex
runtime: ruby

env_variables:
  SECRET_KEY_BASE: 881cf9bd.....(本当はすげー長い。)

beta_settings:
  cloud_sql_instances: testtest-001:asia-northeast1:test-redmine-001

ようやくAPP Engineを作ってデプロイ!

こちらもコマンドで。
今回の手順、コンソールを使う作業はほとんど行いませんでした。

shell
gcloud app create --region=リージョン名(ap-northeast-1などなど)
# --regionを指定しない場合は、途中で聞かれます。
# 仕掛けて、トイレ行って戻ったときに終わってなくてがっかりしました。

できたかな?
できたら、デプロイ!!(急ぎすぎですが、大丈夫。)

shell
gcloud app deploy
# 途中で確認画面が出ますので元気に"Y"で答えましょう。

そして一度失敗を経験する。

先ほどのコマンドですが、最後必ず失敗します。

deploy-error
Updating service [default] (this may take several minutes)...failed.
ERROR: (gcloud.app.deploy) Error Response: [9]
Application startup error! Code: APP_CONTAINER_CRASHED
bundler: failed to load command: rackup (/app/vendor/bundle/ruby/2.6.0/bin/rackup)
ActiveRecord::NoDatabaseError: FATAL:  database "redmine" does not exist

# => そりゃそうだよ、redmineなんていうデータベース作ってないもん。

気を取り直してDBの準備。

失敗しても落ち込む暇はないのです。
DBを準備しましょう。

shell
# まずはデータベースを作成
bundle exec rails appengine:exec -- bundle exec rails db:create

# 出力例
# ---------- CONNECT CLOUDSQL ----------
# cloud_sql_proxy is running.
# 
# ---------- EXECUTE COMMAND ----------
# bundle exec rails db:create
# Created database 'redmine'
# 
# ---------- CLEANUP ----------
# PUSH
# DONE
#
# 次にテーブルの作成など。
bundle exec rails appengine:exec -- bundle exec rails db:migrate

# 出力例
# ---------- CONNECT CLOUDSQL ----------
# cloud_sql_proxy is running.
# 
# ---------- EXECUTE COMMAND ----------
# bundle exec rails db:migrate
# 
# ...ここから、create table結果の嵐。
# 
# ---------- CLEANUP ----------
# PUSH
# DONE
#

# んで、デフォルトデータの投入(これやらないと使い物にならんですね。redmine)
bundle exec rails appengine:exec -- bundle exec rails redmine:load_default_data REDMINE_LANG=ja
# <= コマンドの後ろに"REDMINE_LANG=ja"で使用言語を設定しているところがミソ。
# <= 。。。無いとプロンプトが返されるみたいでタスクが失敗します。

# 出力例
# ---------- CONNECT CLOUDSQL ----------
# cloud_sql_proxy is running.
# ---------- EXECUTE COMMAND ----------
# bundle exec rails redmine:load_default_data REDMINE_LANG=ja
# Default configuration data loaded.
# ---------- CLEANUP ----------
# PUSH
# DONE

隊長!起動準備が整いました。

  • アプリケーションはエラーを起こしながらもデプロイはできた。
  • データベースインスタンスを起動して、redmine用のデータベースもできた。
  • データベースのテーブル作成もできた。
  • デフォルトデータも投入した。

ということで、起動準備完了。
先ほどデプロイに失敗したやつを起動して差し上げます。

shell
# まずはサービスの状態を確認。
> gcloud app versions list
# 出力例(STOPPEDになってますね。)
# SERVICE  VERSION.ID       TRAFFIC_SPLIT  LAST_DEPLOYED              SERVING_STATUS
# default  20200412t165521  1.00           2020-04-12T11:00:15+09:00  STOPPED

# そしたら、起動
> gcloud app versions start 20200412t165521

# 出力例
# Starting the following versions:
#  - testtest-001/default/20200412t165521
Do you want to continue (Y/n)?  Y <= 続けてよいか聞かれるのでYを答える。

# Waiting for operation [apps/testtest-001/operations/349e4332-2923-40de-a840-12f034daa670] to complete...done.

隊長!お気を確かに!!

!!やった起動成功!!!と誰もが思います。
早速、ページが開けるかみてみましょう。
ページのアドレスは以下のコマンドで確認できます。

shell
gcloud app services browse default --no-launch-browser

# 出力例
SERVICE  URL
default  https://testtest-001.an.r.appspot.com

ブラウザにアドレスをコピペして。。。
表示!!でき。。ない。
・・・Temporary Unavailable的なメッセージが。。
・・・30秒後にもう一回来いとな。

任務完了

ということで、念のため1分待ってからもう一回アクセス。
やっと会えた!

ハマったことまとめ。

  • サービス起動してからページが開けるようになるまでに、結構時間がかかるのを知らず、最初は非常に焦って、色々調べてしまいましたが、「待てば良い」それだけでした。
  • 他にも、API有効化してから使えるようになるまで、タイムラグがある感じがします。ので、「ちょっと待ってみる」気持ちの余裕が必要かと。
  • 当初、Cloud ShellはApp Engineの実行環境ではない。というのになかなか気がつかず(お恥ずかしい。。)、プロジェクト移動したのに同じディレクトリが見えるのが「何かの間違い」だと思い込み、無駄な時間を過ごしました。
  • ドキュメントページに用意されているチュートリアルを試さずに始めてしまったので、理解に時間がかかりました。やはり、チュートリアル素晴らしい。