Ubuntu Weekly Recipe

第358回 Upstart Jobをsystemd Unitに変換する

この記事を読むのに必要な時間:およそ 3.5 分

OpenSSH Serverの場合

では,実際にOpenSSH Serverを例に2つの設定ファイルを比較してみましょう。以下は,Ubuntu 14.04 LTSにおけるopenssh-serverパッケージのUpstert Jobです(/etc/init/ssh.conf⁠⁠。

# ssh - OpenBSD Secure Shell server
#
# The OpenSSH server provides secure shell access to the system.

description     "OpenSSH server"

start on runlevel [2345]
stop on runlevel [!2345]

respawn
respawn limit 10 5
umask 022

env SSH_SIGSTOP=1
expect stop

# 'sshd -D' leaks stderr and confuses things in conjunction with 'console log'
console none

pre-start script
    test -x /usr/sbin/sshd || { stop; exit 0; }
    test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }

    mkdir -p -m0755 /var/run/sshd
end script

# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
# 'exec' line here instead
exec /usr/sbin/sshd -D

以下は同じくUbuntu 14.04 LTSにおけるopenssh-serverパッケージに含まれているsystemd Unitです(/lib/systemd/system/ssh.service⁠⁠。

[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=sshd.service

UpstartのJobファイルは「#」で始まるコメントを除くと,大抵はdescription stanzaでJobの説明を記述したあとに,まずは「start on」⁠stop on」で起動や終了の契機となるイベントを設定します。ssh.confで設定されている「runlevel」イベントはrc-sysinit.conf注4が最後にtelinitコマンドで発行しますので,rc-sysinit.confのJobの完了タイミングもしくは外部でtelinitコマンドを使った場合に評価されます。stop onの「[!2345]」「runlevelが0(halt)か1(single user)もしくは6(reboot)のときに停止する」という意味になります。

注4)
/etc/init.d/rcSを実行するTaskタイプのJobです。

systemdの場合はAfterで起動順序を,WantedByで依存関係を設定しています。multi-user.targetは,Ubuntuでいうところの「runlevel [2345]」に近いので,Afterによってnetwork.targetよりあとに起動することをUnitファイル内部で明示していること以外はUpstartと同じ内容だと思って良いでしょう。ちなみにUpstartの場合は,rc-sysinit.conf自体がネットワーク設定が完了したあとに起動されるようになっています。

Upstartの「respawn」「respawn limit 10 5」はexec stanzaで指定したプロセスが終了したときに自動再起動することとその処理を「5秒間隔で最大10回」と制限しています。systemdでは「Restart」directiveで,エラー終了時に再起動することを設定しています。

expect stopはUpstartがexecされたプロセスの起動完了の判定方法を指定します。execされたプロセスは,サービスの種類によって1回ないし2回forkすることがあります。Ubuntuのopenssh serverは環境変数SSH_SIGSTOPが設定されていたら起動完了後にSIGSTOPを送るパッチが適用されているので,このような設定になっています。systemdにおける同じような機能をもったdirectiveは「Type」です。

pre-start stanzaではサービス起動前に必要な準備を行います。場合によってはここやexec stanzaで,他のJobのために独自のイベントを発行することもあります。最後にexec stanzaでコマンドを実行したら起動完了です。systemdの場合はConditionPathExistsなどいくつかのdirectiveを組み合わせて同等のことを実現しているようです。

pre-start stanzaのように,UpstartのJobの中ではscript stanzaを使うことで,シェルスクリプトを記述することが可能です。script stanzaやexec stanzaで実行されるコマンドは「/bin/sh -e」経由で実行されることになっています。systemdにはそのような仕組みはなく,ExecStartなどは直接exec()されるので,別途外部スクリプトを用意するか,⁠/bin/sh -e」から書いたうえで「-c」で実行するスクリプトを文字列で渡してください。

まとめ

Ubuntu 14.04 LTSから16.04 LTSにアップグレードする際には,Upstartからsystemdへの移行と言う壁が立ちふさがる可能性があります。今からでも,systemdについての情報を集めておいても遅くはないでしょう。また,現時点でUbuntu 14.04 LTS上のサービス向けに起動ファイルを作成する必要がある場合は,systemdを念頭に起きながらUpstartで記述するのが無難です。もしイベント駆動である必要がないサービスであれば,従来のSysVInit向けの起動スクリプトを「/etc/init.d/」以下に置いてupdate-rc.dコマンドで有効・無効を管理すると言うのも1つの手かもしれません。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。