2016/10/18 21:07:58

公式MySQLコンテナでDockerコンテナの連携をしてみる

dokcer
目次(クリックするとジャンプします)
  • 1:Dockerでのコンテナはなるべく最小限にする。だから連携が必要
  • 1.1:1つプロセスで1つのコンテナ
  • 2:コンテナ連携
  • 2.1:linkオプションの使用例 公式のMySQLイメージの使用
  • 2.2:MySQLサーバコンテナの作成・起動
  • 2.2.1:セットアップに使う環境変数の意味
  • 2.2.1.1:環境変数の種類
  • 2.2.1.2:MYSQL_ROOT_PASSWORD
  • 2.2.1.3:MYSQL_DATABASE
  • 2.2.1.4:MYSQL_USER・MYSQL_PASSWORD
  • 2.2.2:MySQLサーバコンテナ起動
  • 2.2.2.1:コマンドの意味
  • 2.3:クライアントコンテナの作成・起動
  • 2.3.1:コマンドの意味
  • 2.3.1.1:補足
  • 2.4:クライアントからデータベースを見てみる
  • 2.4.0.1:出力された環境変数
  • 3:補足・ハマりポイント
  • 3.1:公式MySQLのデータ永続化について
  • 3.2:MySQLの設定の変更
  • 3.3:文字コードについて
  • 4:後記

Dockerでのコンテナはなるべく最小限にする。だから連携が必要

1つプロセスで1つのコンテナ

Dokcerではできるだけ1つプロセスで1つのコンテナという構成が推奨されるとのことです。

基本的にコンテナにはSSHなどでログインするのは推奨されていないようです。つまりサーバコンテナ側にsshdを立てるなということらしいです。

なのでいくつかのアプリケーションを連携させるには、コンテナの連携を学ぶ必要がありそうです。

コンテナをサーバみたく扱うことはできるのだけど、これだと後々なんらかのプロセスだけ差し替えたい、スケールしたいなどの場合に面倒になるようです。

@MINOには現時点でよくわかりませんが…。

ともかくもコンテナはなるべく最小限の状態であるべきと偉い人たちが言っているので素直に従いマス。

うむ。頑張ってみよう。

今回のテスト環境はGNU/Linux debian8です。

コンテナ連携

linkオプションの使用例 公式のMySQLイメージの使用

いろいろ試行錯誤しているうちにコンテナ連携にはlinkオプションを使うのがよいことを学びました。

よくあるケースとして、データベースコンテナとクライアントコンテナの連携を例に進めていきたいと思います。

今回の例では公式のMySQLイメージを使いたいと思います。

公式MySQLイメージはすぐにデータベースを使うことができるように設計されています。

docker run時にいくつかの設定をくっつけてあげれば、パスワード設定、データベース作成等を簡単に行うことができます。

@MINOのような初心者にはありがたいイメージです

MySQLサーバコンテナの作成・起動

まずは公式のMySQLイメージをpullします。テストなので特にバージョンを指定していません。

$ dokcer pull mysql

これでローカルに公式のMySQLイメージがダウンロードされたはずです。

セットアップに使う環境変数の意味

pullができたらrunをするのですが、その前に少し説明しておきたいことがあります。

公式MySQLイメージでは簡単にデータベースのセットアップをすることができます。

具体的には環境変数をつかったセットアップです。

環境変数の種類

公式MySQLイメージいくつかの環境変数が用意されており、runeオプションでその変数を設定することができます。

環境変数の種類と意味は以下です。

環境変数 意味
MYSQL_DATABASE データベースの名前を指定する
MYSQL_USER ユーザを作成する
MYSQL_PASSWORD ユーザパスワードを設定する
MYSQL_ROOT_PASSWORD rootのパスワードを設定する
MYSQL_ALLOW_EMPTY_PASSWORD パスワードなしでログインできるようにする
MYSQL_ROOT_PASSWORD

MySQLのrootのパスワードを指定します。この変数の設定は必須です。これを設定しないとエラーが出てrunが成功しません。

MYSQL_DATABASE

イメージ起動時に作成されるデータベースの名前を指定することができます。

ユーザー/パスワードを設定した場合(下記参照)、そのユーザーはこのデータベースへのスーパーユーザになります。(GRANT ALLに相当します)

MYSQL_USER・MYSQL_PASSWORD

新しいユーザーを作成・パスワード付与のオプションです。このユーザーはMYSQL_DATABASE変数で指定されたデータベースのスーパーユーザになります。

ユーザーを作成するためにはMYSQL_USERMYSQL_PASSWORD両方の変数が必要です。どちらかだけだとエラーになります。

MySQLサーバコンテナ起動

上記を踏まえて、MySQLサーバコンテナを起動させます。

docker run --name hogedb -e MYSQL_ROOT_PASSWORD=password -e MYSQL_USER=hoge -e MYSQL_PASSWORD=hogepass -e MYSQL_DATABASE=db -d mysql
コマンドの意味
コマンド 意味
docker run コンテナの作成及び起動
–name hogedb コンテナに名前をつけるオプション。例ではhogedb
-e MYSQL_ROOT_PASSWORD=password rootのパスワード設定。例ではpassword
-e MYSQL_USER=hoge ユーザの名前設定。例ではhoge
-e MYSQL_PASSWORD=hogepass ユーザパスワード設定。例ではhogepass
-e MYSQL_DATABASE=db 作成されるデータベースの名前。例ではdb
-d デタッチ状態(バックグラウンド動作)での起動オプション
mysql コンテナの元になるイメージ

これでdbというデータベースを持ち、hogeというユーザがいるMySQLサーバコンテナがバックグラウンドで起動しました。

docker psコマンドで確認してみてください。NAMESdbというコンテナが起動しているのがわかるかと思います。

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 
5d7489f5d22c mysql "/entrypoint.sh mysql" 2 hours ago Up 2 hours 3306/tcp db

クライアントコンテナの作成・起動

上記の手順で今ホストPC上にはMySQLサーバコンテナがまるでデーモンのように起動しています。

このコンテナと連携するのにlinkオプションを使います。

linkオプションを使うには、link対象のコンテナが起動している必要があります。そのため、先ほど起動させたMySQLサーバコンテナは起動させたままにしてください。

さて今度はクライアントを起動させます。コマンドは以下です。

docker run --name dbclient --link db:mysql -it mysql /bin/bash

コマンドの意味

コマンド 意味
docker run コンテナの作成及び起動
–name dbclient コンテナに名前をつけるオプション。例ではdbclient
–link db:mysql –linkオプションで連携するコンテナを指定。指定はコンテナ名で行っている
-it iオプションはコンテナの標準入力へのアタッチ。tオプションはttyの割り当て。つまりコンテナの中に入れるようになる。
mysql クライアントコンテナ構築に使うイメージ
/bin/bash コンテナ起動後にbashシェルを起動させる
補足

クライアントコンテナのイメージもサーバコンテナでつかったイメージと同じものを使っています。 最初なんでかなと思いました。

クライントコンテナはデータベースサーバコンテナに命令を与えることが役目ですが、MySQLをコマンドラインで操作したいならクライアントコンテナにもコマンドを打つためにMySQLが導入されている必要があります。

なので同じイメージ(MySQLが入っていれば良い)を使います。

もちろんPHPなどからMySQLを使うならクライアントにMySQLのインストールは必要なく、PDOなどのエクステンションが導入されていればOKです。

クライアントからデータベースを見てみる

クライントコンテナを起動させた時点でプロンプトが以下のようにクライントに移行しているかと思います。

プロンプトの構成は若干違うかもしれません。また@の後ろはコンテナのホスト名なので環境ごとに異なる可能性があります。

root@a6e4178c5e6d:/#

早速DBサーバコンテナに繋げたいと思いますが、その前にDBサーバコンテナのアドレスを確認しておきます。

以下を実行するとずらずらと環境変数がでてくると思います。

root@a6e4178c5e6d:/# env
出力された環境変数
MYSQL_ENV_MYSQL_DATABASE=db
MYSQL_ENV_MYSQL_ROOT_PASSWORD=password
TERM=xterm
MYSQL_VERSION=5.7.10-1debian8
MYSQL_PORT_3306_TCP_PORT=3306
MYSQL_PORT_3306_TCP=tcp://172.17.0.2:3306
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MYSQL_ENV_MYSQL_USER=hoge
PWD=/
MYSQL_ENV_MYSQL_PASSWORD=hogepass
MYSQL_ENV_MYSQL_VERSION=5.7.10-1debian8
HOME=/root
SHLVL=1
MYSQL_PORT_3306_TCP_PROTO=tcp
MYSQL_NAME=/dbclient3/mysql
MYSQL_MAJOR=5.7
MYSQL_PORT_3306_TCP_ADDR=172.17.0.2
MYSQL_ENV_MYSQL_MAJOR=5.7
MYSQL_PORT=tcp://172.17.0.2:3306

すごく乱暴なことを言えば、linkオプションとはこれらの環境変数を吐き出すためのオプションと言えます

この中でMYSQL_PORT_3306_TCP_ADDRとして出力されている172.17.0.2がDBサーバコンテナのアドレスになります。

実際は以下のように変数として指定してあげれば172.17.0.2を指定したことになります。

root@a6e4178c5e6d:/# mysql -u hoge -p -h $MYSQL_PORT_3306_TCP_ADDR db

パスワードを入力してログインに成功すると、以下のようにMySQLのコマンドラインに移行します。

root@a6e4178c5e6d:/# mysql -u hoge -p -h $MYSQL_PORT_3306_TCP_ADDR db
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 4
Server version: 5.7.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql> 

あとはテーブルを作るとかユーザを作るとかすればいいよ。

補足・ハマりポイント

公式MySQLのデータ永続化について

公式MySQLではデータが永続的に使えるように設定されています。データベースだからデータはいちいちなくなったら面倒な場合もありますからね。

MySQLコンテナがデータを永続化するために、ホストのどこにディレクトリをマウントしているかについては以下のコマンドで調べることができます。

$ dokcer inspect コンテナID

どばっといろんな情報が出力されるますが、以下のようなMountsに関する出力があるかと思います。

"Mounts": [
        {
            "Name": "4b538bd7dec36757b9cd2133a5e66725812b07745eb324012156465f635c4047",
            "Source": "/var/lib/docker/volumes/4b538bd7dec36757b9cd2133a5e66725812b07745eb324012156465f635c4047/_data",
            "Destination": "/var/lib/mysql",
            "Driver": "local",
            "Mode": "",
            "RW": true
        }
    ],

Sourceがホスト側のディレクトリ、Destinationがコンテナ側のディレクトリです。この場合/var/lib/mysqlには/var/lib/docker/volumes/4b538bd7dec36757b9cd2133a5e66725812b07745eb324012156465f635c4047/_dataがマウントされているということになります。

MySQLで書き込みしたデータは実質的にホストのディレクトリに保存されているということになります。

これは公式MySQLのDockerfile内で以下のようにVOLUME指定がされている為です。

VOLUME /var/lib/mysql

この方法ではホストにデータが依存する形になりますので、可搬性に問題がでてきます。

そのため、より自由度を高める為、データを格納することを専門とするボリュームコンテナをこしらえてマウントするの定石とされています(と、もっぱらの噂です)。

MySQLの設定の変更

my.cnfにて設定を変えたい場合があるかもしれません。公式MySQLのDokcerfileでは以下の方法で設定を変更しています。

Docker公式MySQLのDockerfile(GitHub)

RUN sed -Ei 's/^(bind-address|log)/#&/' /etc/mysql/my.cnf 
    && echo 'skip-host-cachenskip-name-resolve' | awk '{ print } $1 == "[mysqld]" && c == 0 { c = 1; system("cat") }' /etc/mysql/my.cnf > /tmp/my.cnf 
    && mv /tmp/my.cnf /etc/mysql/my.cnf
コマンド 意味
sed -Ei ‘s/^(bind-address|log)/#&/’ /etc/mysql/my.cnf 正規表現でbind-addressまたはlogとなっているところをコメントアウト
&& echo 'skip-host-cache-name-resolve' skip-name-resolveは「DNS問い合わせを使用しない」、skip-host-cacheは「接続ごとにDNSサーバに問い合わせ」という意味
awk ‘{ print } $1 == "[mysqld]" && c == 0 { c = 1; system("cat") }’ /etc/mysql/my.cnf > /tmp/my.cnf /etc/mysql/my.cnfの[mysqld]と記述されている次の行にskip-host-cache-name-resolveを挿入し/tmp/my.cnfに出力
&& mv /tmp/my.cnf /etc/mysql/my.cnf /etc/mysql/my.cnfにファイルを上書きする

sedawkを使ってワンライナーで設定を変更しています。@MINOはsedawkはほとんど使ったことがないので勉強しなければなりません。

Dockerを使いこなすにはこれらのいわゆる「シェル芸」に慣れる必要があるかもしれません。

もちろん設定ファイルを別途マウントする方法はありますが、Dockerfile内にワンライナーとして記述できたほうが一元的に設定を管理でき便利な気がします。

文字コードについて

Docker公式のMySQLはマルチバイト向けの設定になっていない(文字コードがUTF8じゃない)ので、設定を変える必要がありそうです。

マルチバイト語族をなめるなよ〜。

後記

コンテナの連携ができるとだんだんDockerの真価がわかってきたような気がします。開発環境がこれほど簡単に操れるのはすごいことですよね。そりゃ話題にもなりますよね。

もっと勉強していきたいと思います。