SSHセッションが閉じた後にバックグラウンドプロセスが終了するのはなぜですか?

SSHセッションが閉じた後にバックグラウンドプロセスが終了するのはなぜですか?

XManager xshell を SSH クライアントとして使用し、リモートサーバーに接続し、次のコマンドを実行します。

nohup sleep 60 &
ps -ef | grep sleep
exit

その後、もう一度ログインしてください。

ps -ef | grep sleep

そのプロセスが消えました!

この問題を引き起こす可能性がありますか? SSHデーモンはopenssh 8で、サーバーはredhat 7です。

答え1

にはsystemd-logind(デフォルト)設定があります。

KillUserProcesses=yes

あなたのログインプロファイル。ユーザーがログアウトすると、ログインセッション中にユーザーが開始したすべてのプロセスが終了します。これをいいえに設定するか、ユーザーに次の設定を指定できます。

KillExcludeUsers=yourusername

答え2

あなたが望むのは、後で再接続できるように「分離可能」な方法でリモートコマンドを実行するようです。nohupユーザーセッションが終了すると、実際にはハッキングが発生し、systemdはそれを処理します。

クリーンアップメカニズムを無効にしてシステムレベルでこの問題を解決するのではなく、一部の端末マルチプレクサ(などtmuxscreenを使用してこの問題をよりエレガントに解決できます。abduco

ターミナルマルチプレクサは、ログアウトしても引き続き実行される別々のセッションを作成できます。後でセッションに再接続してコンテンツを調整できます。

jsbillings @のコメント以降の編集:

私の最初の答えは正確でしたが、やや簡潔に見えたので、あなたは(おそらく)その意味を忘れてしまったかもしれません。

問題の核心は、「ビハインドストーリー情報」がかなり欠けており、jsbillings @がこれを正しく修正/解決する方法を詳しく説明しようとしていないことです。システム開発者にも大きな非難があります。

結局私はあなたに完全な答えを与えなかったので、間違っても私にあることを認めました。これは、ほとんどの現代のLinuxが動作する方法のために多少疲れて退屈でした(言及されたsystemdのために - そう、はい、あまりにも早くそれが起こります)。

まず、今見ているように、質問のタイトルも技術的に間違っているbashはここに入らないからです。ここでは、その使用はまったく関係ありません。これは、コマンドソルバー関連の問題ではなくシステムレベルの問題であるため、どのシェルでも可能です。

第二に、私の答えはまだ有効です。nohupを使用しないでください(jsbillingsソリューションでは動作しますが)これは、あなたが生まれてからずっと前に終わった時代の不都合なハッキングです。

今、ソリューションを準備してください。かなり長くなりますが、そうしなければならないからです。

まず、ご存知のように、私はsystemdがあまり好きではありません。しかし、残念ながら、ほとんどの基本的なLinuxでは、現在使用しているinitファイルがそれです。

また、常に良いヒントを覚えておいてください:「敵を知ってください」。興味深いことに、systemdに対する私の反対にもかかわらず、私はそれについて多くを知っており、私の答えはまだ非常に適格であることを確信しています。

systemdの主な問題は、少なくともこの場合は「あまりにも賢く」、自分があなたよりも賢くなると思うことです。そうかもしれません。そうでない場合:)。

また、systemdの「適切性」(文字通り見ている人の目で見たとき)が広く疑われるとき、コア開発チームはこれを「迅速に」解決するために数多くのハッキングを試み、愚かなことをすることを恥ずかしくないパターンでもあります。 。

ご存知のように、systemdは私たちが今「意見がある」と呼んでいます。私も自己主張が強く、二人の間があまり良くない。私はsystemdよりスマートなので、systemdがどこから来たのか理解しています。

今、あなたsystemdのソースを理解すると、実際のソリューションも提供できます。 Systemdとそのチームは「よりよく知っている」ので、このような教育(教育)を提供することにはあまり興味がありません(そして、ユーザーが知らないのでシステムを制御したいだけなので、教育はシステムにとって最も重要なものではありません) 。ドキュメントがかなり素晴らしいにもかかわらず、プロジェクトポイントです。

簡単に言えば、教育するのではなく、何百万もの画面やtmuxセッションを破壊するのではなく、前述のような不都合なハッキングを導入しました。

KillUserProcesses=yes
KillExcludeUsers=yourusername

しかし、私の目標は彼らの目標とは異なります。私はあなたに理解と知識を提供することによって制御したいと思います。それで、あなたはこの長い返事を読んでいます。

「分離可能な方法」でコマンドを実行することについて私が言ったことは(最終的に)まだ有効ですが、「今日の」Linuxは「20年前のLinux」ではありません。私の経験によれば、ほとんどの管理者とユーザーは実際の「linux now」時代より5〜20年ほど遅く生きています。これは教育情報の普及には役立ちません。

unice や Linux を扱うときは、歴史的観点が最善です。

10年前、Linuxは基本的なプロセス表示と構成技術であるいわゆるcgroupをサポートし始めました。以前は、プロセスが一度作成されると、少なくとも標準のUNIXシリーズシステムでは、元のコンテキストを観察して監査することが困難でした(そしてコストも安かった)。

CgroupはLinuxプロセス管理拡張です。

これらのcgroupの基本要素で多くを構築できます(リソースのクリーンアップと割り当て、コンテナの実装などに使用できます)。しかし、最も重要なのは、cgroupが非システムソフトウェアにアクセスできないことです。システムタグのcgroupですが、プロセス自体(ブラウザサンドボックスなどの非常に特別な場合を除く)は自分が属するcgroupを操作できません。これは、cgroup システム全体の非常に重要な属性です。

つまり、システムソフトウェアだけがcgroupを作成し、プロセスをcgroupに「移動」できます(ofc例外は言及されています)。

システム化されたLinuxでは、systemdはこれらのcgroup属性を「巧妙に使用」(またはむしろ乱用)し、特定のプロセスの「オブジェクト」が開始されたコンテキスト(たとえば、「マシン」(コンテナ)、サービス、セッション、またはユーザーが所有するもの)を追跡します。 cgroupは入れ子にすることができるので、根本的な神経自閉症の患者は機械、スライス、スコープ...バズーカポのような達成可能なプロセス分類の無限の官僚的な可能性について興奮しています。もちろん、あなたは自己主張が強いので、これについて話すことはできません。

簡略化:systemdがcgroup(これからCG)をプロセスに割り当てると、プロセスは中断されます。

このようにして、数十年ぶりに(つまり、9年前から)私たちは「誰が」実際に特定のプロセスを作成したのかを確実に知ることができます。サービスだったのか、ログインセッションだったのか、エイリアンだったのか…?

systemd-cglssystemctl status呼び出しを介して(または「最近の」Linuxで)システムのCGレイアウトを表示できます。 CGがsystemdシステム内にどのように入れ子になっているかを直接目で確認することができます(tssshは誰にも話しませんが、実際には実際の擬似ファイルシステムオブジェクトであるこれらのGS、つまりファイルとディレクトリはどこかにあります)。

したがって、systemdは最初にプロセス(実際の)機械母集団をいわゆるsystem.slice(単にCG名)で割りますuser.slicesystem.sliceこれは実行中の各サービスごとに1つずつ無制限のCGに細分化されるため、等という名前のCGが得られcrond.serviceますsshd.service。 。

これは実際に非常に素晴らしい機能です。サービスの基本プロセス(「デーモン」)が突然終了したとしても、それが生成するすべての不都合なプロセスを識別する方法をまだ知っているからです。すべての子プロセスは同じCG、すなわちsomething.service

このアルゴリズムを使用すると、systemdはサービス停止イベントでサービスが生成できるすべてをプロセスごとに終了できます。

しかし、user.slice状況はさらに複雑です。ランダムに分割するのではなく、ログインした各ローカルuser.sliceユーザーに基づいて分割します(つまり、各ユーザーアカウントは、そのユーザーが最初にログインしたときにインスタンス化されるuser.sliceを独自に取得します)。

確かに、これはシステムが特定のユーザーに対するすべてのプロセス(ユーザースライスあたり)のメモリ消費を制限できるため、非常に賢いです。どこかで一部のシステムノブを操作して、この場合は興味がありません。 。

とにかく、インタラクティブにログインしたユーザーのシステムデザイナーの見解では、これらの粒度は依然として粗雑です。

したがって、systemdはよりユニークなデザインソリューションを採用しています。つまり、特定のユーザーの各user.sliceは、いわゆるCGという小さなCGに分割されますsession.scope。 session.scopeは、対話型ユーザーがログインセッションを作成するたびに作成されます。

ここに問題があります。問題は、これらの対話型CGが無差別に動作することです。

セッションスコープの場合、systemd はサービスと同じ終了ロジックを適用します。ユーザーがログアウトすると、バックグラウンドで何も実行する権限がありません(すでに頑固だと言いましたか?)。 10年以上前(systemdが存在する前に)使用されていたスクリーンとtmuxをネジで固定してください。

これで、インタラクティブセッションによって生成されたバックグラウンドプロセスを実行することを許可するのか、それともすべて終了するのかなど、正しい解決策である無限の議論を行うことができます。まあ、少なくとも私の考えでは、正しい解決策は状況によって異なります。

通常のユーザープロセスを終了することをお勧めします。マルチユーザーシステムがあり、ユーザーが「一般」人の場合は、最後にログアウトしたときに残ったすべてのジャンクを定期的にクリーンアップします。ただし、tmuxに長期間実行されるバックグラウンドジョブ(ワンショットバックアップ)が必要です。

幸いにも方法がありますが、次は嫌悪です。

KillUserProcesses=yes
KillExcludeUsers=yourusername

なぜ?

どちらも核オプションです(すべてまたは専務)。 1つ目は、すべてのユーザーが残りのゴミでマシンを占有することを許可し(悪い)、2つ目は特定のユーザーが残りのゴミでマシンを占有できるようにします(悪い)。設定可能なクリーンアップを無効にしたい場合は、なぜ面倒になるのですか?

より「正しい」解決策は両方とも最高です。デフォルトでは、systemdに対話的に生成されたプロセスをクリーンアップさせ、tmuxを実際のsystemdサービスとして使用します。これにより、ログアウト時にジョブを自動的にクリーンアップできますが、長期実行プロセスへのアクセスはまだ維持されます。この機能はtmuxにあります。

ソケットを介して交換されたデータが「体系化された」CG境界を超える可能性があることがわかります。httpd.serviceプロセスからプロセスソケットに接続できますsession-yourblabla.scope

これは、端末からログアウトしても終了しない適切なtmuxified "バックグラウンド"を持つ方法です。 tmux「レンダラー」(ログインセッションで)とtmux「サーバー」(systemdサービス)との間のtmux通信は、systemdのCG境界を越えるUnixソケットを通って自然に流れます。

この目標を達成する方法は?

まあ、これは過去にいくつかの問題でした。 screen と tmux はどちらも、システムごみが存在する前に設計されているためです。

これが現在自動殺人が起こる理由でもある。

screenとtmuxの両方が最初のtmuxコマンドを呼び出すときにマルチプレクサデーモンが自動的に起動されるようにする素晴らしい機能を持っています。これはsystemdが登場するまで何十年もうまくいきました(誰もログインセッション内のプロセスについて考えていなかったため)。

これから私たちはtmuxソリューションに集中します。なぜなら、スクリーンはスパゲッティコーディングのおもちゃにすぎず、必要なtmux機能が不足している可能性があるからです。

システム化されたシステムでは、端末のtmuxが実際のtmuxセッションを維持するためにtmuxサーバーデーモンを自動的に作成するとき、指定されたサーバーデーモンはすでに説明されているセッションへのCG継承のために(session-xxを継承するため)、ログインに属するものとしてマークされます。 .scope CG).私たちが知っているように、プロセスはsystemdがなければCGを変更することはできません。

したがって、対話型ログアウト時間が来ると、指定されたログインセッションに属するすべてのプロセスは、systemdのクリーンアップアルゴリズムによって完全に独立したtmuxサーバーデーモン(CGタグがまだそのセッションに接続されているため)まで終了します。

この点でjsbillings @の答えはやや正確です。自動セッションCGタグキラーで生き残ることはできませんが(もちろん、システムレベルで無効にしない限り)、tmuxサーバーがログインセッションで作成された場合にのみ適用されます。 。したがって、独自のシステムCGで作成されたスタンドアロンのtmuxサーバーはログインセッションから独立しているため、クリーンアップの影響を受けません。

私たちが言ったように、私たちはキラーをそのままにしたかったのです。これは、マシンのユーザープロセスをスクリーニングするのに役立ちます。

user.sliceまあ、正しい解決策はtmuxサーバーデーモンsession.scope自体です[email protected]

私たちがすでに学んだように、サービスはログインセッションにバインドされず、最終的にはシステムサービスであるため、システムログインセッションの終了の影響を受けません。

残念ながら、最近のtmux(3.2a以降)を実行していない限り、これはそれほど簡単ではありません。 (常に行うことができます。私を信じてください。しかし、いくつかの考えが必要です。しかし、これはすでに非常に長い応答範囲を超えています。)。

一方、tmuxバージョン3.2a以降、systemdを使用すると、ハッキングなしで非常に安定して動作すると言えます。

tmuxバージョン以前は、「tmuxセッション(!)」がないと、tmux(および画面)の他の機能に問題がありました(つまり、tmux内の端末+ bashシェルプロセスとして、これはシステムログインとは関係ありません)。特定のユーザーに関連付けられたセッション)。

したがって、以前のtmuxを使用すると、一部の変更なしでサービスでデーモンを起動してもすぐにシャットダウンされ、systemd tmuxユーザーサービスが役に立たなくなります。

最後に、最新のLinuxとtmuxを使用してこれを達成するために必要な魔法のステップは何ですか?

  1. 自動起動機能(子孫であるため、実際のデーモンを生成します)を使用する代わりに、サーバーモードで直接、つまりフォアグラウンド「デーモン」でtmuxサーバーを起動する必要があります。
  2. 同時に、tmuxサーバーの「tmuxセッションがないときに自動シャットダウン」機能を無効にする必要があります。それ以外の場合、フォアグラウンドモードでもサーバーはすぐにシャットダウンされます。幸い、最新バージョンのtmuxでは、手順1でもこの問題を自動的に処理します。
  3. その後、この設定をシステム全体のtmuxユーザーサーバーサービスとして構成する必要があります。
  4. システムレベルのtmuxユーザーサーバーサービスが開始されると、そのtmuxユーザーサーバーサービスCG内で長期実行のtmuxセッションを開始できます。マシンからログオフした後も、systemdはそのtmuxセッションをその場所で無期限の実行状態に保ちます。

1.と2.の場合は、新しいtmux-Dフラグを参照してください。 3. 以下は非常に基本的なレシピです。

# cat /etc/systemd/system/tmux-myuser.service
[Unit]
Description=Permanent tmux server for myuser user
 
[Service]
Type=exec
User=myuser
Group=myuser
ExecStart=/usr/bin/tmux -D
 
[Install]
WantedBy=multi-user.target

サービスを作成して開始します。呼び出し後、systemd statustmuxサーバーが「デーモン」またはむしろsystemdサービスとして実行されていることがわかります。同じユーザーの他のログインシェルでtmuxコマンドを実行すると、tmux-myuser.service cgroup内にプロセスツリーが作成されます(systemctlステータスを再確認してください)。

起動して気に入ったら、@systemd変数などを使用してtmuxユーザーサービスを自動生成ユーザーサービスに調整できます。

実際、このソリューションはサーバーモードで管理された状態で実行でき、それをスタンドアロンsystemdサービスにカプセル化する限り、すべてのターミナルマルチプレクサに適用できます。

nohupと比較してこのソリューションの利点は何ですか?

nohupに比べて利点がたくさんあります。

最初はnohupが何をしているのかわからないかもしれませんが、この魔法は従来のUNIXパラダイム(各プロセスが元のコンテキストトレース終了なしで実行され続ける場合)が維持されている場合にのみ機能します。 Linuxでは、このパラダイムは9年以上機能しませんでした。体系的なtmuxサービスは、このような状況を完全に防止します。

第二に、nohuppedプロセス出力ストリームと完全なプロセス制御にアクセスすることはできません。 Nohupを使用すると、プロセス出力を「ログファイル」に「リダイレクトする」ことができますが、実際には標準出力記述子を変換するだけですが、これは最適です(観察、回転など)。これを適切に行うには多くの計画が必要ですが、それでも非常に脆弱です。

基本的なプロセス制御は永久に失われます。元の生成シェルが消えた後にnohuppedプロセスを制御する唯一の方法は、PIDとシグナルを介してです。他のシェルはnohuppedプロセスのプロセスグループを覚えておらず、jobsコマンドで選択または表示できません。

tmuxでこのようなバックグラウンドタスクを実行すると、これらすべてのタスクが自動的に処理され、いくつかの非常に強力な利点も提供されます。

  1. tmux "ログバッファ"をファイルに保存できます(つまり、要求に応じて必要なものだけを記録します)。
  2. さらに重要なのは、tmuxバックエンドを使用すると、必要に応じてバックエンドプロセスに入力を渡すことができることです(パスワードを入力することもできます)。
  3. 正しいバックグラウンドtmuxサービスを事前に実行すると、後で予期しないバックアップ、大容量ファイル転送、一時デーモンなどのバックグラウンドタスクを無制限に作成できます。
  4. 名前付きtmuxセッションで実行することで、予期しない複数のバックグラウンドジョブコンテキストを設定できます。 tmux セッションの複数のウィンドウを使用して、共同プロセスグループを実行することもできます。さらに、tmuxウィンドウレイアウトは、重要性、内部依存性、または階層を効果的に表現することができます。

ご覧のとおり、多重化によりシステムサービスで多くの利点を得ることができます。

関連情報