kmkのメモ帳

気が向いたときにLinuxだったり、プログラミングだったり、適当なメモを書いてます。

Blogは移転しました。

自動的にリダイレクトします。

CentOS6系にdaemontoolsとtcpserverをインストール

tcpserverについて

tcpserverはポートのLISTENやサーバ制御を行うプログラムです。

D.J.Bernsteinさんが作成したプログラムです。

tcpserverはサービス毎にtcpserverプロセスを起動してます。 そのため、各サービス毎にIP制限をかけたり、同時接続数制限も簡単に設定できます。

daemontoolsについて

daemontoolsは起動プロセス(デーモン)を監視し、 何らかの理由でプロセスが停止したときに自動起動してくれたりする便利なやつです。 ログの取得も簡単に設定できます。

daemontoolsも同じくD.J.Bernsteinさんが作成したプログラムです。偉大すぎる。

この2つを利用することによって、異常終了とかでサービスが落ちたら自動起動したり(daemontoolsの機能)、 ログの取得(daemontoolsの機能)、サービスの接続制限(tcpserverの機能)、などが簡単にできるようになります。

今回はLinuxからdropboxのサービスにアクセスする際に必要なdropboxのデーモンを、daemontools経由で起動するように設定してみます。dropboxデーモンは、dropboxユーザでインストール済みとします。(tcpserverはインストールするだけで今回使いません)

下記は前に書いたdropboxデーモンのインストール手順です。下記blog手順ではrootユーザでやっちゃってますが、後でdropboxユーザにインストールしなおしてます。ユーザが変わっても手順を読み替えれば適時実施できるかと思います。 q068891.hatenablog.com

今回はCentOS6.9にtcpserverdaemontoolsをそれぞれインストールしていきます。まずはtcpserverから。

tcpserverインストール

D.J.Bernsteinさんのページからソースもってきてインストールします。

# cd /usr/local/src ;pwd
# wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz
# tar xfz  ucspi-tcp-0.88.tar.gz 
# cd ucspi-tcp-0.88 ;pwd

そのままmakeを叩くとエラーになります。

# make
エラー抜粋
------------------------------------------------------
./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \
        dns.a time.a unix.a byte.a  `cat socket.lib`
/usr/bin/ld: errno: TLS definition in /lib64/libc.so.6 section .tbss mismatches non-TLS reference in tcpserver.o
/lib64/libc.so.6: could not read symbols: Bad value
collect2: ld returned 1 exit status
make: *** [tcpserver] Error 1
------------------------------------------------------

エラー回避のためerror.hを編集します。

# vi error.h
extern int errno; を #include <errno.h>に変更
▼差分
# diff -C2 error.h.20180609 error.h
*** error.h.20180609    Sun Mar 19 00:18:42 2000
--- error.h     Sat Jun  9 04:49:59 2018
***************
*** 2,6 ****
  #define ERROR_H
  
! extern int errno;
  
  extern int error_intr;
--- 2,6 ----
  #define ERROR_H
  
! #include <errno.h>
  
  extern int error_intr;
# 

編集後、もう一回make。成功しました。

# make      
./compile tcpserver.c
./compile remoteinfo.c
./compile timeoutconn.c

---省略---

./auto-str auto_home `head -1 conf-home` > auto_home.c
./compile auto_home.c
./load install hier.o auto_home.o unix.a byte.a 
./compile instcheck.c
./load instcheck hier.o auto_home.o unix.a byte.a 
#
# echo $?
0
#

続いてmake setup checkを実行します。

# make setup check
./install
./instcheck
# 
# echo $?
0
# 

今までの手順が正常に終われば/usr/local/bin/配下にtcpserverとかが設置されているはずです。

# ls -la /usr/local/bin/tcpserver 

tcpserverインストールはこれで完了です。続いてdaemontoolsをインストールします。

daemontoolsインストール

こちらもtcpserverと同じく、D.J.Bernsteinさんのページからソースもってきてインストールしていきます。

# cd /usr/local/src/;pwd
# wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz

/packageディレクトリ作成してそこに移動し、解凍します。

# mkdir -p /package
# chmod 1755  /package
# cd /package/; pwd
# tar xfz /usr/local/src/daemontools-0.76.tar.gz 
# cd /package/admin/daemontools-0.76/ ;pwd

そのままインストール実行すると、エラーがでます。

# package/install 
エラー抜粋
------------------------------------------------------
./load envdir unix.a byte.a 
/usr/bin/ld: errno: TLS definition in /lib64/libc.so.6 section .tbss mismatches non-TLS reference in envdir.o
/lib64/libc.so.6: could not read symbols: Bad value
collect2: ld returned 1 exit status
make: *** [envdir] Error 1
------------------------------------------------------

error.hをtcpserverと同じく修正します。

# vi /package/admin/daemontools-0.76/src/error.h
---
extern int errno; を #include <errno.h>に変更
---
▼差分
# diff -C3 /package/admin/daemontools-0.76/src/error.h.20180609 /package/admin/daemontools-0.76/src/error.h
*** /package/admin/daemontools-0.76/src/error.h.20180609        Fri Jul 13 01:49:49 2001
--- /package/admin/daemontools-0.76/src/error.h Sat Jun  9 05:22:58 2018
***************
*** 3,9 ****
  #ifndef ERROR_H
  #define ERROR_H
  
! extern int errno;
  
  extern int error_intr;
  extern int error_nomem;
--- 3,9 ----
  #ifndef ERROR_H
  #define ERROR_H
  
! #include <errno.h>
  
  extern int error_intr;
  extern int error_nomem;
# 

再度インストール実行。

# package/install 
Linking ./src/* into ./compile...
Compiling everything in ./compile...
./compile envdir.c
./compile alloc.c

---省略---

Making command links in /command...
Making compatibility links in /usr/local/bin...
Creating /service...
Adding svscanboot to inittab...
init should start svscan now.
# echo $?
0
# 

成功しました。/serviceディレクトリが作成されていたり、inittabにsvscanbootが起動するように追加されていたりするはずです。

/serviceディレクトリが自動的に作成されている。
# ls -ld /service/
drwxr-xr-x 2 root root 4096 Jun  9 05:25 /service/
# 

inittabに自動で追加されている。
# cat /etc/inittab  
抜粋
------------------------------------------------------
SV:123456:respawn:/command/svscanboot
------------------------------------------------------
#

svscanbootの中身確認
# cat /command/svscanboot 
#!/bin/sh
# WARNING: This file was auto-generated. Do not edit!

PATH=/command:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin

exec </dev/null
exec >/dev/null
exec 2>/dev/null

/command/svc -dx /service/* /service/*/log

env - PATH=$PATH svscan /service 2>&1 | \
env - PATH=$PATH readproctitle service errors: ................................................................................................................................................................................................................................................................................................................................................................................................................
# 

ただし、CentOS6場合inittabにはこんな記述があります。

 /etc/inittab より抜粋
------------------------------------------------------
# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# System initialization is started by /etc/init/rcS.conf
#
# Individual runlevels are started by /etc/init/rc.conf
#
------------------------------------------------------

ということで、inittabに追加された「SV:123456:respawn:/command/svscanboot」は無意味です。

inittabに追記された記述は消して、upstart経由で起動するようにします。

inittabの記述削除
# vi /etc/inittab 
# diff /etc/.backup/inittab.20180609 /etc/inittab 
28d27
< SV:123456:respawn:/command/svscanboot
# 
upstart経由で起動するように設定ファイル設置
# vi /etc/init/svscan.conf
---
start on runlevel [12345]
respawn
exec /command/svscanboot
---
#

これでdaemontoolsインストール完了です。 サーバを再起動するか、initctl start svscanを手動で実行することでsvscanが起動してきます。

続いて、dropboxデーモンをdaemontools経由で起動させる設定をしていきます。

dropboxデーモンをdaemontools経由で起動

daemontoolsはプロセス/デーモンを起動する際にrunファイルに沿ってプロセス/デーモンを起動しsvscanが監視し続けます。 ということで、runファイルを書いていきます。 尚、dropboxのデーモンは、dropboxユーザでディレクトリ /home/dropbox/ にインストール済みとします。

▼runファイル作成
# vi /home/dropbox/run
------------------------------------------------------
#!/bin/sh

exec /usr/local/bin/setuidgid dropbox /home/dropbox/.dropbox-dist/dropboxd 2>&1

------------------------------------------------------

※ execをなぜ入れるのかは後で説明します。

※ setuidgidでdropboxユーザ経由でdropboxデーモン立ち上げ

※ /home/dropbox/.dropbox-dist/dropboxdはdropboxデーモンを起動するコマンド

※ 2>&1はエラー出力を標準出力に変更するため。後でログ取得(multilog)設定をしますがmultilogは標準出力のみ拾います。エラーも拾うためにエラー出力を、標準出力に渡してます。

実行できるように権限変更
# chmod 755 /home/dropbox/run

runファイルを作成したら、svscanが監視している/service配下にrunファイルを作成したディレクトリのリンクを張ります。

# ln -s /home/dropbox/ /service/dropbox

リンクを張った段階からsvscanが検知して、runファイルに沿って起動されているはずです。プロセスをみたり、daemontools経由で起動しているデーモンの状態を確認できるsvstatコマンドで確認します。

supervise直下でdropboxデーモンがきちんと起動していることを確認
# ps auxwwf 
----
/bin/sh /command/svscanboot
\_ svscan /service
|   \_ supervise dropbox <--こいつ(supervise)の直下
|       \_ /home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/dropbox 
----

up状態できちんと起動時間(336秒)も伸びている(起動し続けている)ことを確認
# svstat /service/dropbox 
/service/dropbox: up (pid 3476) 336 seconds 
# 

これでひとまずdaemontools経由でdropboxのデーモンを起動することができました。

runファイルを書くときexecをなぜ入れる必要があるのか

execコマンドは現在のjobと置き換えて実行するコマンドです。

【 exec 】 現行のジョブに置き換えてコマンドを続行する | 日経 xTECH(クロステック)

execを入れなかった場合、daemontools経由で起動しているプロセスの「stop/start/restart」などが実行できる管理コマンドsvcコマンドが実行できません。 svcコマンドを実行しても、svcが送るシグナルはsupervise直下のrunプロセスの方にいってしまうからです。

例:runファイルを書くときにexec入れない場合

execを記述しない場合、起動すると下記のようなプロセスの親子関係となっています。

#ps auxwwf 
----
/bin/sh /command/svscanboot
\_ svscan /service
|   \_ supervise dropbox 
|       \_ /bin/sh ./run  <---supervise直下にはrunがきてしまっている
|           \_ /home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/dropbox
----

ためしにこの状態でdropboxデーモンをsvc -dでdownさせてみます。

# svc -d /service/dropbox/
#
# svstat /service/dropbox/
/service/dropbox/: down 3 seconds, normally up <---ステータスはdownしている。
#
#ps auxwwf 
----
\_ svscan /service
|   \_ supervise dropbox <---配下に何も無し。runプロセスが死んだ。
----
/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/dropbox 
↑dropboxデーモンはsuperviseから外れて勝手に起動し続けている。
----

svc -dでdownさせると、runファイルが死んでその子プロセスとなっていたdropboxデーモンはsuperviseから外れて、init直下に移って1人ぼっちで勝手に起動し続けます。 こうなると、svcコマンドではこの1人ぼっちのdropboxデーモンをstopすることもできません。

例:runファイルを書くときにexec入れた場合

execを記述した場合、起動すると下記のようなプロセスの親子関係となっています。

#ps auxwwf 
※supervise直下にdropboxデーモンがちゃんといる
----
/bin/sh /command/svscanboot
\_ svscan /service
|   \_ supervise dropbox
|       \_ /home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/dropbox
----

ためしにsvcで止めて(-d)、その後起動(-u)してみます。

# svc -d /service/dropbox/
# 
# svstat /service/dropbox/
/service/dropbox/: down 5 seconds, normally up
# 
#ps auxwwf 
※supervise配下に何もいない。init配下にもdropboxデーモンはいない。完全に死んだ。
----
\_ svscan /service
|   \_ supervise dropbox 
----
# svc -u /service/dropbox/
#
# svstat /service/dropbox/
/service/dropbox/: up (pid 3476) 3 seconds
# 
#ps auxwwf 
----
\_ svscan /service
|   \_ supervise dropbox
|       \_ /home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/dropbox <--正常に起動した。
----

正常にstop/startすることができました。ということでexecはsvcコマンドで管理するためには必須です。

ログ(multilog)設定

daemontools経由でのプロセス起動は実施できたので、プロセスのログを取得するように設定します。 ログ取得はmultilogを使います。multilogはプロセスが出力した標準出力をパイプ経由で受けて記録することができます。

設定方法はdropデーモンを起動したときと同じく、log用のrunファイルを作成して設定します。

まず、ログディレクトリを作成し、そこにrunファイルを作ります。

# mkdir /service/dropbox/log
# vi /service/dropbox/log/run
----
#!/bin/sh

exec multilog t n50 ./main
----
実行できるように権限変更
# chmod 755 /service/dropbox/log/run

multilogオプション説明

  • t : tai64n形式のタイムスタンプをログ先頭に付けます。

  • n50 : ログファイルをどれくらい残すかの設定です。この設定場合50ファイルログが残ります。

ログの設定が終わったので後はsvscanに読み込ませれば良いんですが、一度読み込ませてしまっているため、mvしたり、svc -xコマンドで完全に終了させてから立ち上げます。

とりあえず一旦落とす。
# svc -d /service/dropbox/

落ちたらドット.付きにmvする。
# mv -iv /service/dropbox /service/.dropbox 
`/service/dropbox' -> `/service/.dropbox'
# 

-xで完全に終了。
# svc -x /service/.dropbox/

supervise終了したことを確認。
# svstat /service/.dropbox/
/service/.dropbox/: supervise not running
# 

ディレクトリを戻す。戻すと勝手に起動されるはず。
# mv -iv /service/.dropbox /service/dropbox 
`/service/.dropbox' -> `/service/dropbox'
# 

dropboxデーモンと、ログがそれぞれ起動しているか確認。
# svstat /service/dropbox/
/service/dropbox/: up (pid 4146) 5 seconds
# 
# svstat /service/dropbox/log/
/service/dropbox/log/: up (pid 4145) 7 seconds
#

ログ取得用のプロセスが起動できたら、mainディレクトリが勝手に作成されてその中にログファイルができているはずです。確認してみます。

# ls -la /service/dropbox/log/main/
total 16
drwx------ 2 root root 4096 Jun 10 00:38 .
drwxr-xr-x 4 root root 4096 Jun 10 00:38 ..
-rw-r--r-- 1 root root 5606 Jun 10 00:40 current <----ログファイルが出力されている
-rw------- 1 root root    0 Jun 10 00:38 lock
-rw-r--r-- 1 root root    0 Jun 10 00:38 state
# 

ログファイル中身確認
# tail /service/dropbox/log/main/current 
@400000005b1bf4ea0848eefc dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/psutil._psutil_linux.so'
@400000005b1bf4ea084e80c4 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/psutil._psutil_posix.so'
@400000005b1bf4ea0a829ed4 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.pthread._linuxffi_pthread.so'
@400000005b1bf4ea17684d4c dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.fcntl._linuxffi_fcntl.so'
@400000005b1bf4ea17714dfc dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.sys.compiled._linuxffi_sys.so'
@400000005b1bf4ea1a34f23c dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/tornado.speedups.so'
@400000005b1bf4ea26538bdc dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/cpuid.compiled._cpuid.so'
@400000005b1bf4ea28526d04 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.resolv.compiled._linuxffi_resolv.so'
@400000005b1bf4eb158a36ac dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/posixffi.libc._posixffi_libc.so'
@400000005b1bf4eb16ed7fcc dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/librsyncffi.compiled._librsyncffi.so'
# 

タイムスタンプがtai64n形式なので、tai64nlocal コマンドをかませて確認
# tail /service/dropbox/log/main/current |tai64nlocal 
2018-06-10 00:40:16.138997500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/psutil._psutil_linux.so'
2018-06-10 00:40:16.139362500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/psutil._psutil_posix.so'
2018-06-10 00:40:16.176332500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.pthread._linuxffi_pthread.so'
2018-06-10 00:40:16.392711500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.fcntl._linuxffi_fcntl.so'
2018-06-10 00:40:16.393301500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.sys.compiled._linuxffi_sys.so'
2018-06-10 00:40:16.439677500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/tornado.speedups.so'
2018-06-10 00:40:16.643009500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/cpuid.compiled._cpuid.so'
2018-06-10 00:40:16.676490500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/linuxffi.resolv.compiled._linuxffi_resolv.so'
2018-06-10 00:40:17.361379500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/posixffi.libc._posixffi_libc.so'
2018-06-10 00:40:17.384663500 dropbox: load fq extension '/home/dropbox/.dropbox-dist/dropbox-lnx.x86_64-51.4.66/librsyncffi.compiled._librsyncffi.so'
#

ログの出力が確認できたので、ログ設定完了です。

設定は一見大変そうに見えますが、自分で書いたプログラムを気軽に起動して、ログも取りたいというときかなり便利です。ログは標準出力からパイプで引っ張ってくるので、プログラム側でのログ出力は標準出力/エラー出力さえ出しておけばOKですし。あと、落ちたら勝手に起動するので、落ちて欲しくないプログラム(落ちても勝手に起動して欲しいプログラム)をdaemontools経由で起動しておくとかなり便利です。

これで作業は全て完了です。

参考サイト

# # #