2014年3月13日木曜日

[heroku][yesod] Heroku上でSQLiteを使ってはいけない

HerokuでSQLiteを使ってはいけない理由

なぜHerokuでSQLiteを使ってはいけないか。理由は以下の2つです。
  • HerokuのCedar Stackはephemeral filesystemを持っており、一見ファイルの読み書きができるように見えるが、一日に一度すべてクリアされる。このためSQLiteで保存したデータも毎日失われてしまう。
  • もしHerokuのファイルシステムが永続的にデータを保持したとしても別の問題がある。SQLiteはサービス機能を持っていないため各dynoの間でデータを共有することができず、それぞれ固有のDBを保持しているように振る舞ってしまう。
HerokuサイトのLearning - Application Architectureで公開されているSQLite on Herokuに詳細が説明されています。SQLiteの代わりにアドオンで提供されているPostgreSQL、MySQL、MongoDBなどを使うことになります。
今回YesodチュートリアルのYosogアプリで利用するデータベースをSQLiteからPostgreSQLに移行しました。その手順を紹介しておきます。

ローカル(mac)環境でのPostgres対応

まずローカル環境で動作しないことにはサーバ上で動作するはずがない、ということで、mac上のDevelopment環境でPostgreSQLを利用する手順を記載しておきます。
Yesodチュートリアルのサンプル(Yosogアプリ)をローカル環境でPostgreSQL上で動作させるには以下の修正が必要でした。yesod initコマンド実行時に利用DBとしてsqliteでなくpostgresqlを選択すれば、ここで述べるのSQLiteからPostgreSQLへの変更手順は不要になります。
  1. SQLite環境をPostgreSQL環境に変更
    1. Application.hsのdbconfをSQLiteからPostgreSQLに
    2. 
      -     dbconf <- withYamlEnvironment "config/sqlite.yml" (appEnv conf)
      +     dbconf <- withYamlEnvironment "config/postgresql.yml" (appEnv conf)
      
      
    3. Settings.hsのPersistentConfをSQLiteからPostgreSQLに
    4. (その1)
      
      -import Database.Persist.Sqlite (SqliteConf)
      +import Database.Persist.Postgresql (PostgresConf)
      
      
      (その2)
      
      -type PersistConf = SqliteConf
      +type PersistConf = PostgresConf
      
      
    5. Yosog.cabalのbuild-dependsをpersistent-sqliteからpersistent-postgresに
    6. (その1)
      
      -                 , persistent-sqlite             >= 1.3        && < 1.4
      +                 , persistent-postgresql         >= 1.3        && < 1.4
      
      
      (その2)
      
      -                 , persistent-sqlite
      +                 , persistent-postgresql
      
      
    7. config/postgresql.ymlの準備
    8. 
      Default: &defaults
        user: Yosog
        password: Yosog
        host: localhost
        port: 5432
        database: Yosog
        poolsize: 10
      
      Development:
        <<: *defaults
      
      Testing:
        database: Yosog_test
        <<: *defaults
      
      Staging:
        database: Yosog_staging
        poolsize: 100
        <<: *defaults
      
      Production:
        database: Yosog_production
        poolsize: 100
        <<: *defaults
      
      
  2. MacPortsでpostgresql93をインストールする
    1. postgresql93パッケージをインストール
    2. 
      % sudo port install postgresql93
      % sudo port install postgresql93-server
      % sudo port select postgresql postgresql93
      
      
    3. DBインスタンスの生成(serverのinstall時の指示に従う)
    4. 
      % sudo mkdir -p /opt/local/var/db/postgresql93/defaultdb
      % sudo chown postgres:postgres /opt/local/var/db/postgresql93/defaultdb
      % sudo su postgres -c '/opt/local/lib/postgresql93/bin/initdb -D /opt/local/var/db/postgresql93/defaultdb' 
      
      
    5. サーバーの起動
    6. 
      % sudo launchctl load -w /Library/LaunchDaemons/org.macports.postgresql93-server.plist
      % sudo launchctl start org.macports.postgresql93-server
      
      

  3. Yosogアプリが利用するDBを生成する
    1. ユーザーとデータベースの生成
    2. 自動生成されるconfig/postgres.ymlを確認するとYosogユーザーでYosogデータベースにアクセスする設定になっています。このため以下のコマンドでユーザーとデータベースを作成しておきます。
      
      % createuser -U postgres -P Yosog
      % createdb -U postgres Yosog
      
      
      ユーザーとデータベースが作成されていないと、Yosogアプリ起動時に以下のエラーになります。
      
      Yosog: SqlError {sqlState = "", sqlExecStatus = FatalError, sqlErrorMsg = "FATAL:  role \"Yosog\" does not exist\n", sqlErrorDetail = "", sqlErrorHint = ""}
      
      
    3. PostgreSQL対応したYosogアプリの起動
    4. 
      % cabal run -- Development
      
      

HerokuにPostgreSQL対応版Haskell/Yesodアプリをdeployする

PostgreSQLを利用する手順はRuby on Rails上であればHerokuのドキュメントで紹介されています。ここではHaskellのYesodフレームワーク上でPostgreSQLを利用するサーバーをHerokuにデプロイするための手順を示しておきます。
  1. postgresqlアドオンの登録&接続情報の確認
    1. postgresqlアドオン登録
    2. 
      %  heroku addons:add heroku-postgresql:dev
      
      
    3. DB情報の確認
    4. 
      % heroku pg:info
      === HEROKU_POSTGRESQL_IVORY_URL
      Plan:        Dev
      Status:      available
      Connections: 0
      PG Version:  9.3.3
      Created:     2014-03-12 15:42 UTC
      Data Size:   6.4 MB
      Tables:      0
      Rows:        0/10000 (In compliance)
      Fork/Follow: Unsupported
      Rollback:    Unsupported
      
      
    5. 接続情報の確認
    6. 
      % heroku pg:credentials HEROKU_POSTGRESQL_IVORY_URL
      Connection info string:
         "dbname=ddddd host=aaa-11-222-33-44.compute-1.amazonaws.com port=5432 user=uuuuu password=XXXXX sslmode=require"
      Connection URL:
          postgres://uuuuu:XXXXX@aaa-11-222-33-44.compute-1.amazonaws.com:5432/ddddd
      
      
  2. 接続情報の反映と接続確認
    1. config/postgresql.ymlの編集
    2. 接続情報で確認した、dbname, host, user, passwordをpostgresql.ymlのProduction:の設定に反映します。
      
      --- a/config/postgresql.yml
      +++ b/config/postgresql.yml
      @@ -19,6 +19,10 @@ Staging:
         <<: *defaults
       
       Production:
      -  database: Yosog_production
      +  user: uuuuu
      +  password: XXXXX
      +  host: aaa-11-222-33-44.compute-1.amazonaws.com
      +  port: 5432
      +  database: ddddd
         poolsize: 100
         << *defaults
      
      
    3. postgresql対応版サーバーのdeploy
    4. 
      % git commit -m "- use postgersql instead of sqlite." .
      % git push heroku master
      % heroku open
      
      
    5. psqlを用いた接続確認(おまけ)
    6. 以下のコマンドでPCからadonしたPostgreSQLのDBに接続することができます。postgresql.ymlのDevelopment:欄に同様の設定をすればアプリ本体はPC上、DBはサーバー上の組み合わせで動作確認することもできます。
      
      % psql -h aaa-11-222-33-44.compute-1.amazonaws.com -p 5432 -U uuuuu DDDDD
      ddddd> \d
                        List of relations
       Schema |      Name      |   Type   |     Owner      
      --------+----------------+----------+----------------
       public | article        | table    | uuuuu
       public | article_id_seq | sequence | uuuuu
       public | email          | table    | uuuuu
       public | email_id_seq   | sequence | uuuuu
       public | user           | table    | uuuuu
       public | user_id_seq    | sequence | uuuuu
      (6 rows)
      
      

ここまでの修正はGitHubにコミット済みです。
https://github.com/kurokawh/Yosog/tree/Yosog_PostgreSQL
メモ:ローカルリポジトリの変更をリモートのmaster以外の別ブランチにプッシュするには、以下のコマンドを実行する。

% git push origin master:Yosog_PostgreSQL
Counting objects: 24, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (18/18), done.
Writing objects: 100% (18/18), 2.02 KiB | 0 bytes/s, done.
Total 18 (delta 12), reused 0 (delta 0)
To https://kurokawh@github.com/kurokawh/Yosog.git
   be68e29..8a25b29  master -> Yosog_PostgreSQL
% git branch -r
  origin/Yosog_PostgreSQL
  origin/master


参考にした情報:

0 件のコメント:

コメントを投稿