Docker ComposeでElixir/Phoenixの開発環境を構築する

# はじめに

この記事では、Docker Compose を使用した Phoenix アプリケーションの開発環境構築について説明します。なおこの記事は、次のバージョンに基づいて説明しています。

Elixir: 1.8.1
Phoenix: 1.4.3
Node.js: 10.x
Docker: 18.09

また、以降の説明は `my-app` ディレクトリに `my_app` というアプリケーションを構築するという前提で進めます。

# Docker ファイルの作成

まず最初に Docker のファイルをプロジェクトのディレクトリに配置します。適当な場所に `my-app` というディレクトリを作成し、次に示す `Dockerfile` と `docker-compose.yml` をディレクトリ内に格納してください。

```dockerfile:my-app/Dockerfile
FROM elixir:1.8.1

ENV NODE_VERSION 10.x

RUN curl -sL https://deb.nodesource.com/setup_${NODE_VERSION} | bash \
  && apt-get install -y nodejs

RUN npm install npm@latest -g

RUN mix local.hex --force && \
  mix archive.install hex phx_new 1.4.3 --force && \
  mix local.rebar --force

WORKDIR /app
```

```yml:my-app/docker-compose.yml
version: '3.2'
services:
  web:
    build: .
    ports:
      - '4000:4000'
    command: mix phx.server
    environment:
      - MIX_ENV=dev
      - PORT=4000
    volumes:
      - .:/app

  db:
    image: postgres
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_HOST=db
```

# Phoenix プロジェクトの準備

## プロジェクトの生成

それでは `mix phx.new` コマンドで Phoenix プロジェクトを新規作成しましょう。`my-app` ディレクトリで次のコマンドを実行してください。

```sh
$ docker-compose run web mix phx.new . --app my_app
```

実行中、以下のような確認メッセージが表示されますが、 `y` を入力して処理を続行してください。

- `The directory /app already exists. Are you sure you want to continue? [Yn]`
- `Fetch and install dependencies? [Yn]`

上記の処理が完了すると、以下のようなファイル/ディレクトリが作成されているはずです。

```
my-app
├── _build
├── assets
├── config
├── deps
├── libs
├── priv
├── test
├── .formatter.exs
├── .gitignore
├── docker-compose.yml
├── Dockerfile
├── mix.exs
├── mix.lock
└── README.md
```

# DB のセットアップ

続いて DB のセットアップを行います。Phoenix はデフォルトで PostgreSQL を使用するので、ここではそのまま PostgreSQL を利用することとします。

## 設定ファイルの変更

`my-app/config/dev.exs` を開き、Postgres の hostname を以下のように変更します。

```exs:my-app/config/dev.exs
...

# Configure your database
config :my_app, MyApp.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: "postgres",
  password: "postgres",
  database: "my_app_dev",
  hostname: "db",
  pool_size: 10
```

## docker-compose の実行

`docker-compose.yml` で定義している各 service を立ち上げます。次の `docker-compose` コマンドを実行してください。

```sh
$ docker-compose up -d
```

## コンパイルとマイグレーション

最後に以下のコマンドを実行して、依存ライブラリのコンパイルと DB のマイグレーションを行います。

```sh
$ docker-compose run web bash -c "mix deps.compile && mix ecto.create && mix ecto.migrate"
```

# 実行確認

ブラウザで `http://localhost:4000` という URL を指定してください。次のような Phoenix のデフォルトの初期ページが表示されれば成功です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/12152/7e6dbf67-866b-fe87-2565-0333785c98f1.png)

# 開発中の操作

## Docker コンテナでコマンドを実行する

実行中の Docker コンテナに対してコマンドを実行する場合、次のように[`docker-compose run`](https://docs.docker.com/compose/reference/run/)を使用します。

```sh
$ docker-compose run web mix hex.info
```

ここでは、`web`という service に対して、`mix hex.info`というコマンドを実行しています。

また、ssh のようにコンテナの中で継続してコマンドを実行する場合、[`docker exec -it`](https://docs.docker.com/engine/reference/commandline/exec/)を使用します。

```sh
$ docker exec -it {コンテナのID} bash
```

## コンテナの停止

`docker-compose up -d`によって立ち上げた Docker コンテナを停止する場合、以下のコマンドを実行します。

```sh
$ docker-compose stop
```

なお、コンテナの停止だけでなく、コンテナ、ボリュームの削除まで行う場合は、次のように[`down`](https://docs.docker.com/compose/reference/down/)を指定します。

```sh
$ docker-compose down
```

このコマンドを実行すると、開発中に PostgreSQL に格納したデータも削除されるので注意してください。

# 参考

[Dockerizing a Phoenix Application](https://medium.com/@cristiano.codelab/dockerizing-a-phoenix-application-4e62e7888ae8)