
次の内容のスクリプトがあります。
sudo machinectl start "$machinename"
sudo systemd-run -PM root@"$machinename" "$command"
Failed to connect to bus: No such file or directory
Failed to start transient service unit: Transport endpoint is not connected
最初の行はコンテナを起動するため失敗します。 2行目は、コンテナの起動が完了する前に実行されます。現在、コンテナの状態をポーリングし続け、準備が整うまでブロックするソリューションがあります。
while [ "$(sudo systemctl show "systemd-nspawn@$machinename" -P StatusText)" != "Container running: Ready." ]
do
true
done
コンテナの状態を継続的にポーリングせずにコンテナの起動が完了するまでどのように待つことができますか?
答え1
やりたいことによって異なります。あなたの質問に直接答えて、いくつかの選択肢を提供します。コンテナからinitシステムとしてsystemdを使用しているとします。コンテナOSがDebian / Arch / Ubuntuまたはそれに似た基盤である場合は実際にはそうです。
nspawn コンテナの起動後にコマンドを実行します。
.nspawn
ファイル(/etc/systemd/nspawn/yourcontainer.nspawn
)に以下を追加します。
[Exec]
NotifyReady=yes
次に、sudo machinectl start yourcontainer
コンテナが終了する前に起動が完了するのを待ちます。コンテナが準備されたので、スクリプトの2行目が機能します(コンテナが起動しないため、ポーリングが無限ループに陥らない限り)。
内部的には、ホストはsystemd-nspawn
コンテナにUnixドメインソケットを設定しています。/run/host/notify
コンテナの systemd が準備されると (つまり、ターゲットmulti-user.target
に到達すると)、READY=1
そのソケットに通知を送信します。ホストのsystemd-nspawn
サービスがメッセージの受信を待っています。
このアプローチの欠点は、コンテナを非同期で起動できないことです(&
シンボルを使用しない限り)。これはデバッグ中で、起動時間が長い場合は迷惑になる可能性があります。
その他の方法(複雑度順):
chrootでコマンドを実行する
コンテナが実行されていないと仮定すると、
sudo chroot /var/lib/machines/yourcontainer /bin/bash -c "$command"
これは、コンテナを作成してプログラムで複数回初期化した場合に便利です。明らかに、サンドボックス機能の利点を得ることができないようです。PrivateUsers=yes
ファイルはchown
高いUIDで編集されるため、以前に同じコンテナを実行しても機能しません。コンテナがすでに実行されている場合、未定義の結果が表示されることがあります。
systemd-nspawnを直接使用する
この方法は果たしていいえNotifyReady=yes|no
上記の説明が必要です。
systemd-nspawn -M yourcontainer -P /bin/bash -c "$command"
これにより、すべてのサンドボックスがアクティブなコンテナ内でコマンドが実行されますが、コマンドは唯一のプロセスとして(およびPID=1
)実行されます。つまり、initサービスは実行されません。たとえば、ホストネットワーキングを使用しない限り、ネットワーキングは使用できません。
コンテナがすでに実行されている場合、このコマンドは何もしません。
ソケットの有効化
コンテナのサーバーが準備されるのを待つ場合は、ソケットアクティベーションを使用できます(サーバーが互換性があると仮定)。これは他の場所でより良い説明要約すると、systemdはソケット(TCPポート80など)への接続を待ちます。クライアントが接続されると、systemd はコンテナを起動し、コンテナにトラフィックを転送します。古代にもinetd
同じことが行われました。
これにはファイル[email protected]
内のものと同じ行が必要です.socket
。