the industrial

ブログと言うより自分のためのメモ以外の何モノでもないです。でも読んでくださってありがとうございます。

Play Framework / Scala 再入門 3日目

3日目は

  • Docker を導入する
  • MySQL を Docker Container で動かす
  • Playframework を Docker Container で動かす

をやりました。

今作っているアプリのディレクトリ構成

ざっとこんな感じ。

.
├── api
├── docker
└── web
  • api/ ディレクトリは Playframework のプロジェクトが格納されている。
  • web/ ディレクトリは現在空っぽで、フロントエンドのプロジェクトが格納される予定(Elm で作る予定)。
  • docker/ ディレクトリは、これらのプロジェクトを Docker Container で動かす設定を格納する。

今日は、 docker/ の中身を実装していく。

MySQL をコンテナ上で動かす

これは何度もやっているのでサラッと。

ディレクトリ構造

.
└── docker
    └── mysql
        ├── Dockerfile
        ├── conf.d
        │   └── custom.cnf
        ├── my.cnf
        └── sql
            └── create_database.sql

先程の docker/ ディレクトリに、この様な感じでファイルやディレクトリを追加。

Dockerfile

単純にこんな感じ

FROM mysql:5.7

conf.d / my.cnf

これらの MySQL の設定ファイルなどは、後ほど docker-compose.yaml にてコンテナにマウントさせる。

sql/create_database.sql

今回は create database が記載された単純な SQL ファイル。

コンテナ内の /docker-entrypoint-initdb.d にマウントさせると初回自動でテーブルなどを作成してくれる。

docs.docker.com

こちらも後ほど docker-compose.yaml にてコンテナにマウントさせる。

ただし、Database は後述の MYSQL_DATABASE で作ってくれたりするし、今回は特に内容を記述していない。

Playframework をコンテナ上で動かす

ディレクトリ構造

API 用のディレクトリに Dockerfile を配置するだけ。

.
└── api
    └── Dockerfile

Dockerfile

Dockerfile の中身はこんな感じ。

FROM hseeberger/scala-sbt:8u212_1.2.8_2.12.9

RUN mkdir /project-name

WORKDIR /project-name

ADD . /project-name

RUN cd /project-name

イメージはコチラを利用。

https://hub.docker.com/r/hseeberger/scala-sbt/

Scala の version が今 2.12.8 なので、 scala-sbt:8u212_1.2.8_2.12.9 を選択。

2.13.x にしないとなあ...。

ADD . /project-name でプロジェクト内のソース(つまり Playframework のソース)を追加している。

WORKDIR /project-name を設定しないと、立ち上げたときに下記のようなエラーが出るので注意。

    | [error] java.lang.RuntimeException: No main class detected.
    | [error]   at scala.sys.package$.error(package.scala:26)
    | [error] (Compile / bgRun) No main class detected.
    | [error] Total time: 1 s, completed Aug 16, 2019 9:39:16 AM

docker-compose.yaml の定義

こんな感じ。

version: '2'
services:
  project_name_db:
    container_name: project_name_db
    image: project_name_db
    build: ./mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: project_name
      MYSQL_USER: root
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
    volumes:
      - project_name_db_volume:/var/lib/mysql
      - "./mysql/sql:/docker-entrypoint-initdb.d"
      - "./mysql/conf.d/:/etc/mysql/conf.d/"
      - "./mysql/my.cnf:/etc/mysql/my.cnf"
  project_name_api:
    container_name: project_name_api
    image: project_name_api
    build: ../api
    command: sbt run
    volumes:
      - ../api:/project_name
      - project_name_api_volume:/project
    ports:
      - "9000:9000"
    depends_on:
      - project_name_db
    stdin_open: true
    tty: true

volumes:
  project_name_db_volume:
    driver: local
  project_name_api_volume:
    driver: local

MySQL のコンテナ設定

下記が MySQL

  project_name_db:
    container_name: project_name_db
    image: project_name_db
    build: ./mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: project_name
      MYSQL_USER: root
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
    volumes:
      - project_name_db_volume:/var/lib/mysql
      - "./mysql/sql:/docker-entrypoint-initdb.d"
      - "./mysql/conf.d/:/etc/mysql/conf.d/"
      - "./mysql/my.cnf:/etc/mysql/my.cnf"

volumes:
  project_name_db_volume:
    driver: local

コンテナ名を指定

    container_name: project_name_db

イメージ名を指定

    image: project_name_db

MySQL 用の Dockerfile の場所を指定

    build: ./mysql

ポートを指定

    ports:
      - "3306:3306"

環境変数を指定

MYSQL_DATABASE を指定するとコンテナ起動時に Database を作成してくれる。

docs.docker.com

    environment:
      MYSQL_DATABASE: project_name
      MYSQL_USER: root
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"

volume を指定

    volumes:
      - project_name_db_volume:/var/lib/mysql
      - "./mysql/sql:/docker-entrypoint-initdb.d"
      - "./mysql/conf.d/:/etc/mysql/conf.d/"
      - "./mysql/my.cnf:/etc/mysql/my.cnf"

volume について、下記が先程書いた初期SQL

      - "./mysql/sql:/docker-entrypoint-initdb.d"

下記が MySQL の設定関連

      - "./mysql/conf.d/:/etc/mysql/conf.d/"
      - "./mysql/my.cnf:/etc/mysql/my.cnf"

下記は、作成したデータベースなどをコンテナを消しても永続化させる設定

      - project_name_db_volume:/var/lib/mysql

volume は下記コマンドで確認することが出来る

$ docker volume ls
DRIVER              VOLUME NAME
local               docker_project_name_db_volume

Playframework のコンテナ設定

下記が Playframework 用

  project_name_api:
    container_name: project_name_api
    image: project_name_api
    build: ../api
    command: sbt run
    volumes:
      - ../api:/project_name
      - project_name_api_volume:/project
    ports:
      - "9000:9000"
    depends_on:
      - project_name_db
    stdin_open: true
    tty: true

volumes:
  project_name_api_volume:
    driver: local

下記は MySQL と同じなので割愛

  project_name_api:
    container_name: project_name_api
    image: project_name_api
    build: ../api
・・・
    ports:
      - "9000:9000"
・・・

下記はコンテナを立ち上げたときに実行するコマンド。単純に sbt run しているだけ。

    command: sbt run

下記は、MySQL が立ち上がったら、当該 Playframework のコンテナを立ち上げるといったようなコンテナ間の依存関係の設定。

    depends_on:
      - project_name_db

下記はコンテナ立ち上げっぱなし、コンソール表示、みたいな設定(チョー乱暴な説明)。まあ今更説明せんでも・・・なノリでご愛嬌。

    stdin_open: true
    tty: true

同じく volume の設定。

    volumes:
      - ../api:/project_name
      - project_name_api_project_volume:/project
      - project_name_api_target_volume:/target

volumes:
  project_name_api_project_volume:
    driver: local
  project_name_api_target_volume:
    driver: local

volume に設定しておかないと、コンテナを立ち上げるたびに sbt の build が走ってしまうので、必ず設定する。

追記

どうにも docker-compose.yaml を更新しただけで、sbt の build が走ってしまう。

volume をちゃんと読み込んでいる場合

 [info] Loading settings for project project_name-build from plugins.sbt ...
 [info] Loading project definition from /project_name/project
 [info] Loading settings for project root from build.sbt ...
 [info] Set current project to api (in build file:/project_name/)

 --- (Running the application, auto-reloading is enabled) ---

 [info] p.c.s.AkkaHttpServer - Listening for HTTP on /0.0.0.0:9000

 (Server started, use Enter to stop and go back to the console...)

docker-compose.yaml を編集すると再ビルドが・・・。

 [info] Loading settings for project project_name-build from plugins.sbt ...
 [info] Loading project definition from /project_name/project
 [info] Updating ProjectRef(uri("file:/project_name/project/"), "project_name-build")...

ここらへんどうにかしないと Docker を入れると逆につらくなるので駄目だ。

やりたいこととしては、docker-compose build したときだけ sbt の build を実行して欲しい。

うーむ。

ビルドや起動など

ここからは基本的に docker-compose の作業。

下記ディレクトリに移動し

.
└── docker

下記コマンドでビルドと実行する。

$ docker-compose up

Shell を作ってしまう

僕はこんなシェルを作ってしまっている。

  • rwxr-xr-x build.sh
  • rwxr-xr-x exec.sh
  • rwxr-xr-x login.sh
  • rwxr-xr-x restart.sh
  • rwxr-xr-x start.sh
  • rwxr-xr-x stop.sh

build.sh

単純にビルドしたい場合に利用

#!/bin/zsh
docker-compose build $1 $2 $3 $4 $5 $6 $7 $8 $9

exec.sh

コンテナ内部に対して何らかのコマンドを実行したい場合に利用。

#!/bin/zsh
docker-compose exec project_name_api $1 $2 $3 $4 $5 $6 $7 $8 $9

login.sh

コンテナ内部にログイン(表現間違っているかも)するときに利用。

#!/bin/zsh
docker exec -it project_name_api /bin/bash

restart.sh

コンテナを再起動する。

#!/bin/zsh

rm ../tmp/pids/server.pid

docker-compose stop

docker-compose up

start.sh

コンテナを起動する。

restart.sh を使っているのでコチラはあまり使わない。

#!/bin/zsh

rm ../tmp/pids/server.pid

docker-compose up

stop.sh

コンテナを停止する。

#!/bin/zsh

rm ../tmp/pids/server.pid

docker-compose stop

下記を指定しているのは、時々プロセスが残ってしまうことがあったので。

rm ../tmp/pids/server.pid

前回

omiend.hatenablog.jp

次回

MySQL と ScalikeJDBC の設定をしたいと思います。