使って学ぶgigalixir、DBを使うアプリをデプロイする


本記事では、DBを使うアプリをGigalixirにデプロイする方法を解説します。

@piacerex さんの記事の以下節の作業が終わっていることを前提とします。

- [【本番構築Gigalixir編①】Elixir／Phoenixの初期PJリリースまでの手順](https://qiita.com/piacerex/items/1a9cbcc740ca3707eaec)
    - Gigalixirのアカウント作成
    - PJフォルダをGigalixirリモートレポジトリに設定
- [【本番構築Gigalixir編②】Elixir／Phoenixで構築したCRUD Webアプリをリリース](https://qiita.com/piacerex/items/511f24888c7350639d0b)
    - gigalixirコマンドのインストール
    - ssh公開鍵の設定

# 作業環境

リモートのGigalixirはFree Planを使用します。
Elixirのversionは1.9.1です。
Phoenixのversionは1.4.11です。

アプリケーションは作成済のチャットアプリです。

# アウトライン

以下の順に解説します。

1. DBを作成する  
   Gigalixirにデプロイしたアプリケーションが接続するDBを作成します
1. Phoenixの本番（Production）環境設定をする  
   DBへの接続の設定、Endpointの設定を行います
1. デプロイする  
   アプリケーションをGigalixirにデプロイします
1. DBの初期準備をする  
   migrationを行います。また必要に応じて種データを準備します

# DBを作成する

gigalixirコマンドでアプリケーションが接続するDBを作成します。

~~~ bash
# 作成
$ gigalixir pg:create --free
# 確認
$ gigalixir pg # 以下でブランクとした部分に値が表示されます。
[
  {
    "app_name": "",
    "database": "",
    "host": "",
    "id": "",
    "limited_at": null,
    "password": "",
    "port": 5432,
    "state": "AVAILABLE",
    "tier": "FREE",
    "url": "",
    "username": ""
  }
]
~~~

参考：[How to provision a Free PostgreSQL database](https://gigalixir.readthedocs.io/en/latest/main.html#how-to-provision-a-free-postgresql-database)

# Phoenixの本番（Production）環境設定をする

Production環境の設定はprod.exs, prod.secret.exsに行います。
prod.secret.exsのフォーマットはPhoenix 1.4.4以降とそれ以前で違うため、設定方法が異なります。
今回は1.4.11なので1.4.4以降の設定方法を以下で紹介します。
※1.4.3以前の設定方法は[Configuration and Secrets](https://gigalixir.readthedocs.io/en/latest/main.html#configuration-and-secrets)を参照ください。

参考：[Configuration and Secrets](https://gigalixir.readthedocs.io/en/latest/main.html#configuration-and-secrets)

## prod.secret.exs

ファイル名のとおりProduction環境固有の秘匿しておきたい情報を設定します。
例えば、DBへの接続情報である、URL、ユーザ名、パスワード、ポート等はそれにあたります。
そういった情報を設定ファイルに直書きせず、デプロイ先の環境変数から読み込みます。
デプロイ先の環境変数の設定方法は後述します。

編集はsslのコメントアウトを外すのみです。

~~~ prod.secret.exs
use Mix.Config

database_url =
  System.get_env("DATABASE_URL") ||
    raise """
    environment variable DATABASE_URL is missing.
    For example: ecto://USER:PASS@HOST/DATABASE
    """

config :tombo_chat, TomboChat.Repo,
  ssl: true, # ←ココ！！
  url: database_url,
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")

secret_key_base =
  System.get_env("SECRET_KEY_BASE") ||
    raise """
    environment variable SECRET_KEY_BASE is missing.
    You can generate one by calling: mix phx.gen.secret
    """

config :tombo_chat, TomboChatWeb.Endpoint,
  http: [:inet6, port: String.to_integer(System.get_env("PORT") || "4000")],
  secret_key_base: secret_key_base
~~~

## prod.exs

編集はhostとportを以下に変更し、schemeを追加します。
host: "[your-app-name].gigalixir.com"
port: 443
scheme: "https"

~~~ elixir
config :tombo_chat, TomboChatWeb.Endpoint,
  url: [scheme: "https", host: "your-app-name.gigalixirapp.com", port: 443], # ココ
  cache_static_manifest: "priv/static/cache_manifest.json"

# Do not print debug messages in production
config :logger, level: :info

# 中略

import_config "prod.secret.exs"
~~~

※prod.secret.exsはprod.exsから読み込まれることが分かります。
※urlはTomboChatWeb.Router.Helpersを使ってurlを生成する際に使用されます。例えば、
　TomboChatWeb.Router.Helpers.static_url(TomboChatWeb.Endpoint, "/")は上記設定により
　"https://your-app-name.gigalixir.com/" を返すようになります。"

[your-app-name]はgigalixirコマンドで確認できます。

~~~ bash
$ gigalixir apps
[
  {
    "cloud": "gcp",
    "region": "v2018-us-central1",
    "replicas": 1,
    "size": 0.3,
    "stack": "gigalixir-18",
    "unique_name": "your-app-name" # ココ
  }
]
~~~

# デプロイする

PhoenixのProduction環境用の設定ができたのでデプロイ作業を行います。

## デプロイ先の環境変数の確認と設定

prod.secret.exsはDATABASE_URL、POOL_SIZE、SECRET_KEY_BASE、PORTの4つの環境変数の読み込みを行います。
このなかで設定が必須なのはDATABASE_URLとPOOL_SIZEです。

~~~ bash
# 現在の環境変数の確認
$ gigalixir config
{
  "DATABASE_URL": ""
}

# 設定：gigalixir config:set KEY_NAME=VALUE
$ gigalixir config:set DATABASE_URL="" # ""をgigalixir pgで表示される情報の"url"の右辺値とします。
$ gigalixir config:set POOL_SIZE=2 # Free PlanではPOOL_SIZEを2とする必要があります。
~~~

参考：[Configuration and Secrets](https://gigalixir.readthedocs.io/en/latest/main.html#configuration-and-secrets)

## Elixir, Erlang, Node, NPMのversion指定

Gigalixirでアプリケーションを動作させる際のElixir, Erlang, Node, npmのバージョンを指定します。
参考：[Specify Versions](https://gigalixir.readthedocs.io/en/latest/main.html#specify-versions)

Phoenixアプリケーションのルートディレクトリの直下にelixir_buildpack.configを作成し、バージョンを指定します。
例えば以下です。自身の開発環境に合わせてください。

~~~ elixir_buildpack.config
# Erlang version
erlang_version=22.2

# Elixir version
elixir_version=1.10.0
~~~

~~~ phoenix_static_buildpack.config
# We can set the version of Node to use for the app here
node_version=12.14.0
# We can set the version of NPM to use for the app here
npm_version=6.13.7
~~~

※デプロイに必要なファイルのためgit管理下に忘れずに入れてください。ファイル名を間違えると正しく動作しません。
※NPMの6.13.4〜6.13.6は[バグ](https://github.com/npm/cli/issues/613)がありデプロイできなかったので注意

## デプロイ

git pushでgigalixirにデプロイします。
git remoteへの追加は[PJフォルダをGigalixirリモートレポジトリに設定](https://qiita.com/piacerex/items/1a9cbcc740ca3707eaec#pj%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%82%92gigalixir%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%AC%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%AB%E8%A8%AD%E5%AE%9A)を参照ください。

~~~ bash
$ git push gigalixir master
# ローカルブランチをリモートマスターに送る場合は以下
$ git push gigalixir local_branch:master
~~~

## 動作確認

gigalixirコマンドでステータスを見たり、ログを見たりできます。

ステータスを見る

~~~ bash
$ gigalixir ps
{
  "cloud": "gcp",
  "pods": [
    {
      "lastState": {},
      "name": "",
      "status": "Healthy",
      "version": "1"
    }
  ],
  "region": "v2018-us-central1",
  "replicas_desired": 1,
  "replicas_running": 1,
  "size": 0.3,
  "stack": "gigalixir-18",
  "unique_name": ""
}
~~~

ログを見る

~~~ bash
$ gigalixir logs
~~~


# DBの初期準備をする

デプロイができ、データベースとの接続ができたので、
データベースの初期準備としてmigrationと種データの用意をします。

## migration

gigalixirコマンドでmigrationをします。

~~~ bash
$ gigalixir run mix ecto.migrate
~~~

## 種データの用意

Gigalixirのiexに入って、スクリプトを実行します。
今回はbackend_seeds.exsという種データをDBに挿入するスクリプトを予め用意したので、それを実行します。

~~~ bash
$ gigalixir ps:remote_console
iex> pwd
/app
iex> ls
.bash_history               .basher                     .bashrc                     
.cache                      .formatter.exs              .gitignore                  
.heroku                     .hex                        .mix                        
.platform_tools             .profile                    .profile.d                  
.release                    Procfile                    README.md                   
_build                      app.tar.gz                  assets                      
config                      deps                        elixir_buildpack.config     
lib                         mix.exs                     mix.lock                    
priv                        test 
iex> cd "priv/repo"
iex> ls
backend_seeds.exs     migrations            seeds.exs
iex> c "backend_seeds.exs"
~~~

参考：[How to run seeds?](https://gigalixir.readthedocs.io/en/latest/main.html#how-to-run-seeds)

# トラブルシュート

## remote: npm ERR! invalid bin entry for package

NPMのバグです。NPMのversion指定を見直してください。

https://github.com/npm/cli/issues/613

## remote: cp: cannot overwrite directory ‘/tmp/cache/node_modules/phoenix’ with non-directory

gigalixirのbuild cashが残っているためのようです。
以下で解消されます。

~~~ bash
$ git -c http.extraheader="GIGALIXIR-CLEAN: true" push gigalixir master
~~~

参照：[How to clean your build cache](https://gigalixir.readthedocs.io/en/latest/main.html#how-to-clean-your-build-cache)

# おわり

DBを使うPhoenixアプリケーションをGigalixirにデプロイする方法を順に説明しました。
アプリケーション作成後のデプロイ練習の一手目にGigalixirを試せてよかったです。

**「いいね」**よろしくお願いします。:wink: