Elixir1.6 / Phoenix1.3の環境をDockerで整えてCRUDアプリを動かすまで

# dockerでElixirとMysqlの環境を構築
まずはElixirの入ったコンテナを作成します。alpine linuxのElixirのコンテナをベースに
してnodejsとnpmそして、Hex,Rebar,Phoenixをインストールします。

```Dockerfile:./docker/elixir/Dockerfile
FROM elixir:alpine

# Install NPM
RUN \
    mkdir -p /opt/app && \
    chmod -R 777 /opt/app && \
    apk update && \
    apk --no-cache --update add \
      git make g++ wget curl inotify-tools \
      nodejs nodejs-npm && \
    npm install npm -g --no-progress && \
    update-ca-certificates --fresh && \
    rm -rf /var/cache/apk/*

# Add local node module binaries to PATH
ENV PATH=./node_modules/.bin:$PATH \
    MIX_HOME=/opt/mix \
    HEX_HOME=/opt/hex \
    HOME=/opt/app

# Install Hex+Rebar
RUN mix local.hex --force && \
    mix local.rebar --force && \
    mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez --force

WORKDIR /opt/app
```
mysqlについては、Dockerにある、オフィシャルイメージを使います。
docker-compose.ymlは以下のようになります。

```yaml:docker-compose.yml
version: '2.1'
services:
  db:
    image: mysql:8.0.3
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/volumes:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: 'password'      
  web:
    build: ./docker/elixir
    container_name: "exweb"
    working_dir: /opt/app
    command: mix phx.server
    volumes:
      - .:/opt/app
    environment:
      MYSQL_ROOT_USERNAME: 'root'
      MYSQL_ROOT_PASSWORD: 'password'
      MYSQL_HOSTNAME: 'db'
      MYSQL_PORT: '3306'
    ports:
      - '4000:4000'
    depends_on:
      - db
```

準備が整ったら、elixirを動かすコンテナをビルドします。ビルドが完了したら、一応Elixirの
バージョンを確認しておきます。

```
$ docker-compose build web
Building web
Step 1/5 : FROM elixir:alpine
...
Successfully built 5dfb773fd1a1
Successfully tagged app_web:latest
$ docker-compose run --rm web elixir -v
Starting app_db_1 ... done
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:10] [hipe] [kernel-poll:false]

Elixir 1.6.0 (compiled with OTP 19
$ docker-compose run --rm web mix phx.new --version
Starting app_db_1 ... done
Phoenix v1.3.0
```
また、後でmysqlにPhoenixから接続することになるので、mysqlのコンテナもあらかじめ
起動しておきます。

```
$ docker-compose up -d mysql
```

# Phoenixプロジェクトの作成

Elixirが動く環境が用意できたので、そのコンテナを使ってPhoenixプロジェクトを作成します。

```
$ docker-compose run --rm web mix phx.new . --no-brunch --database mysql
```

phoenix.newの後の指定をカレントディレクトリにします。また-dオプションを使って
データベースをmysqlに指定します。プロジェクトが生成された後は、config/dev.exs
にデータベースの設定を記述します。

```exs:config/dev.exs
# Configure your database
config :app, App.Repo,
  adapter: Ecto.Adapters.MySQL,
  username: "root",
  password: "password",
  database: "app_dev",
  hostname: "db",
  pool_size: 10

```
上記の設定が完了したら、Phoenixのectoのコマンドでmysqlにデータベースを作成します。

```
$ docker-compose run --rm web mix ecto.create
```

最後にPhoenixのサーバーを起動して、動作を確認します。

```
$ docker-compose up
app_db_1 is up-to-date
Starting exweb ... done
Attaching to app_db_1, exweb
...
exweb  | [info] Running App.Endpoint with Cowboy using http://localhost:4000
```

[http://localhost:4000/](http://localhost:4000/)にアクセスして、画面が表示されれば
環境構築は完了です。

# CRUDのページを生成する
phx.gen.htmlというページを生成してくれるコマンドがあるので、
それを使って、CRUDのページを作成します。

```
$ docker-compose run --rm web mix phx.gen.html Account User users name:string age:integer
Starting app_db_1 ... done
* creating lib/app_web/controllers/user_controller.ex
* creating lib/app_web/templates/user/edit.html.eex
* creating lib/app_web/templates/user/form.html.eex
* creating lib/app_web/templates/user/index.html.eex
* creating lib/app_web/templates/user/new.html.eex
* creating lib/app_web/templates/user/show.html.eex
* creating lib/app_web/views/user_view.ex
* creating test/app_web/controllers/user_controller_test.exs
* creating lib/app/account/user.ex
* creating priv/repo/migrations/20180127170317_create_users.exs
* creating lib/app/account/account.ex
* injecting lib/app/account/account.ex
* creating test/app/account/account_test.exs
* injecting test/app/account/account_test.exs

Add the resource to your browser scope in lib/app_web/router.ex:

    resources "/users", UserController


Remember to update your repository by running migrations:

    $ mix ecto.migrate
```
上記のコマンドで、コントローラとモデル、ビューのファイルは生成されました。
ルーティング用の設定は、自動では追加されないので、web/router.exに追記します。

```ex:lib/app_web/router.ex
defmodule App.Router do
  use App.Web, :router
  ...中略...
  scope "/", App do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    resources "/users", UserController
  end
  ...中略...
end

```
ecto.migrateコマンドを使って、dbのテーブルも作成します。

```
$ docker-compose run --rm web mix ecto.migrate
Starting app_db_1 ... done
[info] == Running App.Repo.Migrations.CreateAccounts.change/0 forward
[info] create table users
[info] == Migrated in 0.0s
```

# 動作確認
最後にdocker-compose upやdocker-compose restart webをしてから、
[http://localhost:4000/users](http://localhost:4000/users)にアクセスして
ユーザーの追加や編集が行えることを確認します。