Elixir/Phoenix+MySQL5.7環境をDocker/Docker Composeで整え開発する。
##この記事を書いた理由1
手元の開発コンピュータが何であっても良いように開発環境を、いまさら・・Dockerの勉強も踏まえてみましたので、その共有です。
##この記事を書いた理由2
あー、これでApache、NginX、MySQLは、XAMPPやMAMPのやつ使って、足りないものはOS(MacOSX、Windows10などなど)にインストールして〜・・・ってのがなくなるし、新しいメンバーに開発環境整えてもらう時に、「動かないんですけど・・」で苦労することもなくなる〜。実際、社内でも、そうしてます。
##注意点
私がMacOSXを使用しているので、細かいターミナルでの操作などは、OSXベースになりますが、Windows10など、その他の方も、ほとんど同じなはずなので参考になると思います。
また今回はDockerを使用しています。DockerDesktopをインストールするなどしてください。Windows10では、Dockerは、確か、Professionalじゃないと動かなかったような気もしていますので、そのあたりは・・ご了承ください。 。
またDockerについては、細かく説明は、していません。
##キーワード
- Elixir
- Phoenix
- Docker
- Docker Compose
##アジェンダ
- Elixirの環境をDockerで起動できるようになる。
- Docker初体験
- 1.の環境(Dockerコンテナ)でPhoenixプロジェクトを作成して起動してみる。
- Phoenixプロジェクト作成・初体験
- MySQLもDockerで起動してPhoenixプロジェクトでDBも使えるようになる。
- DockerComposeで、複数Dockerをまとめる。
- プロジェクト一式をローカルPCにコピーする。
- 日々の開発が出来るか?確認する。
- 1日が終わってdocker-compose down。次の日に開発環境を起動する。
##1. Elixirの環境をDockerで起動できるようになる。
###1-1. 作業ディレクトリを作成する
ホームディレクトリ直下に、適当な作業ディレクトリを作成することにします。
とりあえず、ここでは、elixerというディレクトリを作成しました。
mkdir ~/elixir
cd elixir
###1-2. ElixirのDockerfileを作成する
テキストエディタで以下のようにDockerfileを作成します。
FROM elixir:alpine
###1-3. DockerでElixir環境を起動してみる。
早速、Elixirの環境を起動?してみましょう。Docker初めてな人は、起動というと変な感じかもですが。
まず、Dockerfileで記述した内容のものをbuildします。elixir_sampleという名前にしています。
docker build -t elixir_sample .
buildできたら、起動します。
docker run -p 4000:4000 -i -t elixir_sample /bin/ash
実行後、iexというコマンドを実行して、ex(1)> というのが出ていたら成功っす。
##2. 1.の環境(Dockerコンテナ)でPhoenixプロジェクトを作成して起動してみる。
###2-1. Phoenixフレームワークのインストール
1-3.のiex状態な人は、ctl+cを2回押してコマンド待ち状態になってください。そして以下のコマンドを実行します。
mix archive.install hex phx_new 1.4.0
途中、[Yn]と聞かれますが、何も考えずYで。
###2-2. プロジェクトを作成してみる。
このコマンドでsample_dbというプロジェクトを作成します。Phoenixフレームワークは、postgresqlがデフォルトDBになっているんですが、今回はMySQLを使用したいので、--databaseオプションで指定しています。
あ、、この時点では、まだMySQLサーバ自体は、ローカルにインストールも起動もされていません。sample_dbプロジェクトで使用するデータベース・サーバの指定のみです。
2-1.と同様に途中で[Yn]と聞かれますがYで。
mix phx.new sample_db --no-webpack --database=mysql
###2-3. プロジェクト起動してみる。
ここまでで、プロジェクトを起動してみましょう。
下のコマンドを実行します。
cd sample_db
iex -S mix phx.server
そして、少々待つと、
[info] Running SampleDbWeb.Endpoint with cowboy 2.6.1 at http://localhost:4000
と表示されます。
さらに、まだデータベースが用意されていないため、接続エラーがズラズラと表示されます。
[error] Mariaex.Protocol (#PID<0.2550.0>) failed to connect: ** (Mariaex.Error) tcp connect: econnrefused
が、、そんなものは、無視して、ブラウザにlocalhost:4000と入力して、
sample_dbプロジェクトが無事起動しているかを確認しましょう。
###2-4. データベースの設定
接続先のデータベースは未だ作ってないのですが、
その前に、Phoenixプロジェクト内のデータベースに関する設定をやっちゃいます。
cd config
vi dev.exs
として、設定ファイルdev.exsを開いて、
下のようにデータベースに関する部分を修正して保存します。
修正したのは、passwordの値とhostnameです。
passwordは、あとで作成するデータベースsample_db_devへの接続パスワードなので、
自由に設定してもらってOKです。ここでは root としています。
また、hostnameはデフォルトでlocalhostとなっているのですが、
db というものにしています。
localhostじゃないとダメなんじゃ・・? って思う方もいらっしゃるかもですが、
ここは、後述のDockerCompose関連が理由で、そうやっています。
config :sample_db, SampleDb.Repo,
username: "root",
password: "root",
database: "sample_db_dev",
hostname: "db",
pool_size: 10
###2-5. プロジェクトファイル群をローカルPCにコピー
2-2.で作成したsample_dbプロジェクトは、あくまでDockerコンテナに存在するリソースになります。つまり、これらのファイルを参照するためにはDockerコンテナに入る必要があります。
ということは・・・毎回(毎日?)、dockerコンテナ内にコマンド打って入って、
さらに、そのコンテナ内からファイルをさわる・・必要がある??
コンテナ内のファイルって、コンテナ外にあるテキストエディタで修正したり出来るのかな・・?
*この方法をジックリ調べていないので、次の様にしています。
私は、ローカルPCに、このプロジェクト一式をコピーし、Dockerコンテナ起動時にDockerコンテナにマウントする方法をとるようにしています。マウントについては、後述しますので、その準備として、ローカルPCにコピーします。
今、起動しているelixir_sampleコンテナを終了せずに、
新しいターミナルウィンドウを開いて、次のコマンドを打ちます。
docker ps
すると、次のように表示されるのでコンテナIDをコピーします。
ここでは、fe7dd49baeb5 です。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
fe7dd49baeb5 elixir_sample "/bin/ash" About a minute ago Up About a minute 0.0.0.0:4000->4000/tcp
つづけてローカルPCにコピーしていきます。
docker cp fe7dd49baeb5:sample_db .
sample_dbディレクトリ一式がローカルの~/elixir/sample_dbとしてコピーされていますか?
##3. MySQLもDockerで起動してPhoenixプロジェクトでDBも使えるようになる。
###3-1. MySQL用のDockerfileを用意する
~/elixir/mysqlディレクトリを作成して以下のDockerfileを用意します。
FROM mysql:5.7
###3-2. Elixir用のDockerfileファイルの修正
以下のように2行目以降を追加しておいてください。
FROM elixir:alpine
RUN mkdir /app
WORKDIR /app
RUN yes | mix local.hex
RUN yes | mix archive.install https://github.com/phoenixframework/archives/raw/master/phx_new.ez
RUN mix local.rebar --force
RUN apk update && \
apk upgrade && \
apk add --update\
bash \
curl-dev \
gcc \
g++ \
make \
git \
nodejs \
nodejs-npm \
&& rm -rf /var/cache/apk/*
###3-3. docker-compose.ymlファイルの作成
3-1.で、MySQLサーバもDockerで起動することが出来るのですが、このままだとDocker runをElixirとMySQLを使えるようになるために2回打たないといけません。こんな感じだと、そのほかのミドルウェアが必要になるたびにDocker runコマンドを打つ回数も増えます。
しかも、起動した後に、それぞれのサービスに対して毎回、、
1. 決まったコマンドを実行する必要があったり、
2. ボリューム(ローカルPCのディレクトリ領域を各サービスのDocker領域から共有したい)のマウントが必要になったり、、
すると、毎回コマンドを打つだけで大変ですし、その管理も大変になってしまいます。
そんなのを、まとめて管理してくれるのがDocker Composeです。
Docker Composeの詳しいことは、ネット上に詳しい方々がいらっしゃいますので、そちらなどを参照してください。
version: '3'
services:
db:
build: mysql/
volumes:
- ./mysql_lib:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=root
ports:
- "3306:3306"
app:
build: .
tty: true
volumes:
- ./sample_db:/app
ports:
- "4000:4000"
command: ash -c "mix deps.get && mix phx.server"
depends_on:
- db
volumes:
mysql:
driver: local
ここで行われていることを、ちょっとだけ説明しておきます。
-
db:
- db: は、MySQLコンテナの参照名にもなります。そのため2-4.でプロジェクトからMySQLへの接続に関してhostnameをdbにしています。
- volumes:でやっているのは、 MySQLのDockerコンテナにある/var/lib/mysqlフォルダをローカルPC上の~/elixir/mysql_libにマウントしています。これは、データベース(のデータ)をローカルPC上に持っておきたい(=永続化)ためです。そーじゃなかったら、やらなくてOKです。Dockerイメージを削除したりすると、データベース自体が消えてしまうので、毎回データベース作る必要が出てきます。それでも大丈夫だったら、やんなくてOKです。
- portsは、指定しなくても起動できるんですが、私は、MySQLWorkbenchをMacOSXで使っていて、ポート指定をしていないと、DockerコンテナのMySQLに接続できなかった(正確には、出来そうなのですが、ややこしい?)ので、指定しています。
-
app:
- volumes: では、2.5でローカルにコピーしていたプロジェクトをDockerコンテナ内にマウントしています。こーすることによって、プロジェクトファイルをローカルPC上から直接編集できるようになり、且つElixir/Phoenix環境が存在するDockerコンテナを利用して、このプロジェクトを実行することが出来ます。
###3-4. コンテナ(ElixirとMySQL)の同時起動
では、DockerComposeでElixir/Phoenix環境とMySQL環境を同時に起動します。
docker-composeコマンドを実行する前に、現在起動しているコンテナをstopしておきます。
そうしないと、既に4000ポートを、このコンテナ(elixir_sample)が使用しているので、起動できないっす。
ターミナルからdocker psコマンドを叩いて、コンテナIDを確認します。
docker ps
コンテナIDが確認できたら、次のコマンドを実行します。
docker stop コンテナID
ここまで出来たら、docker-composeコマンドで一気に2つのコンテナを作成してみましょう。
docker-compose up
2-3.の時と同様に、まだデータベースが作成されていないので、次の用に接続エラーが表示されると思いますが、一旦OKです。
ブラウザにlocalhost:4000で同じくPhoenixフレームワークの画面が表示されるかを確認してください。
###3-5. データベースの作成
とりあえず、このままでも、この記事の目的としては、大丈夫なのですが、データベース接続エラーが、気持ち悪いので、MySQLコンテナに入ってデータベースを作成してみましょう。docker psコマンドでMySQLコンテナのコンテナIDを確認しコピーします。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b07acadbaa95 elixir_db "docker-entrypoint.s…" 14 minutes ago Up 5 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp elixir_db_1
2つコンテナが確認できますが、データベースのコンテナは、このように**"_db"**という名前が付いていると思います。
では、続いてコンテナの中に入りましょう。
docker exec -it b07acadbaa95 /bin/bash
コンテナに入れたら、mysqlサーバーに接続して、データベースを作成します。データベース名は、2-4.のconfig/dev.exsに書かれてあったsample_db_devです。
mysql -uroot -proot
create database sample_db_dev default character set utf8;
作成できたら、一旦コンテナを停止して、再度起動します。
docker-compose down
docker-compose up
データベース接続エラーは、なくなりましたでしょうか?
##4. 日々の開発が出来るか?確認する。
###4-1. 1日の開始|コンテナ起動
これまでの おさらいになっちゃいますが、念のため書いておこうと思います。
作業を開始する時は、PCを起動して、以下のコマンドでコンテナを起動します。
cd ~/elixir
docker-compose up
###4-2. 作業
ソースコードは、~/elixir/sample_dbとしてプロジェクトファイルがありますので、それを修正していきます。
docker-compose.ymlで、Dockerコンテナ内にマウントしているので、ローカルPC上のソース・ファイルを直接、好きなエディタで編集可能です。
確認もブラウザなりから4000ポートを経由すれば出来ます。
あとは、gitにコミットしたりですね。
###4-3. 1日の終わり
dockerコンテナを停止して、PCの電源切りましょう。
docker-compose down
##まとめ
Elixir/Phoenixの開発環境のイメージと、Docker,DockerComposeを未だ使っていない方の、とっかかり や参考になれば嬉しいです。もっと、こんな方法があるよ! や、間違っている箇所があれば教えてください。 次回は、、Distilleryのデプロイ手法か、datadogで、Elixir/Phoenixの吐くログを見る設定なんかを投稿しようかと思っています(予定は未定)。