PhoenixによるWeb開発 - Dockerによる環境構築まで -

## はじめに

皆様お久しぶりです。
この記事は、Elixirで実装されたWebフレームワーク「Phoenix」を使ってWeb開発を行うための環境構築を行えるチュートリアルとして執筆しています。筆者はこれまでElixir、Phoenixによる開発を行ったことがないため、最初になぜ、Phoenixを取り扱うことになったのかを説明させていただきます。

## なぜRailsからPhoenixに移行するのか

筆者はネットワークエンジニアからキャリアを始め、そこからWeb開発エンジニアの道を進みました。開発エンジニアにチェンジして既に3年が経ちますが、基本的には、Ruby on Rails(以下、Rails)を中心としたサーバサイド開発、たまにフロントエンド開発、及びクラウドの方も取り扱っています。
Railsによる開発は、そこそこの経験となり、卒なくこなせるようにはなってきました。

しかし、ここ最近のRailsに自分自身が魅力を感じなくなってきました。
元々、Railsの専門家になりたいとかそういうモチベーションでWeb開発をしている訳ではなく、ネタがあって偶々Railsを採用して開発しているので、Railsが好きとかそういう感情がないこと。
更にはRails6がリリースされてからアップグレードガイドを読んでいましたが、[主要な機能](https://railsguides.jp/6_0_release_notes.html#%E4%B8%BB%E8%A6%81%E3%81%AA%E6%A9%9F%E8%83%BD)の項目を読んでRails以外を使いたくなってきました。

* ActionText, Action MailBoxは多分あれば嬉しいのだけど、それWebフレームワーク標準で持っていなきゃいけない機能?
* 並列テスト、あるいは複数DBのサポートされるようになったのは嬉しいが、それだけでアップグレードするモチベーションにはならない
* フレームワークの専門家になりたい訳じゃないが、そこそこの時間をかけずにWebのシステムを作りたいのは事実(目安的には1人月で作るレベルのWebアプリケーションの開発は卒なくこなしたい)。ただし、Railsは上記のモチベーションが理由で技術選定する土俵から外れるかも。

という事で、今一度初心に戻ってRailsとは違う方法で開発をする方法を見つけたいと思い、先輩の紹介もありPhoenixを触る事となりました。

## 各バージョン

* Elixir: 1.9.4
* Erlang: 22.2.1

## バージョンマネージャのasdfをインストールする

今回についても、プロジェクト毎に言語のバージョンを切り分け、あるいは固定したいと思うので、Elixir,Erlang用のバージョンマネージャがないかと思い調べた矢先、`asdf`が使えそうだったので、こちらを使う事としました。なお、Elixir,Erlang以外にもRubyなどもサポートしている模様です。ちょっとrbenvからこちらに統一しても良いかもしれませんが、それはまたの機会に。

```zsh
% brew install asdf
% echo -e "\n. $(brew --prefix asdf)/asdf.sh" >> ~/.zshrc
% echo -e "\n. $(brew --prefix asdf)/etc/bash_completion.d/asdf.bash" >> ~/.zshrc
```

### Pluginのインストール

各言語をasdf経由でインストールするためにPluginの導入も必要となってきます。

```zsh
% brew install \
  coreutils automake autoconf openssl \
  libyaml readline libxslt libtool unixodbc \
  unzip curl
```

Pluginのリストを取得するためには、`asdf plugin list-all`コマンドが便利です。

```zsh
% asdf plugin list-all
```

ここではElixirのみをインストールしましょう。

```zsh
% asdf plugin add elixir
```

更に、最新安定版のElixirをインストールします。

```zsh
% asdf install elixir latest
```

プロジェクト毎にelixirのversionを分けたい場合は、以下のコマンドをディレクトリ内で打つことでElixirのバージョンを固定することが出来ます。

```zsh
% asdf local elixir 1.9.4-otp-22
```

## Erlangのインストール

Elixirで書かれたコードは一度、バイトコードにコンパイルされ、Erlang VM上で実行されます。
そのため、Erlangのインストールも必要となります。

```zsh
% asdf plugin add erlang
```

```zsh
% asdf install erlang latest
```

```zsh
% asdf erlang 22.2.1
```

## MixとPhoenixのインストール

パッケージマネージャとなるMixをインストールし、Mix経由でPhonenixをインストールします。

```zsh
% mix local.hex

% mix archive.install hex phx_new 1.4.11
```

## Phoneixサーバの起動

```zsh
% mix phx.new .
```

```zsh
% mix ecto.create
```

```zsh
% mix phx.server
```

以上でデフォルトのPhoneixサーバの起動ができます。

![Phoenix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144991/ddf9dbc6-e94b-1f4d-3dce-2a708fbb2be6.png)

## Dockerによる環境構築

```dockerfile:Dockerfile
FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y locales

RUN locale-gen ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:jp
ENV LC_ALL ja_JP.UTF-8

ENV ELIXIR_VERSION 1.9.4

RUN apt install -y curl wget git make sudo tar bzip2 libfontconfig unzip build-essential inotify-tools
RUN wget http://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
RUN dpkg -i erlang-solutions_1.0_all.deb
RUN apt update && apt install -y esl-erlang
RUN rm erlang-solutions_1.0_all.deb
RUN wget https://github.com/elixir-lang/elixir/releases/download/v${ELIXIR_VERSION}/Precompiled.zip
RUN mkdir -p /opt/elixir-${ELIXIR_VERSION}/ && unzip Precompiled.zip -d /opt/elixir-${ELIXIR_VERSION}/

RUN curl -sL https://deb.nodesource.com/setup_13.x | bash -
RUN apt install -y nodejs

ENV PATH $PATH:/opt/elixir-${ELIXIR_VERSION}/bin

RUN mix local.hex --force
ADD mix.exs mix.exs
ADD mix.lock mix.lock
RUN mix deps.get

WORKDIR /usr/local/phoenix
```

```yaml:docker-compose.yml
version: '3.7'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    command: mix phx.server
    volumes:
      - .:/usr/local/phoenix
    links: [db]
    ports:
      - 4000:4000
    stdin_open: true
    tty: true
  db:
    image: postgres:latest
    environment:
      - POSTGRES_USER=daily_report
      - POSTGRES_PASSWORD=daily_report
      - POSTGRES_DB=daily_report_dev
    ports:
      - 5432:5432
```

基本的にDockerfile,docker-compose.ymlではPhoenixをコンテナ上で動かすにはどうしたら良いのか、またソースコードを同期させるためにはどうしたら良いのかという方法で記述しました。

ただし、Elixirのコードを一度コンパイルするため、必要なソースを準備した後にコンテナ上で直接コンパイルする方法を取りました。

```zsh
% docker exec -it daily_report_web_1 /bin/bash
% mix compile
```

この辺り、他にも良い方法があれば教えていただけると幸いです。多分、結局コンパイルしないと実行できない以上、ソースコードを同期させるのももしかしたらバットプラクティスのような気もします。

## まとめ

今回は作りたいネタもあるので、引き続きコードを書いていきます。

## 参考文献

* [https://railsguides.jp/6_0_release_notes.html](https://railsguides.jp/6_0_release_notes.html)

* [https://hexdocs.pm/phoenix/overview.html](https://hexdocs.pm/phoenix/overview.html)

* [https://hexdocs.pm/phoenix/installation.html#content](https://hexdocs.pm/phoenix/installation.html#content)

* [https://github.com/asdf-vm/asdf](https://github.com/asdf-vm/asdf)