Write failed: Broken pipeでssh接続が切断されるのを防ぐ

sshで接続したあと操作せずに一晩捨ておくと知らぬ間に「Write failed: Broken pipe」というメッセージが表示されてセッションが切断されている。再度、接続し直すのも手間であるから設定を取り繕って切断されぬようにするものである。

$ vi ~/.ssh/config
Host *
  ServerAliveInterval 30
  ServerAliveCountMax 10

ServerAliveIntervalはサーバからデータが送られてこなくなってから何秒後に応答を求めるメッセージを投げつけるか定める模様である。デフォルトではそもメッセージを放たないという。メッセージの中身をtcpdumpで覗いてみるとPSHフラグを立てたパケットを送りつけているようであった。

$ sudo tcpdump -n -i ens3 port 22
(snip)
22:50:30.488309 IP 192.0.2.1.55773 > 153.121.51.164.22: Flags [P.], seq 72:108, ack 109, win 305, options [nop,nop,TS val 1047147664 ecr 177098205], length 36
22:50:30.488696 IP 153.121.51.164.22 > 192.0.2.1.55773: Flags [P.], seq 109:145, ack 108, win 309, options [nop,nop,TS val 177105717 ecr 1047147664], length 36
22:50:30.506156 IP 192.0.2.1.55773 > 153.121.51.164.22: Flags [.], ack 145, win 305, options [nop,nop,TS val 1047147668 ecr 177105717], length 0

22:51:00.536025 IP 192.0.2.1.55773 > 153.121.51.164.22: Flags [P.], seq 108:144, ack 145, win 305, options [nop,nop,TS val 1047155176 ecr 177105717], length 36
22:51:00.536334 IP 153.121.51.164.22 > 192.0.2.1.55773: Flags [P.], seq 145:181, ack 144, win 309, options [nop,nop,TS val 177113229 ecr 1047155176], length 36
22:51:00.554444 IP 192.0.2.1.55773 > 153.121.51.164.22: Flags [.], ack 181, win 305, options [nop,nop,TS val 1047155180 ecr 177113229], length 0
(snip)

ServerAliveCountMaxはサーバからの反応が無くなった際、応答を呼びかけるメッセージを何回送りつけるかを定め、これを超えたら切断してセッションを終える模様である。デフォルトでは3回という取り決めであった。したがって概ね

ServerAliveInterval ✕ ServerAliveCountMax

秒の間、サーバから返答がなければTimeout, server hostname not responding.というようなメッセージと共に切断するというものである。

参考:
man ssh_config
How to prevent “Write Failed: broken pipe” on SSH connection?

systemdを用いてマシン起動時にMySQLを起動するよう設定

OS: Ubuntu Server 16.04
MySQL 5.7.21

大変な権勢を誇っているsystemdで以ってMySQLの起動や停止を管理しようと息巻いてオンラインの文献を二、三斜め読みしたところでこれはえらいものに手を出してしまったぞと気付いた。マニュアルが多数あり分量も膨大でどこから手を付けていいか途方に暮れた。も少し軽薄に臨む心づもりでいたからこれには参った。とまれMySQLのドキュメントを見ているとcmakeのオプションでsystemd用のファイルをインストールするものがあるようである。

-DWITH_SYSTEMD=bool

Whether to enable installation of systemd support files. By default, this option is disabled. When enabled, systemd support files are installed, and scripts such as mysqld_safe and the System V initialization script are not installed. On platforms where systemd is not available, enabling WITH_SYSTEMD results in an error from CMake.

-DWITH_SYSTEMD=1を加えてMySQLをビルド、インストールしてみるとなるほどmysqld.serviceというファイルがインストールディレクトリに放り込まれて居る。どのような取り扱いが定石であるか判然としないけれども、手探りで設定したところなんだか希望どおりには動いている模様である。まずはMySQLの起動オプションを書き付けた。

$ sudo vi /etc/default/mysql
MYSQLD_OPTS="--basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=mysql.err --pid-file=/usr/local/mysql/data/mysql.pid"

次にユニットファイル(mysqld.service)を/etc/systemd/system/へコピーし、みずからの環境に合致するようオプションを編集した。

$ cd /usr/local/mysql
$ sudo cp mysqld.service /etc/systemd/system/
$ sudo vi /etc/systemd/system/mysqld.service
#PIDFile=/var/run/mysqld/mysqld.pid
PIDFile=/usr/local/mysql/data/mysql.pid

#ExecStart=/usr/local/mysql/bin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS
ExecStart=/usr/local/mysql/bin/mysqld --daemonize $MYSQLD_OPTS

#EnvironmentFile=-/etc/sysconfig/mysql
EnvironmentFile=-/etc/default/mysql

そうしたらシステムの起動時にMySQLが起動するようsystemctl enableコマンドで執り成してやる。マシンを再起動してみるとたしかにMySQLが自動で立ち上がっているので概ね成功と言ってよかろうとおもう。

$ sudo systemctl enable mysqld.service
Created symlink from /etc/systemd/system/multi-user.target.wants/mysqld.service to /etc/systemd/system/mysqld.service.

$ systemctl list-unit-files mysqld.service
UNIT FILE      STATE
mysqld.service enabled

なお手動でMySQLを起動するならこういう具合である。ステータスを確認することもできるようである。

$ sudo systemctl start mysqld
$ sudo systemctl status mysqld
● mysqld.service - MySQL Server
   Loaded: loaded (/etc/systemd/system/mysqld.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2018-03-22 20:42:22 JST; 15s ago
(snip)
Mar 22 20:42:22 mysql-systemd-test systemd[1]: Started MySQL Server.

ユニットファイルの全貌はこういう塩梅である。

$ cat /etc/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target

[Service]
User=mysql
Group=mysql
Type=forking
PIDFile=/usr/local/mysql/data/mysql.pid
TimeoutSec=0
PermissionsStartOnly=true
ExecStartPre=/usr/local/mysql/bin/mysqld_pre_systemd
ExecStart=/usr/local/mysql/bin/mysqld --daemonize --pid-file=/usr/local/mysql/data/mysql.pid $MYSQLD_OPTS
EnvironmentFile=-/etc/default/mysql
LimitNOFILE = 5000
Restart=on-failure
RestartPreventExitStatus=1
PrivateTmp=false

参考:
systemd.exec
systemd – ArchWiki
systemd – Wikipedia
2.5.10 Managing MySQL Server with systemd
What is $OPTIONS in a systemd service file?

MySQL5.7.21をソースからインストール

OS: Ubuntu Server 16.04
MySQL 5.7.21

久しくMySQLのインストールから離れていたのでメモをとっておくものである。libncurses5-devが無いとcmakeのステージで下記のエラーメッセージが現れて処理が取りやめとなる。

CMake Error at cmake/readline.cmake:64 (MESSAGE):
  Curses library not found.  Please install appropriate package,

      remove CMakeCache.txt and rerun cmake.On Debian/Ubuntu, package name is libncurses5-dev, on Redhat and derivates it is ncurses-devel.

もっと以前のバージョンに於いてはconfigureスクリプトで以ってMakefileを生み出していたように思うけれども、近頃のMySQLはどうもcmakeである。そういう訳だから必要なパッケージを予めインストールしておく。

$ sudo apt install cmake libncurses5-dev

あとは公式の文献を手がかりに作業を進めてゆく。

$ sudo useradd -r -s /bin/false mysql
$ wget -c https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.21.tar.gz
$ wget -c https://dev.mysql.com/downloads/gpg/?file=mysql-5.7.21.tar.gz -O mysql-5.7.21.tar.gz.asc
$ gpg --recv-keys 5072E1F5
$ gpg --verify mysql-5.7.21.tar.gz.asc
$ tar zxvf mysql-5.7.21.tar.gz
$ cd mysql-5.7.21/
$ mkdir bld
$ cd bld/

CMAKE_INSTALL_PREFIXはデフォルトで/usr/local/mysqlである旨、記載があるから何もせずにいたのであるけれどもいったい何の都合か具合が悪い事があったのでいちいち明示したほうが良さそうな情勢である。

$ cmake .. -DDOWNLOAD_BOOST=1 -DWITH_BOOST=./boost/ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci
$ make
$ sudo make install
$ cd /usr/local/mysql/
$ sudo mkdir mysql-files
$ sudo chown mysql:mysql mysql-files/
$ sudo chmod 750 mysql-files/

データディレクトリの初期化を実施する。そうするとまるきりランダムに生成されたrootユーザのパスワードが現れる。このパスワードは態と有効期限が切らしてあるからリセットするまではMySQLを碌に操作できないものである。

$ sudo bin/mysqld --initialize --user=mysql
2018-03-19T02:49:10.755528Z 1 [Note] A temporary password is generated for root@localhost: Su>-%Gnhz86z

$ sudo bin/mysql_ssl_rsa_setup
$ sudo bin/mysqld_safe --user=mysql &
$ sudo cp -v support-files/mysql.server /etc/init.d/mysql.server
$ cd bin/

$ ./mysql -uroot -p
mysql> show databases;
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.

パスワードをリセットするためにset passwordステートメントを発行する。これでMySQLをほしいままに操れるようになる。

mysql> set password = 'avava';
Query OK, 0 rows affected (0.00 sec)

ひとまずMySQLをシャットダウンして作業は完了である。

$ sudo ./mysqladmin -uroot -p shutdown
Enter password:
2018-03-19T02:57:21.415800Z mysqld_safe mysqld from pid file /usr/local/mysql/data/guro.pid ended

参考:
2.9.2 Installing MySQL Using a Standard Source Distribution
2.9.4 MySQL ソース構成オプション
13.7.1.1 ALTER USER 構文

php.iniの正しい設置場所をあらためて確認する

OS: Ubuntu Server 16.04
Nginx 1.12.2
PHP 7.2.3

Nginxが稼働する環境へPHPをインストールするとなればNginx 1.4.x on Unix systemsの手続きを参照するのは無理からぬ事である。公式であるから全幅の信頼を寄せて盲目的に従うのもやはり無理からぬ事である。これが裏目に出た。第四番目の手続きである。

4. Obtain and move configuration files to their correct locations
cp php.ini-development /usr/local/php/php.ini

php.iniを/usr/local/php/へと配したのちに、OPcacheを有効にすべくphp.iniへ必要な記述をこなしてphp -vを実行するとこうである。

$ php -v
PHP 7.2.3 (cli) (built: Mar 17 2018 01:31:01) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

「with Zend OPcache v7.2.3, Copyright (c) 1999-2018, by Zend Technologies」が出力に表れないのでOPcacheが有効になっていない模様である。テストスクリプトの実行結果も「PHP Fatal error: Uncaught Error: Call to undefined function opcache_get_status()」とあるからまったく狼狽した。いくらインターネットのページを繰っても似たような状況に遭遇した人が見当たらないのでどうやら世界ではじめて犯したヘマである。情けない。さんざ調べた末、結局はphp.iniの設置場所が良くないようで/usr/local/libへと移動させることで解決を見た。

$ sudo mv /usr/local/php/php.ini /usr/local/lib/
$ php -v
PHP 7.2.3 (cli) (built: Mar 17 2018 01:31:01) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.3, Copyright (c) 1999-2018, by Zend Technologies

configureのヘルプからも特別に指定しなければ/usr/local/libにphp.iniを求めにゆくことが明らかである。

$ ./configure --help
(snip)
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [/usr/local]
  --with-config-file-path=PATH
                          Set the path in which to look for php.ini [PREFIX/lib]

またphp -iの実行結果から現在の設定を確かめることができるから、php.iniの設定が反映されずどうも様子がおかしいと感ずるときは確認をするのが良さそうである。

$ php -i | grep php.ini
Configuration File (php.ini) Path => /usr/local/lib
Loaded Configuration File => /usr/local/lib/php.ini

参考:
Nginx 1.4.x on Unix systems

bashで変数をechoする際に文字列に含まれるアスタリスクがワイルドカードとして扱われないようにする

シェルスクリプトを組み上げる際に見栄えを考慮してオシャレなメッセージを表示しようとしたところ予期せぬ結果に困惑したものである。

$ msg="*** select * from avava;"
$ echo ${msg}
public_html src tmp select public_html src tmp from avava;

アスタリスク * がワイルドカードとして展開されているからいけない。これを抑制するには変数をダブルクォーテーションで囲い込んでやればよいのであった。

$ echo "${msg}"
*** select * from avava;

bashのマニュアルによればset -fやset -noglobコマンドによってダブルクォーテーションのあるなしに拘わらずアスタリスクをワイルドカードとして展開しないようにできる模様である。然し乍らあらゆる場合に於いてパス名の展開がおこなわれなくなるので影響を及ぼす範囲が明瞭でないなら控えたほうが良さそうな情勢である。

$ man bash
(snip)
       set [--abefhkmnptuvxBCEHPT] [-o option-name] [arg ...]
       set [+abefhkmnptuvxBCEHPT] [+o option-name] [arg ...]
              -f      Disable pathname expansion.
              -o option-name
                      noglob  Same as -f.

一旦展開しないようセットしたものの気が変わってやはり元の仕組みが嬉しい向きにはset +fやset +noglobを実行すればよろしい。

$ set -f
$ echo ${msg}
*** select * from avava;
$ echo "${msg}"
*** select * from avava;
$ ls *
ls: cannot access *: No such file or directory
$ set +f
$ echo ${msg}
public_html src tmp select public_html src tmp from avava;
$ echo "${msg}"
*** select * from avava;