Dockerを使ってHerokuへPhoenixアプリをデプロイする

主夫在宅パートのeitoballです。野菜の値段が高くて、ちょっと困っているこの頃です。

HerokuがDocker対応を2ヶ月半ほど前に発表しました。そこで、試しにPhoenix Frameworkを使ったアプリをDocker対応経由でHerokuへデプロイしてみましたので、共有したいと思います。

関連記事

はじめに

今回の事前条件としては、

になります。

アプリの作成

おなじみのmixを使って作成します。

$ mix phoenix.new hello_heroku
* creating hello_heroku/config/config.exs
...

dockerプラグインのインストール

以下のコマンドを実行して、dockerプラグインをインストールします。

$ heroku plugins:install heroku-docker
Installing plugin heroku-docker... done

Dockerfileの作成

先ほど、作成したアプリのディレクトリに移動して、以下のコマンドを実行します。

$ heroku docker:init
Wrote Dockerfile (node)

HerokuへデプロイできるDockerコンテナを作成するDockerfileが作成されます。

Dockerfileの編集

Dockerfileを次のように編集します。

FROM heroku/cedar:14

RUN locale-gen en_US.UTF-8
RUN cp /usr/share/zoneinfo/Japan /etc/localtime

RUN useradd -d /app -m app
USER app
WORKDIR /app

ENV HOME /app
ENV NODE_ENGINE 0.10.38
ENV PORT 3000

RUN mkdir -p /app/heroku/node
RUN mkdir -p /app/src
RUN curl -s https://s3pository.heroku.com/node/v$NODE_ENGINE/node-v$NODE_ENGINE-linux-x64.tar.gz | tar --strip-components=1 -xz -C /app/heroku/node
ENV PATH /app/heroku/node/bin:$PATH

RUN mkdir -p /app/.profile.d
RUN echo "export PATH=\"/app/heroku/node/bin:/app/bin:/app/src/node_modules/.bin:\$PATH\"" > /app/.profile.d/nodejs.sh
RUN echo "cd /app/src" >> /app/.profile.d/nodejs.sh
WORKDIR /app/src

RUN mkdir -p /app/erlang
RUN curl -s https://s3.amazonaws.com/s3.hex.pm/builds/erlang/cedar-14/OTP-17.5.tar.gz | tar --strip-components=1 -xz -C /app/erlang
RUN /app/erlang/Install -minimal /app/erlang
ENV PATH /app/erlang/bin:$PATH

RUN mkdir -p /app/elixir
RUN curl -s https://s3.amazonaws.com/s3.hex.pm/builds/elixir/v1.0.4.zip -o /app/elixir/v1.0.4.zip
RUN (cd /app/elixir; unzip -q v1.0.4.zip)
ENV PATH /app/elixir/bin:$PATH

ENV LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8
RUN mix local.hex --force && mix local.rebar --force

RUN echo "export PATH=\"/app/elixir/bin:/app/erlang/bin:\$PATH\"" > /app/.profile.d/elixir.sh

ONBUILD COPY . /app/src
ONBUILD USER root
ONBUILD RUN chown -Rh app /app/src
ONBUILD USER app
ONBUILD RUN mix do deps.get, deps.compile
ONBUILD RUN rm -rf node_modules
ONBUILD RUN npm install
ONBUILD RUN node_modules/.bin/brunch build
ONBUILD RUN sed -e 's/port: 4000/port: 3000/' -i config/dev.exs
ONBUILD RUN MIX_ENV=prod mix do compile.protocols, phoenix.digest
ONBUILD EXPOSE 3000

ポイントはアセットファイルやアプリを事前にコンパイルしていることです。(下から4行目と2行目)

Procfileの作成

Procfileにデプロイ後にどのようにアプリを実行するかを記述します。以下の内容でProcfileを作成します。

web: MIX_ENV=prod elixir -pa _build/prod/consolidated -S mix phoenix.server

コンパイルされてまとまったアプリを実行します。

ローカル環境でのテスト

ローカル環境でアプリを動作させてみます。heroku docker:startで起動します。

$ heroku docker:start
building image...
...
tarting container...
web process will be available at http://192.168.0.1:3000/
01:23:45.678 [info] Running HelloHeroku.Endpoint with Cowboy on port 3000 (http)

表示されている(環境によって異なります)IPアドレスにブラウザでアクセスして、

Welcome to Phoenix!

のような画面が表示されれば、テストは成功です。

Herokuへのデプロイ

Heroku上にアプリを新規作成して、アプリをデプロイします。

$ heroku create
Creating some-fake-1234... done, stack is cedar-14
https://some-fake-1234.herokuapp.com/ | https://git.heroku.com/desolate-lake-5348.git
$ heroku docker:release --app=some-fake-1234
creating local slug...
building image...
Sending build context to Docker daemon
...
uccessfully built 936664d30cff
creating remote slug...
uploading slug...
releasing slug...
$ heroku open --app=some-fake-1234

ブラウザにローカル環境でテストした時と同じ画面が表示されれば、デプロイ成功です。

データベースへの接続

データベースに接続する例です。Heroku Postgresの場合、はじめにプラグインを追加して、

$ heroku addons:create heroku-postgresql:hobby-dev --app=some-fake-1234

データベースの接続情報を環境変数DATABASE_URL)から取得するように設定を変更します。

config/prod.exs

config :hello_heroku, HelloHeroku.Repo,
  adapter: Ecto.Adapters.Postgres,
  url: System.get_env("DATABASE_URL")

さいごに

駆け足でDockerを使って、HerokuへPhoenixアプリをデプロイしてみました。Dockerを使う利点としては、

  • Herokuと同じ実行環境で、ローカルでもアプリを実行できる。
  • buildpackより、自由に実行環境を設定できる。

だと思います。Herokuを使っている、もしくは、興味ある方は、お試し下さい。