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가 이를 처리합니다.

정리 메커니즘을 비활성화하여 시스템 수준에서 이 문제를 해결하는 대신 일부 터미널 멀티플렉서(예 tmux: screen등 )를 사용하여 이 문제를 더 우아하게 해결할 수 있습니다.abduco

터미널 멀티플렉서는 로그아웃하더라도 계속 실행되는 분리된 세션을 생성할 수 있습니다. 나중에 세션에 다시 연결하여 내용을 조정할 수 있습니다.

jsbillings@의 의견 이후 편집:

내 초기 답변은 정확했지만 다소 간결해 보였기 때문에 귀하는 (아마도) 그 의미를 잊어버렸을 것이며 또한 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.slice. system.slice이는 실행 중인 각 서비스마다 하나씩 무제한의 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

왜?

둘 다 핵 옵션입니다(모두 아니면 전무). 첫 번째는 모든 사용자가 남은 쓰레기로 머신을 점유하도록 허용하고(좋지 않음), 두 번째는 특정 사용자가 남은 쓰레기로 머신을 점유하도록 허용합니다(또한 나쁨). 구성 가능한 정리를 비활성화하려는 경우 왜 귀찮게 해야 합니까?

보다 "올바른" 솔루션은 두 가지 모두에서 가장 좋은 것입니다. 기본적으로 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 솔루션에만 집중할 것입니다. 왜냐하면 screen은 단지 스파게티 코딩 장난감일 뿐이고 필요한 tmux 기능이 부족할 수도 있기 때문입니다.

체계화된 시스템에서 터미널의 tmux가 실제 tmux 세션을 유지하기 위해 tmux 서버 데몬을 자동으로 생성할 때, 지정된 서버 데몬은 이미 설명된 세션에 대한 CG 상속으로 인해(session-xx를 상속하기 때문에) 여전히 지정된 로그인에 속하는 것으로 표시됩니다. .scope CG). 우리가 알고 있듯이, 프로세스는 systemd 없이는 CG를 변경할 수 없으며, 게다가 systemd는 독단적이기 때문에 의도적으로 그렇게 하기 위한 도구를 제공하지 않습니다.

따라서 대화형 로그아웃 시간이 오면 지정된 로그인 세션에 속하는 모든 프로세스는 systemd의 정리 알고리즘으로 인해 완전히 독립적인 tmux 서버 데몬(CG 태그가 여전히 해당 세션에 연결되어 있기 때문에)까지 종료됩니다.

이 점에서 jsbillings@의 답변은 다소 정확합니다. 자동 세션 CG 태그 킬러에서 살아남을 수는 없지만(물론 시스템 수준에서 비활성화하지 않는 한) tmux 서버가 로그인 세션에서 생성된 경우에만 해당됩니다. . 따라서 자체 시스템 CG에 생성된 독립형 tmux 서버는 로그인 세션과 독립적이므로 정리의 영향을 받지 않습니다.

우리가 말했듯이, 우리는 Killer를 그대로 두기를 원했습니다. 왜냐하면 그것이 기계 사용자 프로세스를 선별하는 데 유용할 수 있기 때문입니다.

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 status이제 tmux 서버가 "데몬" 또는 오히려 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 창 레이아웃은 중요성이나 내부 종속성 또는 계층 구조를 효과적으로 표현할 수 있습니다.

보시다시피 다중화를 통해 시스템 서비스로 많은 이점을 얻을 수 있습니다.

관련 정보