- 投稿日:2020-08-14T23:29:59+09:00
mariadb(mysql)起動しなくなった場合
OS: centos7
journalctl -xe 8月 14 23:09:01 cent74 mariadbd[8773]: 2020-08-14 23:09:01 0 [Note] InnoDB: Using SSE4.2 crc32 instructions 8月 14 23:09:01 cent74 mariadbd[8773]: 2020-08-14 23:09:01 0 [Note] InnoDB: Initializing buffer pool, total size = 134217728, chunk size = 134 8月 14 23:09:01 cent74 mariadbd[8773]: 2020-08-14 23:09:01 0 [Note] InnoDB: Completed initialization of buffer pool 8月 14 23:09:01 cent74 mariadbd[8773]: 2020-08-14 23:09:01 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread pr 8月 14 23:09:01 cent74 mariadbd[8773]: 2020-08-14 23:09:01 0 [ERROR] InnoDB: Upgrade after a crash is not supported. The redo log was created 8月 14 23:09:01 cent74 mariadbd[8773]: 2020-08-14 23:09:01 0 [ERROR] InnoDB: Plugin initialization aborted with error Generic error 8月 14 23:09:02 cent74 mariadbd[8773]: 2020-08-14 23:09:02 0 [Note] InnoDB: Starting shutdown... 8月 14 23:09:02 cent74 mariadbd[8773]: 2020-08-14 23:09:02 0 [ERROR] Plugin 'InnoDB' init function returned error. 8月 14 23:09:02 cent74 mariadbd[8773]: 2020-08-14 23:09:02 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed. 8月 14 23:09:02 cent74 mariadbd[8773]: 2020-08-14 23:09:02 0 [Note] Plugin 'FEEDBACK' is disabled. 8月 14 23:09:02 cent74 mariadbd[8773]: 2020-08-14 23:09:02 0 [ERROR] Unknown/unsupported storage engine: InnoDB 8月 14 23:09:02 cent74 mariadbd[8773]: 2020-08-14 23:09:02 0 [ERROR] Aborting 8月 14 23:09:02 cent74 systemd[1]: mariadb.service: main process exited, code=exited, status=1/FAILURE 8月 14 23:09:02 cent74 systemd[1]: Failed to start MariaDB 10.5.5 database server. -- Subject: Unit mariadb.service has failed -- Defined-By: systemd上記ファイルを削除
/var/lib/mysql/ib_logfile0
/var/lib/mysql/ib_logfile1
/var/lib/mysql/ib_logfile101再起動
systemctl restart mariadb
- 投稿日:2020-08-14T23:10:34+09:00
【Docker】コンテナ構築時に、MySQLデータベースが立ち上がらない
エラー内容
ERROR: for db Cannot start service db: Ports are not available: listen tcp 0.0.0.0:3306: bind: address already in useどうやら、すでにポート番号3306が使われている様子
まずは、プロセス確認
$ sudo lsof -i -P | grep "LISTEN" rapportd 315 user 4u IPv4 0xb08837e7170ea82d 0t0 TCP *:59397 (LISTEN) rapportd 315 user 5u IPv6 0xb08837e7098fcf3d 0t0 TCP *:59397 (LISTEN) com.docke 19101 user 10u IPv4 0xb08837e717a7d30d 0t0 TCP localhost:56362 (LISTEN) com.docke 19102 user 50u IPv6 0xb08837e709900c7d 0t0 TCP *:8080 (LISTEN) mysqld 20618 _mysql 21u IPv4 0xb08837e7180b7e4d 0t0 TCP localhost:3306 (LISTEN)とりま、ID指定して停止。
$ kill -9 20618 $ docker-compose up -d --build ERROR: for db Cannot start service db: Ports are not available: listen tcp 0.0.0.0:3306: bind: address already in useまだダメ、、、。
mysqldはまだ起動していた。そこで、思い出した。
他のプロジェクトで、
$ mysql.server start
していたことを。
エラー解決
mysql自体を止めましょう
$ mysql.server stop
$ docker-compose up -d --build Starting db ... done成功!
- 投稿日:2020-08-14T22:16:39+09:00
「MySQL 8.0]大量のレコードをDELETEする
[MySQL]大量のレコードをDELETEする という記事を書いたのは 2016 年のこと。使用した MySQL も 5.6.30 でした。MySQL も今では 8.0 系列が登場していますので、同じクエリを MySQL 8.0 環境で動かしてみました。
使用したのは MySQL 8.0.21 です。
root@localhost [(none)]> select version(); +-----------+ | version() | +-----------+ | 8.0.21 | +-----------+ 1 row in set (0.00 sec)開発機で試したので root ユーザになってますがご容赦を。
テスト用テーブル作成
0から9の値が均等に配置された1千万レコード。いろいろ試すためプライマリキー、インデックス、外部制約などを付けてます。以後のテストでは、毎回テーブルを DROP して作り直してます。
root@localhost [test]> CREATE TABLE seed ( -> value INTEGER UNIQUE -> ) ENGINE=InnoDB; Query OK, 0 rows affected (0.29 sec) root@localhost [test]> INSERT INTO seed (value) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9); Query OK, 10 rows affected (0.04 sec) Records: 10 Duplicates: 0 Warnings: 0 root@localhost [test]> DROP TABLE IF EXISTS huge; Query OK, 0 rows affected, 1 warning (0.01 sec) root@localhost [test]> CREATE TABLE huge ( -> id INTEGER PRIMARY KEY AUTO_INCREMENT, -> number INTEGER, -> string VARCHAR(255), -> INDEX num_idx (number), -> INDEX str_idx (string), -> CONSTRAINT num_fk FOREIGN KEY (number) REFERENCES seed(value) -> ) ENGINE=InnoDB; root@localhost [test]> INSERT INTO huge SELECT NULL, s1.value, s1.value FROM seed AS s1, seed AS s2, seed AS s3, seed AS s4, seed AS s5, seed AS s6, seed AS s7; Query OK, 10000000 rows affected (6 min 38.02 sec) Records: 10000000 Duplicates: 0 Warnings: 0 root@localhost [test]> SELECT COUNT(*) FROM huge; +----------+ | COUNT(*) | +----------+ | 10000000 | +----------+ 1 row in set (0.89 sec) root@localhost [test]> SELECT number, COUNT(*) FROM huge GROUP BY number; +--------+----------+ | number | COUNT(*) | +--------+----------+ | 0 | 1000000 | | 1 | 1000000 | | 2 | 1000000 | | 3 | 1000000 | | 4 | 1000000 | | 5 | 1000000 | | 6 | 1000000 | | 7 | 1000000 | | 8 | 1000000 | | 9 | 1000000 | +--------+----------+ 10 rows in set (4.10 sec)全DELETE
root@localhost [test]> DELETE FROM huge; Query OK, 10000000 rows affected (18 min 21.52 sec)TRUNCATE
root@localhost [test]> TRUNCATE TABLE huge; Query OK, 0 rows affected (2.27 sec)一部DELETE
root@localhost [test]> DELETE FROM huge WHERE number=0; Query OK, 1000000 rows affected (1 min 14.75 sec)一部DELETE(LIMIT指定)
root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (4.19 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (4.88 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (5.27 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (8.73 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (9.62 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (10.43 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (11.02 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (12.21 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (13.78 sec) root@localhost [test]> DELETE FROM huge WHERE number=0 LIMIT 100000; Query OK, 100000 rows affected (13.87 sec)一部DELETE(INDEX一時削除)
root@localhost [test]> ALTER TABLE huge DROP INDEX str_idx; Query OK, 0 rows affected (0.89 sec) Records: 0 Duplicates: 0 Warnings: 0 root@localhost [test]> DELETE FROM huge WHERE number=0; Query OK, 1000000 rows affected (1 min 7.10 sec) root@localhost [test]> ALTER TABLE huge ADD INDEX str_idx (string); Query OK, 0 rows affected (2 min 5.37 sec) Records: 0 Duplicates: 0 Warnings: 0一部DELETE(外部キー制約一時解除)
root@localhost [test]> ALTER TABLE huge DROP FOREIGN KEY num_fk; Query OK, 0 rows affected (0.07 sec) Records: 0 Duplicates: 0 Warnings: 0 root@localhost [test]> DELETE FROM huge WHERE number=0; Query OK, 1000000 rows affected (1 min 12.24 sec) root@localhost [test]> ALTER TABLE huge ADD CONSTRAINT num_fk FOREIGN KEY (number) REFERENCES seed(value); Query OK, 9000000 rows affected (4 min 15.43 sec) Records: 9000000 Duplicates: 0 Warnings: 0別テーブルの作成
root@localhost [test]> CREATE TABLE huge_copy LIKE huge; Query OK, 0 rows affected (0.06 sec) root@localhost [test]> ALTER TABLE huge_copy ADD CONSTRAINT num_fk_copy FOREIGN KEY (number) REFERENCES seed(value); Query OK, 0 rows affected (0.26 sec) Records: 0 Duplicates: 0 Warnings: 0 root@localhost [test]> INSERT INTO huge_copy SELECT * FROM huge WHERE number<>0; Query OK, 9000000 rows affected (5 min 55.15 sec) Records: 9000000 Duplicates: 0 Warnings: 0 root@localhost [test]> RENAME TABLE huge TO huge_old, huge_copy TO huge; Query OK, 0 rows affected (0.71 sec) root@localhost [test]> DROP TABLE huge_old; Query OK, 0 rows affected (0.67 sec)別テーブルの作成(INDEX一時削除)
root@localhost [test]> CREATE TABLE huge_copy LIKE huge; Query OK, 0 rows affected (0.08 sec) root@localhost [test]> ALTER TABLE huge_copy ADD CONSTRAINT num_fk_copy FOREIGN KEY (number) REFERENCES seed(value); Query OK, 0 rows affected (0.19 sec) Records: 0 Duplicates: 0 Warnings: 0 root@localhost [test]> ALTER TABLE huge_copy DROP INDEX str_idx; Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0 root@localhost [test]> INSERT INTO huge_copy SELECT * FROM huge WHERE number<>0; Query OK, 9000000 rows affected (4 min 47.31 sec) Records: 9000000 Duplicates: 0 Warnings: 0 root@localhost [test]> ALTER TABLE huge_copy ADD INDEX str_idx (string); Query OK, 0 rows affected (1 min 8.52 sec) Records: 0 Duplicates: 0 Warnings: 0 root@localhost [test]> RENAME TABLE huge TO huge_old, huge_copy TO huge; Query OK, 0 rows affected (0.10 sec) root@localhost [test]> DROP TABLE huge_old; Query OK, 0 rows affected (0.74 sec)パーティショニングDROP
root@localhost [test]> DROP TABLE IF EXISTS p_huge; Query OK, 0 rows affected, 1 warning (0.02 sec) root@localhost [test]> CREATE TABLE p_huge ( -> number INTEGER, -> string VARCHAR(255), -> INDEX num_idx (number), -> INDEX str_idx (string) -> ) ENGINE=InnoDB; Query OK, 0 rows affected (0.08 sec) root@localhost [test]> INSERT INTO p_huge SELECT s1.value, s1.value FROM seed AS s1, seed AS s2, seed AS s3, seed AS s4, seed AS s5, seed AS s6, seed AS s7; Query OK, 10000000 rows affected (5 min 8.32 sec) Records: 10000000 Duplicates: 0 Warnings: 0 root@localhost [test]> ALTER TABLE p_huge PARTITION BY LIST(number) ( -> PARTITION num_0 VALUES IN (0), -> PARTITION num_1 VALUES IN (1), -> PARTITION num_2 VALUES IN (2), -> PARTITION num_3 VALUES IN (3), -> PARTITION num_4 VALUES IN (4), -> PARTITION num_5 VALUES IN (5), -> PARTITION num_6 VALUES IN (6), -> PARTITION num_7 VALUES IN (7), -> PARTITION num_8 VALUES IN (8), -> PARTITION num_9 VALUES IN (9) -> ); Query OK, 10000000 rows affected (3 min 47.23 sec) Records: 10000000 Duplicates: 0 Warnings: 0 root@localhost [test]> ALTER TABLE p_huge DROP PARTITION num_0; Query OK, 0 rows affected (2.18 sec) Records: 0 Duplicates: 0 Warnings: 0 root@localhost [test]> ALTER TABLE p_huge ADD PARTITION ( -> PARTITION num_0 VALUES IN ( 0 ) -> ); Query OK, 0 rows affected (0.09 sec) Records: 0 Duplicates: 0 Warnings: 0総評
MySQL 5.6.30 と比較してみました。ちなみに前回と今回で使用したハードウェアは同じです。
テスト項目 MySQL 5.6.30 MySQL 8.0.21 全DELETE 28分57.90秒 18分21.52秒 TRUNCATE 0.41秒 2.27秒 一部DELETE 3分15.38秒 1分14.75秒 一部DELETE(LIMIT指定) 2分47.27秒 1分34秒 一部DELETE(INDEX一時削除) 2分32.75秒 3分13.36秒 一部DELETE(外部キー制約一時解除) 3分16.11秒 5分27.74秒 別テーブルの作成 2分12.60秒※ 5分56.87秒 別テーブルの作成(INDEX一時削除) 2分40.57秒 5分57秒 パーティショニングDROP 0.08秒 2.27秒 ※ MySQL 5.6 では外部キー制約のコピーが漏れていたので直接比較はできない。
こうしてみると 8.0 系になって大量 DELETE はかなり速くなってますね。そして、下手に小細工を弄するよりも素直な手順でやった方がよさそうですね。
- 投稿日:2020-08-14T19:33:14+09:00
[SQL]DELETE文でデータを削除
DELETE文でデータを削除
テーブルのデータを削除するときはDELETE文を使います。
DELETE FROM テーブル名 WHERE 条件文;SELECT文でuserテーブルのデータを確認。
mysql> select * from user; +------+---------------+----------------------------------------------------+ | id | name | prefecture | address | +------+---------------+----------------------------------------------------+ | 1 | テスト | 東京都 | 東京都千代田区丸の内1丁目 | | 2 | テスト1 | 滋賀県 | 滋賀県彦根市金剛寺町2-16ザ金剛寺町313 | | 3 | テスト2 | 大阪府 | 東京都練馬区豊玉南4-11 | | 4 | テスト3 | 北海道 | 北海道千歳市千代田町2-3千代田町シティ102 | | 5 | テスト4 | 東京都 | 東京都小平市回田町2-12-17フォレスト回田町202 | +------+---------------+---------------------------+------------------------+データを削除していきます。
「id > 3」とすると、idが3より大きいデータが対象になります。mysql> DELETE FROM meibo WHERE id > 3; Query OK, 2 rows affected (0.19 sec)データが削除されているか確認します。
mysql> select * from user; +------+---------------+----------------------------------------------------+ | id | name | prefecture | address | +------+---------------+----------------------------------------------------+ | 1 | テスト | 東京都 | 東京都千代田区丸の内1丁目 | | 2 | テスト1 | 滋賀県 | 滋賀県彦根市金剛寺町2-16ザ金剛寺町313 | | 3 | テスト2 | 大阪府 | 東京都練馬区豊玉南4-11 | +------+---------------+---------------------------+------------------------+
- 投稿日:2020-08-14T19:09:58+09:00
[SQL]UPDATE文でデータを更新
UPDATE文でデータを更新
すでに挿入済みのデータを更新するときは、UPDATE文を使います。
UPDATE テーブル名 SET カラム名1 = 値1, カラム名2 = 値2 WHERE 条件文;現在のテーブルデータは以下です。
mysql> select * from user; +------+---------------+----------------------------------------------------+ | id | name | prefecture | address | +------+---------------+----------------------------------------------------+ | 1 | テスト | 東京都 | 東京都千代田区丸の内1丁目 | | 2 | テスト1 | 滋賀県 | 滋賀県彦根市金剛寺町2-16ザ金剛寺町313 | | 3 | テスト2 | 東京都 | 東京都練馬区豊玉南4-11 | | 4 | テスト3 | 北海道 | 北海道千歳市千代田町2-3千代田町シティ102 | | 5 | テスト4 | 東京都 | 東京都小平市回田町2-12-17フォレスト回田町202 | +------+---------------+---------------------------+------------------------+上記テーブルの「id=2」の「prefecture」を変更してみます。
mysql> UPDATE user SET prefecture = 大阪府 WHERE id = 2; Query OK, 1 row affected (0.17 sec) Rows matched: 1 Changed: 1 Warnings: 0更新できているか確認してみます。
mysql> select * from user; +------+---------------+----------------------------------------------------+ | id | name | prefecture | address | +------+---------------+----------------------------------------------------+ | 1 | テスト | 東京都 | 東京都千代田区丸の内1丁目 | | 2 | テスト1 | 滋賀県 | 滋賀県彦根市金剛寺町2-16ザ金剛寺町313 | | 3 | テスト2 | 大阪府 | 東京都練馬区豊玉南4-11 | | 4 | テスト3 | 北海道 | 北海道千歳市千代田町2-3千代田町シティ102 | | 5 | テスト4 | 東京都 | 東京都小平市回田町2-12-17フォレスト回田町202 | +------+---------------+---------------------------+------------------------+
- 投稿日:2020-08-14T18:26:55+09:00
MySQLで複数のDBをまたいで使用する
概要
サービスが大きくなったりしてDBが増えたときに、複数のDBをまたいで使用する場合の書き方です。
環境
PHP 5.3.29
FuelPHP 1.7.3
MySQL 5.5.61本題
方法1
まず、FuelPHPの
fuel/app/config
以下にあるdb.php
に設定を書きます。書くファイルはそれぞれの環境に応じたものにします。(開発環境であればdevelopment/db.php
)
ここに複数の設定を書けばクエリを発行する際に各DBを指定して使用できます。db.php<?php return array{ 'db01' => array( 'type' => 'pdo', 'connection' => array( 'dsn' => 'mysql:host=localhost;dbname=db01', 'username' => '', 'password' => '', ), ), 'db02' => array( 'type' => 'pdo', 'connection' => array( 'dsn' => 'mysql:host=localhost;dbname=db02', 'username' => '', 'password' => '', ), ), 'db03' => array( 'type' => 'pdo', 'connection' => array( 'dsn' => 'mysql:host=localhost;dbname=db03', 'username' => '', 'password' => '', ), ), ); ?>各パラメータは各々の環境に合わせます。
次に、モデルにクエリを発行する文を書きます。
examplemodel.php<?php namespace Example; class Model_Examplemodel extends \Model { public static function get_example() { $get = \DB::select() ->from('tablename') ->execute('db01') return $get; } } ?>このように
execute()
の引数にdb.phpで定義した文字を入れればそのDBを参照してくれます。方法2
セレクトするテーブルの情報にDB名を加える形でも可能です。
examplemodel.php<?php namespace Example; class Model_Examplemodel extends \Model { public static function get_example() { $get = \DB::select() ->from('db01.tablename') ->execute() return $get; } } ?>joinする場合
joinする場合は、方法1をとるとすべてそのDBにあるテーブルが参照されます。
ですので、db01・db02それぞれからテーブルを参照する必要がある場合は方法2、もしくは両方を合わせて使う必要があります。examplemodel.php<?php namespace Example; class Model_Examplemodel extends \Model { public static function get_example() { $get = \DB::select() ->from('db01.table01') ->join('db02.table02') ->on('table01.column01', '=', 'table02.column01') ->execute() return $get; } } ?>カラム名が被っている場合はその点にも注意します。
終わりに
FuelPHPを書いていて、発行されたクエリが簡単にわかる方法はないかなーと思って探しています。知っている方いましたらコメントいただけるとすごく助かります。
- 投稿日:2020-08-14T14:57:18+09:00
MySQLdumpでバックアップ【warning】using a password on the command line interface can be insecure
MySQLdumpでバックアップ【warning】using a password on the command line interface can be insecure
MySQLdumpでバックアップする基本構文でパスワードが直書きされているとのエラーが。
どうやらSQLコマンドにパスワードを直書きすると注意されるらしい。mysqldumpの基本構文は以下。
mysqldumdp -u[ユーザー名] -p[パスワード] -h[ホスト名] [データベース名] [テーブル名1], [テーブル名2],...[オプション] > [保存先ファイル名]
調べたところ、パスワードを外部ファイルに保存するなどの方法もありましたが、次の方法でOK
mysqldump -u[ユーザー名] -p -h[ホスト名] [データベース名] [テーブル名1], [テーブル名2],...[オプション] > [保存先ファイル名]
パスワード欄は空欄にして打ち込みENTERを押すとENTER passwordという表記になるのでそこでパスワード入力。
参考
https://proengineer.internous.co.jp/content/columnfeature/6793#section100
- 投稿日:2020-08-14T14:50:57+09:00
DockerのMySQLへのinsertでError Code: 1366. Incorrect string value: 'xx' for column 'name' at row 1
事象
日本語を含むinsert分で上記エラーが発生。
対応
以下を確認すると文字コードが
latin1
になっているのが原因。mysql> status; -------------- mysql Ver 14.14 Distrib 5.7.31, for osx10.15 (x86_64) using EditLine wrapper Connection id: 174 Current database: xxx Current user: root@xxx SSL: Cipher in use is DHE-RSA-AES256-SHA Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.7.26 MySQL Community Server (GPL) Protocol version: 10 Connection: 127.0.0.1 via TCP/IP Server characterset: latin1 Db characterset: latin1 Client characterset: utf8 Conn. characterset: utf8 TCP port: 13307 Uptime: 2 days 3 hours 37 min 13 sec Threads: 3 Questions: 2106 Slow queries: 0 Opens: 219 Flush tables: 1 Open tables: 212 Queries per second avg: 0.011 --------------以下で確認したところmy.cnfがない。
docker container exec -it xxx bash cat /etc/mysql/conf.d/my.cnfDockerfileが間違っていた。(mysqlではなくmusql)
ADD ./Docker/mysql/conf.d/my.cnf /etc/musql/conf.d/my.cnf上記修正をした上で、以下でコンテナを再作成。
(再起動でも良いのだけど、もう一度マイグレーションをロールバックして、再実行するのが手間だと感じたので)docker-compose down --rmi all --volumes docker-compose up -d参考
- 投稿日:2020-08-14T05:41:38+09:00
docker-compose を用いて Apache・PHP・MySQL の開発環境を構築してみた
はじめに
docker-compose を用いて Apache・PHP・MySQL の開発環境を構築してみた備忘録になります。
バージョン情報
docker-compose はインストールされていることが前提になります。
今回は以下のバージョンでの動きになります。$ docker-compose -v docker-compose version 1.26.2, build eefe0d31PHP のバージョンは 5.4、MySQL のバージョンは 5.5 の環境を構築します。
Apache のバージョンは特に気にしていません。ディレクトリ構造
ディレクトリ構造は以下のようになります。
. ├── config │ ├── mysql │ │ ├── Dockerfile │ │ ├── initdb.d │ │ │ └── init.sql │ │ └── my.cnf │ └── php │ ├── Dockerfile │ ├── apache2.conf │ ├── php.ini │ └── sites │ ├── 000-default.conf │ └── default-ssl.conf ├── data ├── docker-compose.yml └── html └── test ├── connect.php └── index.phpGitHub にもあげました。ご参考まで。
設定
各サービスに以下のような設定ファイルがそれぞれあると思いますが、それらを変更したものを動かしたいと思います。
Apache の設定
今回は DocumentRoot を変更してみます。
公式ドキュメント をみると以下のように Dockerfile を記述することで DocumentRoot を変更できるようです。
いろいろな記事をみるとコンテナから 000-default.conf などの設定ファイルをホスト側にもってきてそれを修正した後、Dockerfile のCOPY
でコンテナ側にコピーするようでした。
やはり公式ドキュメントをみるのが一番ですね。公式ドキュメントのように行ったらコンテナが再起動ループに陥ってしまいました。
※ 理由をよく調べたら php:5.5-apache 以降であればそれでよかったらしいです。
なので、php:5.4-apache のイメージからコンテナを立ち上げて、元ファイルをホスト側にコピーして、それを編集することにしました。
# とりあえず php:5.4-apache のコンテナを動かしてログインする $ docker image pull php:5.4-apache $ docker container run --name php54apache -d php:5.4-apache $ docker exec -it php54apache /bin/bash # 設定ファイルを確認 ( php:5.4-apache 以前は apache2.conf の修正も必要) $ ls /etc/apache2/apache2.conf httpd.conf $ ls /etc/apache2/sites-available 000-default.conf default-ssl.conf # コンテナを抜ける $ exit # ホスト側にコピー $ docker container cp php54apache:/etc/apache2/apache2.conf ./config/php $ docker container cp php54apache:/etc/apache2/sites-available/000-default.conf ./config/php/sites $ docker container cp php54apache:/etc/apache2/sites-available/default-ssl.conf ./config/php/sitesこれらの
apache2.conf
、000-default.conf
、default-ssl.conf
に記述してある DocumentRoot を変更します。今回は以下のように変更しました。
# DocumentRoot /var/www/html DocumentRoot /var/www/html/test
これで DocumentRoot の変更の準備は完了です。
PHP の設定
PHP は
php.ini
によって設定を行います。公式ドキュメント をみると以下のように記述することで php.ini を指定するらしいです。
しかし、コンテナを立ち上げてログインしてみても、
php.ini-development
やphp.ini-produciton
のようなファイルは存在しませんでした。おそらく Apache の設定でもそうであったように公式のドキュメントは過去のバージョンまで挙動は保証していないようです。
サンプルにあるような
php:7.4-fpm-alpine
ならそれで良さそうですね。今回は
php.ini-development
やphp.ini-produciton
については GitHub で公開してあったのでそちらの php.ini-development を元に php.ini を作成することにしました。php.ini の修正についてはこちらを参照して、ロケーションや言語の設定を修正しました。
MySQL の設定ファイルの変更
MySQL の設定ファイルは
my.cnf
によって行います。MySQL の設定ファイルの my.cnf は 公式ドキュメント によると
/etc/mysql/my.cnf
に配置してあるとのことでした。なのでそちらをローカルホストに持ってきて、適宜修正していきたいと思います。
# とりあえず mysql:5.5 のコンテナを動かしてログインする $ docker image pull mysql:5.5 $ docker container run -e MYSQL_ROOT_PASSWORD=sample_pw --name mysql55 -d mysql:5.5 $ docker exec -it mysql55 /bin/bash # /etc/mysql/my.cnf を確認 $ ls /etc/mysql/my.cnf /etc/mysql/my.cnf # コンテナを抜ける $ exit # my.cnf をホスト側にコピー $ docker container cp mysql55:/etc/mysql/my.cnf ./config/mysql/あとは環境に合わせて修正して、
my.cnf
を作成してください。※ ちなみに今回は
my.cnf
の修正は行っていません。Dockerfile の作成
Dockerfile は
php:5.4-apache
とmysql:5.5
のイメージについて作成しました。php:5.4-apache
config/php/Dockerfile# image FROM php:5.4-apache # Set php.ini COPY ./php.ini /usr/local/etc/php/ # Set apache conf (Before tag:5.4-apache) COPY ./apache2.conf /etc/apache2/ COPY ./sites/*.conf /etc/apache2/sites-available/ # Set apache conf (After tag:5.5-apache) # ENV APACHE_DOCUMENT_ROOT /var/www/html/test # RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf # RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf # Install MySQL connection module RUN apt-get update \ && apt-get install -y libpq-dev \ && docker-php-ext-install pdo_mysql pdo_pgsql mysqli mbstringここでは「DocumentRoot の変更」、「php.ini の配置」、「MySQL と疎通するためのモジュールを追加」しています。
mysql:5.5
config/mysql/Dockerfile# image FROM mysql:5.5 # Set my.cnf COPY ./my.cnf /etc/mysql/conf.d/ # Set Japanese RUN apt-get update && apt-get install -y \ locales \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* RUN sed -i -E 's/# (ja_JP.UTF-8)/\1/' /etc/locale.gen \ && locale-gen ENV LANG ja_JP.UTF-8 CMD ["mysqld", "--character-set-server=utf8", "--collation-server=utf8_unicode_ci"]デフォルトのままであると MySQL にログインした後に日本語の入力ができなかったため、ここでは日本語を入力可能にするような設定をおこなています。
MySQL の日本語の設定は こちら を参照しました。
MySQL の初期データの投入
docker-compose 起動時に MySQL に初期データを投入してみたく、以下のような SQL を用意しました。
init.sqlDROP TABLE IF EXISTS sample_table; CREATE TABLE sample_table ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name TEXT NOT NULL ) charset=utf8; INSERT INTO sample_table (name) VALUES ("太郎"),("花子"),("令和");コンテナ起動後にここで記述した SQL が実行されていることを確認します。
docker-compose.yml の作成
以下のように docker-compose.yml を作成しました。
docker-compose.ymlversion: '3.8' services: # PHP Apache php-apache: build: ./config/php ports: - "8080:80" volumes: - ./html:/var/www/html restart: always depends_on: - mysql # MySQL mysql: build: ./config/mysql ports: - 3306:3306 volumes: - ./config/mysql/initdb.d:/docker-entrypoint-initdb.d - ./data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: sample_root_passward MYSQL_DATABASE: sample_db MYSQL_USER: sample_user MYSQL_PASSWORD: sample_passMySQL のデータの永続化について
MySQL のデータディレクトリは /var/lib/mysql であり、
- ./data:/var/lib/mysql
とあるようにホスト側の./data
ディレクトリにマウントすることによってデータを永続化しております。試してみたところ
docker-compose stop
やdocker-compose down
してもデータが永続化されていることが確認できました。docker-compose 使い方
いよいよ docker-compose を動かします。
docker-compose 起動
まずはなにも起動されていないことを確認します。
$ docker-compose ps Name Command State Ports ------------------------------ $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES今回はわかりやすいようにコンテナも空の状態にしておきます。
docker-compose.yml が存在する階層で
docker-compose up -d
コマンドを実行することで、docker-compose.yml の記述をもとにコンテナが作成されます。※ docker-compose のコマンドの
build
とup
の違いやオプションについてはこちらがわかりやすかったです。# image の作成 $ docker-compose build --no-cache Successfully tagged docker-compose-sample_php-apache:latest # コンテナの構築・起動 $ docker-compose up -d Creating network "docker-compose-sample_default" with the default driver Creating docker-compose-sample_mysql_1 ... done Creating docker-compose-sample_php-apache_1 ... done # docker-compose の確認 $ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------- docker-compose-sample_mysql_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp docker-compose-sample_php-apache_1 apache2-foreground Up 0.0.0.0:8080->80/tcp # コンテナの確認 $ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 26b0cec2daad docker-compose-sample_php-apache "apache2-foreground" 3 minutes ago Up 3 minutes 0.0.0.0:8080->80/tcp docker-compose-sample_php-apache_1 eaae044f4bba mysql:5.5 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:3306->3306/tcp docker-compose-sample_mysql_1コンテナが動いていることが確認できました。
PHP-Apache コンテナの確認
DocumentRoot の直下に配置する、php:5.4-apache コンテナの疎通確認用のページとして以下のようなファイルを用意しました。
html/test/index.php<?php echo __DIR__; phpinfo();
http://localhost:8080
にアクセスすると以下のように表示されるはずです。
echo __DIR__;
はその PHP ファイルが置かれている絶対パスを出力するので DocumentRoot の変更が行われていることが確認できます。また、
php.ini
についてオリジナルものから修正を加えていれば、phpinfo();
の出力でそちらも反映されていることも確認できるかと思います。MySQL コンテナの確認
mysql:5.5
のイメージで作成されたコンテナにログインして、初期データが投入されていることを確認します。shell# コンテナにログイン $ docker exec -it eaae044f4bba /bin/bash # MySQL にログイン $ mysql -p Enter password:パスワードを求められるので docker-compose.yml で
MYSQL_ROOT_PASSWORD
の環境変数に登録したsample_root_passward
と入力するとログインできます。docker-compose.yml に登録した
MYSQL_DATABASE
、MYSQL_USER
が登録されていることを確認します。mysql> select user, host from mysql.user; +-------------+-----------+ | user | host | +-------------+-----------+ | root | % | | sample_user | % | | root | localhost | +-------------+-----------+ 3 rows in set (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sample_db | +--------------------+ 4 rows in set (0.00 sec)
sample_user
とsample_db
があることが確認できました。続いて
init.sql
で作成したテーブルとカラムについても確認してみます。mysql> use sample_db; Database changed mysql> show tables; +---------------------+ | Tables_in_sample_db | +---------------------+ | sample_table | +---------------------+ 1 row in set (0.00 sec) mysql> select * from sample_table; +----+--------+ | id | name | +----+--------+ | 1 | 太郎 | | 2 | 花子 | | 3 | 令和 | +----+--------+ 3 rows in set (0.00 sec)テーブルとカラムについても問題なく確認できました。
PHP-Apache から MySQL コンテナへの疎通確認
PHP-Apache から MySQL コンテナへの疎通確認用のページとして以下のようなファイルを用意しました。
html/test/connect.php<?php try { // host=XXXの部分のXXXにはmysqlのサービス名を指定します $dsn = 'mysql:host=mysql;dbname=sample_db;'; $db = new PDO($dsn, 'sample_user', 'sample_pass'); $sql = 'SELECT * FROM sample_table;'; $stmt = $db->prepare($sql); $stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); var_dump($result); } catch (PDOException $e) { echo $e->getMessage(); exit; }※ 注意点として、ホスト名は
localhost
や127.0.0.1
ではなく、docker-compose.yml でサービス名として指定してたmysql
を使用します。
http://localhost:8080/connect.php
にアクセスすると以下のように表示されればが PHP-Apache から MySQL コンテナへの疎通がうまく行っています。docker-compose 停止・削除
以下のコマンドで 停止・削除 を行います。
# コンテナを停止 $ docker-compose stop # コンテナを停止し、そのコンテナとネットワークの削除 $ docker-compose down # コンテナを停止し、そのコンテナとネットワークを削除、さらにイメージも削除 $ docker-compose down --rmi all --volumes
./config/mysql/initdb.d/init.sql
の初期データ投入からやり直したい時などはdocker-compose down --rmi all --volumes
してから./data
ディレクトリの中身も削除してdocker-compose up -d
でコンテナの構築・起動からやり直してください。まとめ
以下を自動化する docker-compose の開発環境構築を行いました。
- DocumentRoot の変更
- php.ini の変更
- my.cnf の変更
- MySQL への初期データの投入
- MySQL のデータの永続化
- PHP-Apache コンテナから MySQL コンテナへの疎通
つまり、これらの環境がワンライナーで構築できるようになりました。
学んだこと
今回初めて docker-compose で開発環境を構築してみて学んだことを羅列します。
- 公式ドキュメント(DockerHub)は読んだ方がいい
- Qiita よりも DockerHub を先に見た方がよさそうです。
- docker-compose.yml と Dockerfile はかき分ける
- 一度変更すればコンテナ起動後に変更のない設定ファイルなどは Dockerfile で
COPY
でコンテナ側にファイルを配置して、コンテナ起動後に変更のあるものは docker-compose.yml でマウントさせるという書き分けがよさそうです。- Dockerfile をいきなり書くのは難しい
- 以下の手順で Dockerfile を書くと良いです。
- ベースイメージを決める
- ベースイメージのコンテナ内で作業しつつ、うまくいった処理をメモ
- 全て成功したらDockerfileを作成
以上になります。
- 投稿日:2020-08-14T00:18:07+09:00
MySQLのトリガーってなんなん?
沈黙?それが正しい答えなんか?
ぼく「つまり、トリガーっていうのがストアドプロシージャーってことなんですか?」
先輩「・・・・・・。」
ぼく「(・・・沈黙?それが正しい答えなんか。)」
ぼく「(いや、流石にそれが答えじゃないことぐらいは分かるで・・・。)」
ぼく「(多分、エンジニアに必要なのは洞察力やということを暗に教えてくれてるんやろうな・・・。)」
ぼく「(ほんまにええ先輩やで!)」
ぼく「わかりました!とりあえずやってみます!」先輩「はい。」
とにかく調べてみる。
ぼく「ほーん・・・。」
ぼく「トリガーいうんはDBのテーブルにあるデータが更新されたときに走るプロシージャのことなんか」
ぼく「データの更新ってINSERT,UPDATE,DELETEが対象になるんやな。」
ぼく「プロシージャってそもそもなんやねん。」
ぼく「戻り値のない関数のことか、草属性のポケモンと名前似てるやん。」
ぼく「てことは、対象のテーブルのデータが更新されたタイミングにトリガーを設定すれば自分の更新したいテーブルに何かできるってことなんか。」
ぼく「で、ストアドプロシージャーはなんや・・・。」
ぼく「複数のSQLを一つにまとめてRDBMSに、この場合はMySQLやな?そこに保存して実行できるもの。」
ぼく「めっちゃ便利やん。」タイミングとかある。
ぼく「データ更新のタイミングいうけど、更新する前と後があるやん・・・。それも指定できんのかな?」
ぼく「ふんふん。BEFOREとAFTERでトリガーの起動タイミングを指定するねんな。」
ぼく「それで?データ更新は起動タイミングを記載した後にINSERT,UPDATE,DELETEのどれかを指定すると・・・。」
ぼく「対象となるテーブルはどこで設定すればええんや?」
ぼく「データの更新を記載した後にON 対象となるテーブル名みたいな感じで書くねんな。」
ぼく「で、使ってるのはMySQLやからFOR EACH ROWとその後に書くと・・・。」
ぼく「なるほどね。とりあえず作ってみるか。」DELIMITER // CREATE TRIGGER test1 BEFORE UPDATE ON items FOR EACH ROW BEGIN CALL 呼びたいストアドプロシージャー(引数); END // DELIMITER ;ぼく「これでitemsテーブルを更新するとストアドプロシージャーが自動で実行されんのか・・・。」
トリガーの実行
ぼく「トリガーを実行するためには、自分で設定したテーブルの更新をしたらええねんな。」
UPDATE items SET value=100 WHERE Items.id = 1;ぼく「おお、ほんまにトリガーが起動して、自分が呼び出したいストアドプロシージャーが動いてるで!」
トリガーの削除
ぼく「削除したいときは、DROP TRIGGERに自分が作成したトリガーを指定するねんな。」
DROP TRIGGER test1;ぼく「トリガーと結びつけたitemsテーブルが削除されたときもトリガーは、一緒に削除されんのか。」
ストアドプロシージャーとトリガーの違い
ぼく「トリガーで設定したタイミングにストアドプロシージャーを動かせるようになったで!」
ぼく「トリガーもプロシージャーやし、ストアドプロシージャーもそうやん・・・。」
ぼく「データベースで更新タイミングがあったときに実行されるストアドプロシージャーのことを・・・。」
ぼく「トリガーと呼ぶ。」
ぼく「先輩の沈黙もあながち答えとして間違ってないやん」終わり