プログラミング初心者がアーキテクトっぽく語る

見苦しい記事も多数あるとは思いますが訂正しつつブログと共に成長していければと思います

DockerでMySQLを試してみる

先日、nginxのDockerを試しました。その勢いでデータベースのDockerも試してみます。

まずは一番有名なMySQLからです。MySQLは大昔に触ったことがありますが、Dockerでセットアップするのは始めてです。Docker固有のポイントがあると思うので勉強していきたいと思います。


コンテナ実行

docker run -d --name mydb --env MYSQL_ROOT_PASSWORD=mysecret mysql

MYSQL_ROOT_PASSWORDは必須の環境変数です。Rootのパスワードを指定します。

タグを指定していないのでmyslq:latestが使われます。myslq:latestのDockerfileを覗いてみるとdebian:buster-slimでMySQLのバージョンは8.0だそうです。


コンテナに接続

docker exec -it mydb /bin/bash

Dockerfileを確認したらENTRYPOINTを使っているので「docker run -it mysql /bin/bash」のようにしてシェルを起動することはできません。大人しくdocker execでコンテナに接続します。

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["mysqld"]

MySQLの起動に使われている/usr/local/bin/docker-entrypoint.shはかなり手の混んだシェルスクリプトで私には読めませんでした。


MySQLにログイン

mysql -u root -p

パスワードを要求されたらMYSQL_ROOT_PASSWORDで指定した「mysecret」を入力します。


データベース作成

create database test;
show databases;
connect test;

当たり前ですがmysqlの中に入ると普通のMySQLと同じです。


テーブル作成

create table books ( id int auto_increment not null primary key, title varchar(64) not null, in_stock boolean not null default 0);
show tables;
show create table books;

以下のようなテーブルを作成しました。

  • idは自動採番
  • titleは必須。型は文字列。
  • in_stockは真偽値でデフォルトはFalse。真偽値は内部ではtiny_intという数値。

エントリ作成

insert into books (title) values ("Docker 101");
insert into books (title, in_stock) values ("Introduction to MySQL", true);
select * from books;

コンテナが消えるとデータも消える

exit
docker stop mydb
docker start mydb
docker exec -it mydb /bin/bash
mysql -u root -p
<データはまだある>

コンテナの停止、開始ではデータは消えません。

exit
docker stop mydb
docker rm mydb
docker run -d --name mydb --env MYSQL_ROOT_PASSWORD=mysecret mysql
docker exec -it mydb /bin/bash
mysql -u root -p
<データはない>

コンテナを削除、再作成するとデータはありません。データを維持するにはvolumeを使います。


volume

volumeにはnamed volumeとbind mountがあります。bind mountは開発用、named volumeは本番用という気がするのでnamed volumeを使います。

docker volume create mydb-volume
docker volume ls
docker run -d -v mydb-volume:/var/lib/mysql --name mydb --env MYSQL_ROOT_PASSWORD=mysecret mysql

こうすればコンテナを削除、再作成してもデータは消えません。


終了

docker stop mydb

掃除

docker rm mydb
docker rmi mysql:latest
docker volume prune

docker volume pruneで未使用なvolumeを一括削除できます。


おまけ:Flaskから利用する

Flask_SQLAlchemy + sqlite3を使うFlaskアプリのTutorialは溢れていますがMySQLを使うFlaskアプリは少ない印象です。そこでFlask_SQLAlchemy + sqlite3構成をFlask_SQLAlchemy + MySQL構成に置き換えてみます。

Flask_SQLAlchemy + sqlite3のFlaskアプリがある前提です。

まずSQLALCHEMY_DATABASE_URIを書き換えます。

SQLALCHEMY_DATABASE_URI = 'mysql://root:mysecret@myapp-db/test'

MySQLではデータベース名に「.db」を付けません。sqlite3と違って「@myapp-db/test.db」とするとエラーになります。

これだけで済むかと思ったらもう少し手間が必要でした。

次にMySQLdbがないと怒られました。所謂「DBAPI」です。調べるとMySQLdbよりPyMySQLの方がよいそうなのでPyMySQLを入れます。

pipenv install PyMySQL

MySQL 8からデフォルトの認証方式が変更になりcryptographyがないと怒られます。入れます。

pipenv install cryptography

データベースがないと怒られます。sqlite3だとdb.create_all()で自動でデータベースが作成されますがMySQLでは予め作成しておく必要があります。

create database test;

後はいつもの初期化のおまじないです。

export FLASK_APP=myapp
flask shell
from myapp import db
db.create_all()
exit()

これでテーブルが作成されました。

ここから先はsqlite3と同じコードで動きました。

コードの変更はSQLALCHEMY_DATABASE_URIだけで済みましたがライブラリやDB側のセットアップ作業に少し追加作業が必要でした。