Elixir +  Phoenix Frameworkアプリケーション作成 [docker]

## 開発環境

* WSL2
* docker 20.10.*
* docker-compose

## 更新履歴
* [2022/11/21] `restart: always`の設定を削除しました。

## 手順

1. プロジェクト作成

    ```bash
    git init 
    ```

2. Up and Running
    * 公式 [https://hexdocs.pm/phoenix/installation.html] によるとmixで導入する。
    * Official image [https://hub.docker.com/_/elixir]を用いる。
    * 公式イメージにはhexがないので追加する。

    <div class="code-title" data-title="docker/Dockerfile">

    ```Dockerfile

    FROM elixir:1.14.1-slim

    WORKDIR /var/www/app

    RUN mix do \
        local.hex --force, \
        local.rebar --force, \
        archive.install --force hex phx_new

    ```

    </div>

     <div class="code-title" data-title="docker-compose.yml">

    ```yml

    version: "3"

    services:
        app:
            build: ./docker/
            ports:
                - "${APP_PORT:-4000}:4000" # phoenixのデフォルト
            volumes:
                - .:/var/www/app
            tty: true

    ```

    </div>

    * buildしてdocker-compose upして初期プロジェクト作成

    ```bash

    $ docker image build -t phoenix:latest docker/.
    $ docker-compose up -d
    $ docker exec -it phoenix-docker-app-1 bash

    root@a801b6f28926:/var/www/html# mix phx.new .
    The directory /var/www/html already exists. Are you sure you want to continue? [Yn] Y
    * creating config/config.exs
    ...
    * creating priv/static/favicon.ico

    Fetch and install dependencies? [Yn] Y

    * running mix deps.get

    We are almost there! The following steps are missing:

        cd .

    Then configure your database in config/dev.exs and run:

        mix ecto.create

    Start your Phoenix app with:

        mix phx.server

    You can also run your app inside IEx (Interactive Elixir) as:

        iex -S mix phx.server

    ```

3. 設定変更
    * IPの設定を変更する。dockerコンテナでプロジェクト作成をすると権限がなかったりするので`chmod`で適宜変更する。

     <div class="code-title" data-title="config/dev.exs">

    ```exs

    config :html, HtmlWeb.Endpoint,
        # Binding to loopback ipv4 address prevents access from other machines.
        # Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
        http: [ip: {0, 0, 0, 0}, port: 4000], # ここを0.0.0.0に変更
        check_origin: false,
        code_reloader: true,
        debug_errors: true,
        secret_key_base: "liMR8XBEdIZqzY96IB5pzS7KGUkL+O2r74hkcZ/0xBv9M/L+ktK5zvkD2Nx/Kht1",
        watchers: [
            # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
            esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}
        ]
    ```

    </div>

4. ローカルサーバを立ち上げる

    ```bash
    docker-compose up -d
    docker exec -it phoenix-docker-app-1 bash

    :/var/www/app# iex -S mix phx.server
    # DBの設定はしていないので、エラー表示がでる

    ```

5. DB設定
    * `docker-compose.yml`に追記と、初期化のための`init.sql`を作成する。

     <div class="code-title" data-title="docker-compose.yml">

    ```yml

    services:
        app:
            ...
            depends_on:
                - postgres
        postgres:
            image: postgres:15.0-alpine
            environment:
                - POSTGRES_USER=${POSTGRES_USER:-postgres}
                - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
            ports:
                - ${POSTGRES_PORT:-5432}:5432
            volumes:
                - ./docker/init:/docker-entrypoint-initdb.d

    ```

    </div>

     <div class="code-title" data-title="/docker/init/init.sql">

    ```sql

    CREATE USER docker;
    CREATE DATABASE html_dev;
    GRANT ALL PRIVILEGES ON DATABASE html_dev TO docker;

    ```

    </div>

     <div class="code-title" data-title="/config/dev.exs">

    ```exs

    config :html, Html.Repo,
        username: "postgres",
        password: "postgres",
        hostname: "postgres", # hostnameを変更

    ```

    </div>

6. docker-compose upでローカルサーバが立ち上げるように設定

     <div class="code-title" data-title="/docker/start-server">

    ```bash
    #!bin/bash
    mix phx.server

    ```

    </div>

    <div class="code-title" data-title="docker/Dockerfile">

    ```Dockerfile
    ...
    RUN mix do ...

    # 起動時にローカルサーバを起動するようにする
    COPY /entry.sh /usr/local/bin
    RUN chmod +x /usr/local/bin/entry.sh
    CMD [ "start-server" ]

    ```

    </div>

    * `docker-compose build --no-cacheでビルドしなおし`

7. `docker-compose up`

## 参考

<https://zenn.dev/tnka122/articles/abb6149f5a5f6c>