LoginSignup
4
4

More than 5 years have passed since last update.

docker-composeを使ってMySQL + webフレームワークrevelの開発環境を作る

Last updated at Posted at 2018-12-21

概要

記事の題名そのままです。
前の記事でrevelでapiサーバー作ったので、docker-composeにまとめてみました。

途中ハマったところなどをメインにまとめてみます。

動作環境

Mac OS Mojave 10.14
docker Version: 18.09.0
docker-compose version 1.23.2, build 1110ad01
Revel Framework : 0.21.0

Dockerfileの設定

FROM golang

COPY . /go/src
WORKDIR /go/src
# 必要なパッケージなどをインストールする
RUN apt-get update -qq && \
    apt-get install -y mysql-client vim && \
    # install revel 
    go get -u github.com/revel/revel && \
    go get -u github.com/revel/cmd/revel && \
    # install gorm
    go get -u github.com/jinzhu/gorm 

EXPOSE 9000

docker-compose.ymlの設定

docker-compose.yml
version: '3'
services:
  mysql:
    image: mysql:5.7 
    container_name: mysql
    hostname: mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: password
    # MySQLの文字コードを指定する
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci --skip-character-set-client-handshake
    volumes:
      # DBデータの永続化
      - "db-data:/var/lib/mysql"
      # MySQL起動時にDBを作成し、初期データの投入する
      - ./initdb.d:/docker-entrypoint-initdb.d 
  sample_docker_compose:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: sample_docker_compose
    ports:
      - "9000:9000"
    command: bash ./scripts/start.sh
volumes:
  db-data:
    driver: local

通常、コンテナの中身は一度コンテナが停止するとまっさらな状態になりますが、docker-compose.ymlファイルのトップにvolumesを設定することによって、停止した後に再起動してもデータがそのまま残っている状態になります。

ちなみに、db-dataのvolumesはdocker volume rmのコマンドで消去することもできます。

初期データを投入する際は、docker-compose.ymlと同階層にある「initdb.d」という名前のディレクトリ配下に「.sql」ファイルを入れておきます。そのディレクトリに入っている「.sql」「.sh」「.sql.gz」ファイルが実行されます。
参考:https://hub.docker.com/_/mysql/

commandは、一つのコンテナにつき、一つしか書けないので、余分な分はシェルスクリプトを実行するようにします。シェルスクリプトでは、MySQLの処理が完了してから、アプリケーションを起動するようにします。

# !/bin/bash

# MySQLサーバーが起動してからGolangのアプリケーションを起動させる
until mysqladmin ping -h mysql --silent; do
  echo 'waiting for mysqld to be connectable...'
  sleep 2
done

echo 'app is starting...'
exec revel run api-server

参考:https://qiita.com/yu-croco/items/0c0d5083298f7db9e1bb

docker-compose.ymlで指定したコンテナは、同じネットワーク上に存在することになるので、相互に作用することが可能です。その際に、コンテナのIPを指定するのではなく、コンテナのホスト名を指定することができます。今回の場合はGoアプリケーション側からMySQLへアクセスするので、mysqlがホスト名になります。

試しにhostのMacからMySQLに接続してみる

$ docker-compose up -d

-dオプションはバックグランドでの実行。

$ mysql -h mysql --port 3306 -u root -p

-hまたは、--hostで、IPを指定する。-h 127.0.0.1も可能。
--portでport番号を指定する。デフォルトは、3306。
-uでユーザーを指定する。
-pは、パスワードの有無。

トラブルシューティング

ここで、ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)のようなエラーがでた場合、もしかすると別のプロセスでローカルのMySQLが動いている可能性があるので、そちらを完全に止める(自分の場合、MacのローカルでもMySQLを動かしていたため、dockerの方ではなく、ローカルの方を参照しようとしていて、アクセスが拒否されていました)。

具体的には、mysql.server stopで停止できるはずですが、これも機能しない場合、プロセスから切ってしまいます。

$ mysql.server stop
 ERROR! MySQL server process #5470 is not running!
$ ps ax | grep mysql
14594   ??  S      0:00.02 /bin/sh /usr/local/Cellar/mysql/8.0.12/bin/mysqld_safe --datadir=/usr/local/var/mysql --pid-file=/usr/local/var/mysql/MacBook-puro.local.pid
14693   ??  S     10:32.73 /usr/local/Cellar/mysql/8.0.12/bin/mysqld --basedir=/usr/local/Cellar/mysql/8.0.12 --datadir=/usr/local/var/mysql --plugin-dir=/usr/local/Cellar/mysql/8.0.12/lib/plugin --log-error=MacBook-puro.local.err --pid-file=/usr/local/var/mysql/MacBook-puro.local.pid
31608 s001  S+     0:00.00 grep mysql

で出てきたプロセスをkillします。

$ sudo kill -TERM 14594
$ sudo kill -TERM 14693
$ ps ax | grep mysql
31674 s001  S+     0:00.01 grep mysql

MacのMySQLサーバーが停止したら、コンテナの方のMySQLとの接続もうまくいきました。
MySQLのプロセスの確認。
きちんと動いていたら、mysqld is aliveが表示されます。

$  mysqladmin ping -h 127.0.0.1 --port 3306 -u root -p
Enter password:
mysqld is alive

golangのコンテナからMySQLコンテナに接続する

ERROR 2005 (HY000): Unknown MySQL server host 'api-server_db_1' (-2)

これにはいくつか原因が考えられます。

アプリケーション側の問題

今回は、GoのRevelと呼ばれるフレームワーク内で、gormを使って接続をしたのですが、tableの指定をしていないかったために、接続ができないことがありました。

アプリケーションロジックの中でDB.Table(TABLE_NAME).Find(&User)のように、きちんとtable名を指定してあげれば、問題なく動きました。

docker-composeの設定の問題

docker-compose upで、一度立ち上げたものの、両方のコンテナが立ち上がらないことがあります。そのときに、コンテナの中で、作業して、もう一度アプリケーションを起動させても、MySQLとの接続がうまくいきません。これは、docker-composeの性質上、同じタイミングで立ち上がったコンテナは、同じネットワーク内の者として認識されますが、逐一立ち上げた場合はそれには当てはまらないという仕様になっていることがあげられます。
逐一立ち上げてコンテナ同士の接続をする場合は、--linkを使う必要があります。

MySQL側の問題

mysql:latestで立ち上げたときに、エラーが出ました。
これは、バージョンの問題で、最新版のMySQL8.0系だとログインの仕方が違うため、同じやり方ではうまくいかないみたいです。

参考:https://employment.en-japan.com/engineerhub/entry/2018/09/18/110000

dockerのvolumesとdockerfileのcopyについて

volumesでマウントするタイミングと、シェルスクリプト実行のタイミングが合わずにエラーがでました。
これについては、次の記事が同じ状況を書いていたので参考になりました。

参考:https://kuroeveryday.blogspot.com/2016/11/docker-compose-volumes.html

おまけーコンテナ内部に入って修正作業ー

docker-composeで立ち上げたものの、何らかのエラーでexitedしてしまったコンテナをもう一回立ち上げるには、docker commitを使うと良いです。

Dockerfiledocker-compose.ymlの編集をするときに結構使いました。

次のコマンドでimageが生成されます。

$ docker commit {コンテナID} {任意の名前}

そのimageを立ち上げて、コンテナの中に入ります。

$ docker run --rm -it {任意の名前} /bin/bash

参考:https://qiita.com/mom0tomo/items/35dfacb628df1bd3651e

長々書きましたが、結構色々なエラーが出てその度に調べていたので、docker周り詳しくなった気がします。docker奥深いなあ(小並感)

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4