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側のセットアップ作業に少し追加作業が必要でした。