Herokuで1つのアプリを複数の環境にデプロイする

Herokuで運用中のアプリのローカルリポジトリからHerokuに複数環境を生成する方法です。

具体的には次のような事を行う場合に便利です。

  • Herokuに本番環境とステージング環境と開発環境を作成
  • Herokuでモバイルアプリの有料アプリのサーバと無料アプリのサーバを別に作る

新たなheroku環境作成

heroku create アプリ名 --remote 新環境名 (例:free, production, staging, test,...) 

例:

heroku create newapp --remote production

新たなheroku環境へデプロイ

git push 新環境名 master

例:

git push production master

Add-onを追加

1つのローカルリポジトリで複数のheroku環境を扱う様になったので、アドオン追加時にはアプリ名の指定が必要になります。

例:NewRelicのAdd-onを追加する場合

heroku addons:add newrelic --app アプリ名

以上

Herokuのアプリをターミナルで削除する

Herokuで運用しているアプリをCLIのターミナル経由で削除する方法です。

ターミナルで削除するとgit remoteの設定を削除する必要がないため、WebのGUI管理画面で削除するよりも楽です。

確認無しで削除する

heroku apps:destroy --app アプリ名 --confirm アプリ名

アプリの作成や削除をスクリプトなどで自動化したい場合はこちらを使います。

確認ありで削除する

heroku apps:destroy --app アプリ名

確認を求められるのでアプリ名を入力します。

MagicalRecord に mogenerator を組み合わせてよいか

CoreDataを使う際に、MagicalRecordに加えてmogeneratorを使う事を推奨しているブログ記事が散見されますが、mogeneratorには以下のようにリジェクトのリスクがあるようです。

筆者はmogeneratorを使っていた事もありましたが、現在は別の理由もあってMagicalRecord単体で使っています。リジェクトのリスクはmogeneratorに限った話しではないですが、注意した方がいいかもしれません。

以上

MagicalRecordでCoreDataをお手軽に使う

iOSアプリでデータを保存(serialize/deserialize)する方法としてCoreDataがありますが、コード量が多く慣れるまでにも時間がかかります。

ここではより簡単なMagicalRecordによって、CoreDataを使ってみます。

MagicalRecordActive Recordパターンを採用したCoreDataのラッパーです。ActiveRecordは、Martin FowlerらのPatterns of Enterprise Application Architectureで名付けられ、Ruby on Railsで普及しました。

MagicalRecordがあれば、Webアプリ開発者でもCoreDataを簡単に扱えるようになり、iOSアプリ開発がより身近に感じられるようになると思います。

前提

CocoaPodsはインストール済みとします。CocoaPodsのインストール方法は以下を参照してください。

iOSアプリのプロジェクト作成

  1. Xcodeを開いて新規プロジェクトを作成します。

     File > New > Project
    
    • Use Core Dataの指定は不要です。
      • 指定すると不要なコードが生成されるため、指定しない事をおすすめします。

MagicalRecordのインストール

  1. Podfile作成

    1. .xcodeprojがあるディレクトリにPodfileファイルを作成します。
    2. Podfileに次の1行を追記します。

      pod 'MagicalRecord'

  2. MagicalRecordインストール

    1. ターミナル上でPodfileと同じディレクトリに移動して以下を実行します。

       pod install
      
  3. 設定

    1. アプリ名/アプリ名-Prefix.pchを開いて次の1行を追記します。

       #import "CoreData+MagicalRecord.h"
      

CoreDataデータモデルの定義と作成

  1. Data Modelを追加

    1. メニューからFile > New > File > Data Modelを選択します。
    2. Model.xcdatamodeldを作成します。
  2. Entityを追加

    1. ツリー上でModel.xcdatamodeldを選択します。
    2. Add EntityをクリックしてEntityを追加します。
    3. Entityを適切な名前に変更します。
    4. Entityの属性(Attributes)や関係(Relationship)を定義します。
  3. Entityから必要なソースコードを自動生成

    1. ツリー上でModel.xcdatamodeldを選択します。
    2. メニューからEditor > Create NSManagedObject Subclass > Next > Next > Createを選択します。

      Use scalar properties for priitive data typesをチェックすると以下のようなスカラー型(定数型)のプロパティがプリミティブなデータ型に変換されます。チェック不要で構いません。

      • Date -> NSTimeInterval.
      • Double -> double.
      • Float -> float.
      • Integer 16/32/64 -> int16_t/int32_t/int64_t
      • Boolean -> BOOL

MagicalRecordの起動/終了処理

  1. 起動処理

    AppDelegete.mファイルを開いてdidFinishLaunchingWithOptionsに起動処理を追加します。

     - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
     {
         // 以下を追加
         [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"database_name.sqlite"];
         return YES;
     }
    

    初期化には以下のようなメソッドが用意されています。目的に応じて選択します。

    ローカルのSQLite

     + (void) setupCoreDataStack;
     + (void) setupAutoMigratingCoreDataStack;
     + (void) setupCoreDataStackWithInMemoryStore;
     + (void) setupCoreDataStackWithStoreNamed:(NSString *)storeName;
     + (void) setupCoreDataStackWithAutoMigratingSqliteStoreNamed:(NSString *)storeName;
    

    iCloud

     + (void) setupCoreDataStackWithiCloudContainer:(NSString *)icloudBucket localStoreNamed:(NSString *)localStore;
     + (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent;
     + (void) setupCoreDataStackWithiCloudContainer:(NSString *)containerID contentNameKey:(NSString *)contentNameKey localStoreNamed:(NSString *)localStoreName cloudStorePathComponent:(NSString *)pathSubcomponent completion:(void(^)(void))completion;
    
  2. 終了処理

    AppDelegete.mファイルを開いてapplicationWillTerminateに終了処理を追加します。

     - (void)applicationWillTerminate:(UIApplication *)application
     {
         // 以下を追加
         [MagicalRecord cleanUp];
     }
    

MagicalRecordでのデータ保存

  • 同期

      Album *album = [Album MR_createEntity];
      album.title = @"Friends";
          :
    
      [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
    

MR_saveメソッドは次期メジャーリリースの3.0からは無くなるので同じ機能を持つMR_saveToPersistentStoreAndWaitを使いましょう。

  • 非同期

      Album *album = [Album MR_createEntity];
      [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext){
    
          //保存前の処理(保存したいインスタンスの作成など)
          Album *localAlbum = [album MR_inContext:localContext];
          localAlbum.title = @"NeverMind";
              :
    
      } completion:^(BOOL success, NSError *error) {
    
          //保存後の処理(全件取得や件数カウントなど)
    
      }];
    
  • その他

    MagicalRecord / Docs / Saving.md

MagicalRecordでのデータ取得

  • 全件取得

      NSArray *albums = [Album findAll];
    
  • 条件を指定して取得

      NSArray *albums = [Album MR_findByAttribute:@"genre" withValue:@"piano trio" andOrderBy:@"year" ascending:YES];
    
  • その他高度な取得

    MagicalRecord / Docs / Fetching.md

MagicalRecordでのデータ更新

  • データ取得&更新

    あらかじめAlbumのインスタンス(ここではcheckyourhead)を取得しておきます。

      Album *checkyourhead = ...;
      checkyourhead.rate = [NSNumber numberWithInt:5];
      [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
    

MagicalRecordでのデータ削除

  • 全件削除

      [Album MR_truncateAll];
      [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
    
  • 1件削除

    あらかじめAlbumのインスタンス(ここではmellowgold)を取得しておきます。

      Album *mellowgold = ...;
      [mellowgold MR_deleteEntity];
    

MagicalRecordでのデータカウント

  • カウント

      NSNumber *count = [Album MR_numberOfEntities];
    

注意

MagicalRecordでデータの保存、更新、削除を反映する際は必ず以下を実行します。

    [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];

以上です。MagicalRecordを使うとCoreDataを簡単に扱えます。

OSXでDockerを使う

Dockerに特化した軽量Linuxのboot2dockerを使ってOSXでDockerを使ってみます。Dockerはv0.8でアーキテクチャを変更してOSXに対応し、homebrewにも入ったため誰でも簡単に使えるようになりました。

f:id:slowquery:20140311231722p:plain

インストール

brew cask install virtualbox
brew cask install vagrant
brew install docker
brew install boot2docker

boot2dockerのVMを作成

boot2dockerのVirtualBox用のVMを作成します。

boot2docker init

※ boot2dockerは、Dockerコンテナを動かす目的に特化したTinyCoreLinuxベースの軽量Linuxディストリビューションです。

boot2dockerのVMを起動

boot2docker up  
export DOCKER_HOST=tcp://localhost:XXXX

boot2dockerのVMへ接続(参考)

boot2docker ssh

ユーザ/パスワードは以下です。

user:docker
password:tcuser

f:id:slowquery:20140311231722p:plain

コンテナイメージを探す

以下のサイトにDockerのコンテナがたくさんあります。

例1. Ubuntuのコンテナをダウンロード

Ubuntuのコンテナをダウンロードしてboot2dockerに展開します。

docker pull ubuntu

例1. Ubuntuへログイン

docker run -i -t ubuntu /bin/bash

f:id:slowquery:20140311231933p:plain

例2. CentOSのコンテナをダウンロード

docker pull centos

例2. CentOSへログイン

docker run -i -t centos /bin/bash

トラブル対策

OSXVirtualBox 4.3.8環境で問題が発生するケースがあります。

boot2docker / boot2docker - Kernel panic on VirtualBox 4.3.8 (Mac OS X) #260

現象

解決策

上記現象が発生する場合は以下を実行します。

boot2docker stop
boot2docker delete
boot2docker init

VBoxManage setextradata boot2docker-vm VBoxInternal/CPUM/EnableHVP 1
boot2docker up