今回、新たにセットアップしたサーバで CGI から MySQL への接続がうまくいかない。
環境は、
CentOS 7.4(1708)Apache 2.4.39MySQL 8.0.16Perl 5.16.3DBI 1.627DBD::mysql 4.023
というソフトウェア構成。
Apache は systemd(init に変わる起動処理やシステム管理を行う仕組み)を使って起動している。
(systemctl start httpd.service というコマンドで起動しているというわけね)
で、この環境で、CGI から DBI/DBD 経由で MySQL にアクセスすると、
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
というエラーが発生してしまう。
しかし、/tmp/mysql.sock は存在している。権限関係も問題ない。
# ls -la /tmp/mysql*srwxrwxrwx 1 mysql mysql 0 May 31 09:55 /tmp/mysql.sock-rw------- 1 mysql mysql 5 May 31 09:55 /tmp/mysql.sock.lock
いやぁ、ハマったわぁ~(^^;
結局、オチから言うと、これって systemd の PrivateTmp 機能による問題で、例えばソケットの置き場所を /var/lib/mysql/mysql.sock とかにしていた人には発生しない。
どういうことかというと、今回、ソースビルドした Apache についても systemd で管理(起動等)をしているのは上に書いたとおり。
で、systemd 経由で起動したデーモン(今回は Apache)は、それぞれ独自の /tmp ディレクトリが用意される。
つまり、Apache 上で実行される CGI プログラムが見ている /tmp と、本来の /tmp ディレクトリは全然別物なので、いくら MySQL が(本来の)/tmp ディレクトリ上にソケットファイル(mysql.sock)を用意しても、CGI プログラムからは見えないのである。
結果、
DBI connect('dbname=hoge_db;host=localhost;port=3306;mysql_socket=/tmp/mysql.sock','hoge_admin',...) failed: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) at ./db_connect_test.pl line 42.
というエラーとなってしまう。
反対に、ソケットファイルの置き場を /tmp ではなく /var/lib/mysql/mysql.sock などにしていた場合は CGI からも見ることができる。これは、/tmp(/var/tmp も?)だけの問題である。
tmp は temporary の略で、/tmp ディレクトリというのは文字通り「一時ファイル」の置き場所。そのため、誰でも読み書きできるようになっており、それを専用に用意することで安全性や利便性を上げようって思想なんだろうけど、裏目に出たなあ>俺のところでは(^^;
ちなみに、じゃあ、プロセス毎の /tmp ってどこにあるの?というと、/tmp ディレクトリの下にある。
# ls -lad /tmp/systemd*drwx------ 3 root root 4096 Apr 20 2016 /tmp/systemd-private-4ee168e88455407fa3b27bd35ffb371d-ntpd.service-1GgKhBdrwx------ 3 root root 4096 May 22 16:24 /tmp/systemd-private-bf1b49c0e6014448894be7a3091317ee-ntpd.service-5jH2a8drwx------ 2 root root 4096 Feb 8 2016 /tmp/systemd-private-W69tS0# ls -la /tmp/systemd-private-4ee168e88455407fa3b27bd35ffb371d-ntpd.service-1GgKhBtotal 12drwx------ 3 root root 4096 Apr 20 2016 .drwxrwxrwt 13 root root 4096 May 31 14:44 ..drwxrwxrwt 2 root root 4096 Apr 20 2016 tmp# ls -la /tmp/systemd-private-4ee168e88455407fa3b27bd35ffb371d-ntpd.service-1GgKhB/tmptotal 8drwxrwxrwt 2 root root 4096 Apr 20 2016 .drwx------ 3 root root 4096 Apr 20 2016 ..
こういう具合に、systemd が /tmp の下にそれぞれのプロセスごとに専用の /tmp を用意している。
じゃ、どうするかって話なんだけど、ソケットファイルを /tmp 以外のディレクトリに置けばいいんだけど、もう多くの CGI などで明示的に /tmp/mysql.sock を指定しているので全部直すのも大変。
とりあえず、sysytemd 経由での起動をやめる。
手動で apachectl コマンドを叩いて実行。
# systemctl stop httpd# /usr/local/apache2/bin/apachectl start# ps auxww|grep httproot 21911 0.0 0.2 114864 4516 ? Ss 13:45 0:00 /usr/local/apache-2.4.39/bin/httpd -k startapache 21912 0.0 0.1 114656 2756 ? S 13:45 0:00 /usr/local/apache-2.4.39/bin/httpd -k startapache 21913 0.0 0.1 401692 3328 ? Sl 13:45 0:00 /usr/local/apache-2.4.39/bin/httpd -k startapache 21914 0.0 0.1 401692 3324 ? Sl 13:45 0:00 /usr/local/apache-2.4.39/bin/httpd -k startapache 21916 0.0 0.1 401692 3324 ? Sl 13:45 0:00 /usr/local/apache-2.4.39/bin/httpd -k startroot 22011 0.0 0.0 112708 948 pts/1 S+ 13:45 0:00 grep --color=auto http
これで、CGI からも MySQL へのアクセスが可能となった。
systemd の PrivateTmp 機能を無効にする方法を調べるまでは、とりあえずこの運用とする。
コメントする