systemd-nspawn コンテナを systemd 単位で管理

systemd-nspawn コンテナを systemd 単位で管理

質問

systemd-nspawnコンテナをsystemd単位で管理する方法は?

設定

イメージのインストール

# machinectl pull-raw --verify=no https://ftp.halifax.rwth-aachen.de/fedora/linux/releases/30/Cloud/x86_64/images/Fedora-Cloud-Base-30-1.2.x86_64.raw.xz

画像名が見つかりました。

# machinectl list-images
NAME                            TYPE RO  USAGE  CREATED                     MODIF
Fedora-Cloud-Base-30-1.2.x86_64 raw  no  891.6M Fri 2019-04-26 02:14:49 UTC Fri 2

1 images listed.

Fedoraコンテナ内で対話型シェルを起動する

# systemd-nspawn -M Fedora-Cloud-Base-30-1.2.x86_64

/root/app.pyでシグナルを処理するpython3アプリケーションの作成

# https://stackabuse.com/handling-unix-signals-in-python/
import signal
import os
import time
import sys

def terminateProcess(signalNumber, frame):
    print(f'received signal {signalNumber}')
    print ('exiting...')
    sys.exit()

def receiveSignal(signalNumber, frame):
    print(f'received signal {signalNumber}')
    return

if __name__ == '__main__':
    # register the signals to be caught
    signal.signal(signal.SIGHUP, receiveSignal)
    signal.signal(signal.SIGINT, terminateProcess)
    signal.signal(signal.SIGQUIT, receiveSignal)
    signal.signal(signal.SIGILL, receiveSignal)
    signal.signal(signal.SIGTRAP, receiveSignal)
    signal.signal(signal.SIGABRT, receiveSignal)
    signal.signal(signal.SIGBUS, receiveSignal)
    signal.signal(signal.SIGFPE, receiveSignal)
    #signal.signal(signal.SIGKILL, receiveSignal)
    signal.signal(signal.SIGUSR1, receiveSignal)
    signal.signal(signal.SIGSEGV, receiveSignal)
    signal.signal(signal.SIGUSR2, receiveSignal)
    signal.signal(signal.SIGPIPE, receiveSignal)
    signal.signal(signal.SIGALRM, receiveSignal)
    signal.signal(signal.SIGTERM, terminateProcess)

    # output current process id
    print(f'pid {os.getpid()}')

    # wait in an endless loop for signals 
    while True:
        time.sleep(1)

キーの組み合わせを使用してコンテナを終了する

Control + ]]]

アプリケーションサービス体験1

/etc/systemd/system/app.service 単位ファイルを作成します。

[Service]
ExecStart=/usr/bin/systemd-nspawn --keep-unit -M Fedora-Cloud-Base-30-1.2.x86_64 python3 -u /root/app.py
SyslogIdentifier=%N
  • --keep-unitsystem.slice/app.servicecgroupにsystemd-nspawnとapp.pyを保持するように切り替える
  • -uバッファされていない出力スイッチ
  • %Nサフィックスのないデバイス名「app」文字列を使用するSyslogIdentifier指定子

systemdデーモンを再ロードしてください。

# systemctl daemon-reload

他の端末では、systemd-journald を使用してログ出力を追跡します。

# journalctl -f -u app.service

app.serviceユニットの起動

# systemctl start app.service

app.serviceユニットを停止

# systemctl stop app.service

観察記録

-- Logs begin at Fri 2019-08-23 16:58:11 UTC. --
Aug 23 17:26:42 srv0 systemd[1]: Started app.service.
Aug 23 17:26:42 srv0 app[12745]: Spawning container Fedora-Cloud-Base-30-1.2.x86_64 on /var/lib/machines/Fedora-Cloud-Base-30-1.2.x86_64.raw.
Aug 23 17:26:42 srv0 app[12745]: Press ^] three times within 1s to kill container.
Aug 23 17:26:42 srv0 app[12745]: Failed to create directory /tmp/nspawn-root-afZQoJ/sys/fs/selinux: Read-only file system
Aug 23 17:26:42 srv0 app[12745]: Failed to create directory /tmp/nspawn-root-afZQoJ/sys/fs/selinux: Read-only file system
Aug 23 17:26:42 srv0 app[12745]: pid 1
Aug 23 17:26:54 srv0 systemd[1]: Stopping app.service...
Aug 23 17:26:54 srv0 app[12745]: Container Fedora-Cloud-Base-30-1.2.x86_64 terminated by signal KILL.
Aug 23 17:26:54 srv0 systemd[1]: app.service: Main process exited, code=exited, status=1/FAILURE
Aug 23 17:26:54 srv0 systemd[1]: Stopped app.service.
Aug 23 17:26:54 srv0 systemd[1]: app.service: Unit entered failed state.
Aug 23 17:26:54 srv0 systemd[1]: app.service: Failed with result 'exit-code'.
Aug 23 17:26:54 srv0 systemd[1]: Stopped app.service.

systemd-nspawn は SIGTERM の代わりに SIGKILL を使用します。

Aug 23 17:26:54 srv0 app[12745]: Container Fedora-Cloud-Base-30-1.2.x86_64 terminated by signal KILL.「app.pyをSIGKILLしたくないSIGTERMしたい」行を参照してください。

アプリケーションサービス体験2

Githubの問題を読む

https://github.com/systemd/systemd/issues/7105#issuecomment-467491778

-a/--as-pid2スイッチの使用

[Service]
ExecStart=/usr/bin/systemd-nspawn --keep-unit --as-pid2 -M Fedora-Cloud-Base-30-1.2.x86_64 python3 -u /root/app.py
SyslogIdentifier=%N

デーモンの再ロード、開始、停止

観察記録

Aug 23 17:29:59 srv0 systemd[1]: Started app.service.
Aug 23 17:29:59 srv0 app[12841]: Spawning container Fedora-Cloud-Base-30-1.2.x86_64 on /var/lib/machines/Fedora-Cloud-Base-30-1.2.x86_64.raw.
Aug 23 17:29:59 srv0 app[12841]: Press ^] three times within 1s to kill container.
Aug 23 17:29:59 srv0 app[12841]: Failed to create directory /tmp/nspawn-root-jaGbcx/sys/fs/selinux: Read-only file system
Aug 23 17:29:59 srv0 app[12841]: Failed to create directory /tmp/nspawn-root-jaGbcx/sys/fs/selinux: Read-only file system
Aug 23 17:29:59 srv0 app[12841]: pid 2
Aug 23 17:30:06 srv0 systemd[1]: Stopping app.service...
Aug 23 17:30:06 srv0 app[12841]: Container Fedora-Cloud-Base-30-1.2.x86_64 terminated by signal KILL.
Aug 23 17:30:06 srv0 systemd[1]: app.service: Main process exited, code=exited, status=1/FAILURE
Aug 23 17:30:06 srv0 systemd[1]: Stopped app.service.
Aug 23 17:30:06 srv0 systemd[1]: app.service: Unit entered failed state.
Aug 23 17:30:06 srv0 systemd[1]: app.service: Failed with result 'exit-code'.

app.pyはpid 2で実行されます!しかし、まだSIGTERMの代わりにSIGKILL信号を受け取ります。

ベストアンサー1

その他のGithubの問題を読む

https://github.com/systemd/systemd/issues/7105#issuecomment-467491778

--kill-signalフラグの使用

[Service]
ExecStart=/usr/bin/systemd-nspawn --keep-unit --kill-signal=SIGTERM -M Fedora-Cloud-Base-30-1.2.x86_64 python3 -u /root/app.py
SyslogIdentifier=%N

systemdを再ロードしてapp.serviceを起動してからapp.serviceを停止します。

systemctl daemon-reload
systemctl start app.service
systemctl stop app.service

観察記録

Aug 23 17:51:32 srv0 systemd[1]: Started app.service.
Aug 23 17:51:32 srv0 app[12994]: Spawning container Fedora-Cloud-Base-30-1.2.x86_64 on /var/lib/machines/Fedora-Cloud-Base-30-1.2.x86_64.raw.
Aug 23 17:51:32 srv0 app[12994]: Press ^] three times within 1s to kill container.
Aug 23 17:51:32 srv0 app[12994]: Failed to create directory /tmp/nspawn-root-71uVxm/sys/fs/selinux: Read-only file system
Aug 23 17:51:32 srv0 app[12994]: Failed to create directory /tmp/nspawn-root-71uVxm/sys/fs/selinux: Read-only file system
Aug 23 17:51:32 srv0 app[12994]: pid 1
Aug 23 17:51:35 srv0 app[12994]: Trying to halt container. Send SIGTERM again to trigger immediate termination.
Aug 23 17:51:35 srv0 app[12994]: received signal 15
Aug 23 17:51:35 srv0 app[12994]: exiting...
Aug 23 17:51:35 srv0 systemd[1]: Stopping app.service...
Aug 23 17:51:35 srv0 app[12994]: Container Fedora-Cloud-Base-30-1.2.x86_64 exited successfully.
Aug 23 17:51:35 srv0 systemd[1]: Stopped app.service.
Aug 23 17:51:35 srv0 systemd[1]: Stopped app.service.

SIGTERMがapp.pyにどのように渡されるかを見てください!

おすすめ記事