そろそろ AlmaLinux 辺りに手を付けないと、とは思いつつ今までの積み重ねを生かすためにひとまず Docker で LAMP環境 を作るのは最後までやってみました。
経緯
ベースは以下の記事の Apache + PHP 環境です。
ここに至るまでも
- CentOS で リポジトリの enable/disabled を切り替える方法 – Ewig Leere(Lab2)
- Docker で手動で手順を確認しつつ Apache にアクセスできるようになるまで (Failed to get D-Bus connection: Operation not permitted 対処含む) – Ewig Leere(Lab2)
のような積み重ねを行ってきましたが、さらに MySQL や phpMyAdmin も加えます。
- Docker で MySQL に入ろうとしたら「Can’t connect to local MySQL server through socket …」で怒られたので起動する – Ewig Leere(Lab2)
- MySQL8.0 起動時に「Can’t find error-message file …」エラーで怒られた – Ewig Leere(Lab2)
成果物
構成
ディレクトリ構造
PROJECT_ROOT/
├ apache/
│ // 略
│
├ cert/
│
├ mysql/
│ ├ cnfd/ // /etc/my.cnf.d にマウント
│ ├ data/ // /var/lib/mysql/data にマウント
│ ├ docker/
│ │ └ Dockerfile // Apache 用 Dockerfile
│ │
│ ├ log/ // /var/log/mysql にマウント
│ └ my.cnf // /etc/my.cnf として使用
│
├ php/
│ // 略
│
├ phpmyadmin/sessions // /sessions にマウント。 phpMyAdmin のセッション格納用
│
├ template/
│ ├ apache/
│ │ ├ apache_vh.conf // 仮想サイトのディレクティブ設定を記述した conf ファイル
│ │ ├ apache_vh_ssl.conf // 上同。SSL版
│ │ ├ php.conf // /etc/httpd/conf.d/php.conf を上書きするためのテンプレート
│ │ └ ssl.conf // /etc/httpd/conf.d/ssl.conf を上書きするためのテンプレート
│ │
│ └ mysql/
│ ├ 20-default-authentication-plugin.cnf
│ ├ 40-pass.cnf
│ ├ 50-my-tuning.cnf
│ └ base.cnf
│
├ workspace/
│ ├ entrypoint_db.sh // MySQL イメージのエントリポイント
│ └ entrypoint_web.sh // Apache イメージのエントリポイント
│
├ .env // docker-compose.yml 用の環境変数
└ docker-compose.yml
docker-compose.yml
version: '3.8'
services:
web:
# 略
db:
build:
context: ./mysql/docker
dockerfile: Dockerfile
args:
DB_ROOT_PASSWORD: $DB_ROOT_PASSWORD
DB_HOST_PORTNUM: $DB_HOST_PORTNUM
DB_CONTAINER_PORTNUM: $DB_CONTAINER_PORTNUM
labels:
lamp.ambergrease.dolphin: "Ambergrease MySQL"
volumes:
# workspace
- ./workspace:/workspace
# docker settings template
- ./template:/template
# mysql cnf.d
- ./mysql/cnfd:/etc/my.cnf.d
# mysql cnf
- ./mysql/my.cnf:/etc/my.cnf
# mysql data
- ./mysql/data:/var/lib/mysql/data
# error log
- ./mysql/log:/var/log/mysql
tty: true
ports:
- "$DB_HOST_PORTNUM:$DB_CONTAINER_PORTNUM"
entrypoint: bash -c "bash /workspace/entrypoint_db.sh $DB_CONTAINER_PORTNUM $DB_ROOT_PASSWORD $PHPMYADMIN_USER_NAME $PHPMYADMIN_USER_PASSWORD && /bin/bash"
phpmyadmin:
image: phpmyadmin/phpmyadmin
labels:
lamp.ambergrease.yacht: "Ambergrease phpMyAdmin"
volumes:
# sessions
- ./phpmyadmin/sessions:/sessions
environment:
- PMA_ARBITRARY=1
- PMA_HOST=db
- PMA_USER=$PHPMYADMIN_USER_NAME
- PMA_PASSWORD=$PHPMYADMIN_USER_PASSWORD
ports:
- "$PHPMYADMIN_HOST_PORTNUM:$PHPMYADMIN_CONTAINER_PORTNUM"
上述の通りベースは CentOS7 + Apache + PHP (Xdebug, composer) の環境で、そこに MySQL と phpMyAdmin を足した形になります。最初は公式の MySQL8 のイメージを使用しようかと思いましたが上手くいかなかったので結局 プレーンな CentOS7 に MySQL を足す形にしました。
一方、 phpMyAdmin は最後にちょい足しで済んだので公式イメージをそのまま利用しています。
.env
# Web系 略
DB_ROOT_PASSWORD=Password-1234
DB_HOST_PORTNUM=13306
DB_CONTAINER_PORTNUM=3306
PHPMYADMIN_USER_NAME=admin
PHPMYADMIN_USER_PASSWORD=Password-1234
PHPMYADMIN_HOST_PORTNUM=8081
PHPMYADMIN_CONTAINER_PORTNUM=80
MySQL の設定と phpMyAdmin の設定が増えました。項目は分かりやすいと思います。
mysql/docker/Dockerfile
FROM centos:centos7
# args
ARG DB_ROOT_PASSWORD
ARG DB_HOST_PORTNUM
ARG DB_CONTAINER_PORTNUM
# timezone
RUN cp -p -f /usr/share/zoneinfo/Japan /etc/localtime
# yum install
RUN yum -y update && yum -y install \
epel-release \
sudo \
less \
# network ss (instaed of netstat)
iproute
# rpm
RUN rpm -ivh https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
# mysql
RUN yum -y install mysql-community-devel mysql-community-server
# mysql log
RUN mkdir /var/log/mysql
# mkdir and owner and so on
RUN chown -R mysql:mysql /var/log/mysql
RUN chown -R mysql /var/lib/mysql/
RUN chgrp -R mysql /var/lib/mysql/
RUN mkdir /template
RUN mkdir /workspace
上述の通り、 CentOS7 に MySQL を足す形で構築。
20-default-authentication-plugin.cnf
[mysqld]
# default_authentication_plugin=caching_sha2_password
default-authentication-plugin = mysql_native_password
パスワード保存形式を mysql_native_password
に変更。
base.cnf
[mysqld]
basedir = /var/lib/mysql
datadir = /var/lib/mysql/data
plugin_dir = /usr/lib64/mysql/plugin
# socket
socket = /var/lib/mysql/mysql.sock
# language
lc-messages-dir = /usr/share/mysql-8.0/japanese
# error messages
lc_messages_dir = /usr/share/mysql-8.0
# not only lowercase characters in tablename
lower_case_table_names = 0
# character set
character_set_server = utf8mb4
collation_server = utf8mb4_ja_0900_as_cs_ks
# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM
# port
port = 3306
# Error Log
log-error = /var/log/mysql/mysql-error.log
# Slow Query Log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow_query.log
long_query_time = 5.0
# General Log
general_log = 1
general_log_file = /var/log/mysql/mysql-query.log
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
basedir
, datadir
, plugin_dir
の指定や socket
ファイルの位置、 lc-messages-dir
の言語ファイルの場所、 character_set_server
, collation_server
の文字コードや照合順序のデフォルト値等々、必要な項目を足しておきます。
workspace/entrypoint_db.sh
#!/bin/bash
SYSDBPATH="/var/lib/mysql/data/sys/"
DBINDFILE="sys_config.ibd"
SOCKFILE="/var/lib/mysql/mysql.sock"
# setting file replace and copy
sed -e "s/DB_CONTAINER_PORTNUM/${1}/gi" /template/mysql/base.cnf > /etc/my.cnf.d/base.cnf
cp /template/mysql/20-default-authentication-plugin.cnf /etc/my.cnf.d/20-default-authentication-plugin.cnf
cp /template/mysql/40-paas.cnf /etc/my.cnf.d/40-paas.cnf
cp /template/mysql/50-my-tuning.cnf /etc/my.cnf.d/50-my-tuning.cnf
# mysql initialize
if [ ! -e $SYSDBPATH$DBINDFILE ]; then
/usr/sbin/mysqld --user=mysql --initialize &
# wait for initialize process
wait
echo "mysqld initialized"
/usr/sbin/mysqld --user=mysql &
echo "mysqld boot"
# wait for the mysql.sock file to be created
# If you do not wait, you will get the error below when executing the command to change the password.
# ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
while [ ! -e $SOCKFILE ]
do
sudo sleep 1
done
# get the init password
DB_INIT_PASSWORD=$(sudo grep 'temporary password' /var/log/mysql/mysql-error.log | sudo awk '{print $13}')
# change root password
sudo mysql -u root -p${DB_INIT_PASSWORD} --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${2}'; CREATE USER '${3}'@'%' IDENTIFIED BY '${4}'; GRANT ALL ON *.* TO 'admin'@'%'; FLUSH PRIVILEGES;"
else
/usr/sbin/mysqld --user=mysql &
echo "mysqld boot"
fi
- 最初の方はテンプレートから設定ファイルをコピー・一部設定をパラメータで置換
if [ ! -e $SYSDBPATH$DBINDFILE ]; then
以降は結構クセモノ。初回起動時は MySQL のデータファイルが存在しないため--initialize
オプション で初期化を試みます- データファイルの配置場所は永続化しているので、初めて Dockerコンテナ をビルドしたのかそうでないのかで MySQL のデータファイルの有無が変化します
- 問題は初回起動なのか異なるのかの判定。今回は
sys_config.ibd
が存在するかどうかで判定することで成功しました- なお、初期化からソケットが作られる (
mysql.sock
ファイル が作成される) まで時間がかかるため、while [ ! -e $SOCKFILE ]
の条件とsudo sleep 1
で確立まで待機しています - 初期化時に
root
のパスワードがログファイルに吐き出されるため、以下を実行awk
コマンド で取り出し- 取り出した初期パスワードを用い、
.env
にあるパスワードに変更するようにroot
パスワード 変更の SQL文 を実行- このとき通常だとエラーが出てしまうので
-e
オプション を指定
- このとき通常だとエラーが出てしまうので
- なお、初期化からソケットが作られる (
sys_config.ibd
が存在する(=2回目以降の起動) 場合は、単純に MySQL のプロセスを起動するだけ
以上のような工程を実行しています。
phpMyAdmin に関しては公式イメージを利用し、環境変数で設定を実施しているだけなのでスルーします。
余談 (名前の由来)
以上を以て一通りの LAMP環境 となったわけですが、この設定集には「Ambergrease」と名前を付けました。
アンバーグリス。龍涎香。かつては龍の涎が固まったものと考えられていたためにその名前となったわけですが、英名の方は古フランス語の ambre gris から、らしいです。
その正体はマッコウクジラの腸内に発生する結石。クジラは Docker のロゴでおなじみですね(種は問わず)。
さて、マッコウクジラ等のクジラから採れる油脂は灯りの燃料としても用いられたという歴史があるようです。
灯り、すなわちランプ(LAMP)。そこでこのマッコウクジラからの連想で、油を重視して grease の単語を採用しました。
クジラによるLAMP。そのため、「Ambergrease」。
参考
MySQL 初期化
- MySQL :: MySQL 8.0 リファレンスマニュアル :: 2.10.1 データディレクトリの初期化
- CentOS に MySQL8.0をインストールする | 404 motivation not found
bin/mysqld --initialize --user=mysql &
とか /usr/sbin/mysqld --user=mysql --initialize &
とか
5.7 からは mysqld --initialize
に変更。それ以前は mysql_install_db
。
ディレクトリ初期化
# chown -R mysql /var/lib/mysql/
# chgrp -R mysql /var/lib/mysql/
※ basedir = /var/lib/mysql/
の場合
mysql-files
Insecure configuration for –pid-file: Location ‘/var/run/mysqld’ in the path is accessible to all OS users. Consider choosing a different directory.
初期管理者パスワード変更
Warning: Using a password on the command line interface can be insecure
[MySQL][ERROR] Fatal error: Please read “Security” section of the manual to find out how to run mysqld as root!
[Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
[ERROR] [MY-011011] [Server] Failed to find valid data directory.
ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)
mysql.sock がない
- Dockerで立ち上げたmysqldに接続する | ハックノート
- MySQL server through socket ‘/tmp/mysql.sock’ – Qiita
- Dockerコンテナ上のMySQLにホストOSから接続できなくて調査・対応したのでメモ – delhi09の勉強日記
- mysql locahost の接続では、unix socket かTCPかを明示しないとsock エラーで混乱した – それマグで!
外部接続
シェルスクリプト
wait
コマンド実行結果を echo で出力
Docker の MySQL公式イメージ
それ以上のことを行いたい場合には別の方法で行う必要がある。 鍵をにぎるのが同じくdocker-entrypoint.shの中に記述のある、/docker-entrypoint-initdb.d/だ。 このディレクトリにある、シェルスクリプトやsqlファイルが実行されるようになっている。
何……だと……(早く知りたかった
Docker Compose
ログ確認には docker-compose logs
。
Docker Compose の command と entrypoint
- docker-compose.ymlのcommandプロパティに複数コマンドを設定する方法 | ゲンゾウ用ポストイット
- docker-composeで指定するcommandはDockerfileよりも優先される – Qiita
- docker-compose.ymlでcommandの引数が長いのでエスケープして改行したい – Qiita
- [DockerCompose]Commandを複数行実行する方法 | エンジニアの眠れない夜