본문 바로가기
TYLER SONGBlog
← Blog index
CS학습5 min read

kill: 프로세스에 시그널(Signal)을 보내는 명령어

kill은 이름과 달리 프로세스를 "죽이는" 명령이 아니라 지정한 프로세스에 시그널(Signal)을 보내는 명령이다. 기본 시그널은 SIGTERM(15)이며, 프로세스는 이를 받아 정리 작업 후 종료할 수 있다. SIGKILL(9)은 커널이 강제로 종료시키므로 최후의 수단으로 써야 한다. 시그널의 종류와 동작 방식을 이해하면 서버 프로세스를 안전하게 종료하

By 송민성

1. 개념

kill은 프로세스(process)에 시그널(signal)을 전달하는 명령어다. 시그널은 커널이나 다른 프로세스가 대상 프로세스에 보내는 짧은 비동기 알림이다. 이름 때문에 종료 명령으로 오해하기 쉽지만, 종료는 시그널이 수행하는 여러 동작 중 하나일 뿐이다.

shell
kill [-시그널] PID...

PID(Process ID)는 프로세스를 식별하는 정수다. 시그널을 생략하면 SIGTERM(15)이 전달된다.

2. 왜 사용하는가

  • 응답 없는 프로세스나 더 이상 필요 없는 프로세스를 종료한다.
  • 서버 데몬에 설정 다시 읽기(reload)를 요청한다. 예: SIGHUP
  • 프로세스를 일시 정지(SIGSTOP)하거나 재개(SIGCONT)한다.
  • 프로세스가 종료 전에 연결을 닫고 파일을 저장하도록 정상 종료(graceful shutdown)를 유도한다.

3. 동작 원리

kill 명령은 내부적으로 kill(2) 시스템 콜(system call)을 호출한다. 커널은 대상 프로세스에 시그널을 전달(pending 처리)하고, 대상 프로세스는 다음 중 하나로 반응한다.

  1. 기본 동작(default action): 종료, 무시, 코어 덤프, 정지 등 시그널별로 정해진 동작
  2. 핸들러(handler) 실행: 프로세스가 등록한 함수를 실행
  3. 무시(ignore): 시그널을 무시

단, SIGKILL(9)과 SIGSTOP은 핸들러 등록, 무시, 차단이 불가능하다. 그래서 SIGKILL은 프로세스가 정리 작업을 할 기회 없이 즉시 종료된다.

자주 쓰는 시그널은 다음과 같다.

번호이름의미
1SIGHUP터미널 끊김, 데몬은 설정 재로드 용도로 자주 사용
2SIGINT인터럽트(Ctrl+C)
9SIGKILL강제 종료, 잡거나 무시할 수 없음
15SIGTERM정상 종료 요청(기본값)
18SIGCONT정지된 프로세스 재개 (Linux x86 기준)
19SIGSTOP프로세스 정지, 잡거나 무시할 수 없음 (Linux x86 기준)

시그널 번호는 아키텍처에 따라 다를 수 있으므로, 번호보다 이름을 쓰는 편이 안전하다.

4. 코드 예제

먼저 SIGTERM을 받으면 정리 후 종료하는 TypeScript 서버를 만든다.

typescript
// server.ts import http from "node:http"; const server = http.createServer((_req, res) => { res.end("ok\n"); }); server.listen(3000, () => { console.log(`PID ${process.pid} listening on 3000`); }); process.on("SIGTERM", () => { console.log("SIGTERM 수신: 연결을 닫고 종료합니다"); server.close(() => process.exit(0)); }); process.on("SIGHUP", () => { console.log("SIGHUP 수신: 설정을 다시 읽습니다"); });

다른 터미널에서 시그널을 보낸다.

shell
# 프로세스 찾기 pgrep -f server.ts # 기본값(SIGTERM)으로 정상 종료 요청 kill 12345 # 이름으로 시그널 지정 kill -s HUP 12345 kill -SIGTERM 12345 # 시그널 목록 확인 kill -l # 프로세스 존재 여부와 권한 확인 (시그널 0은 실제로 전달하지 않음) kill -0 12345 && echo "살아 있음" # 정상 종료가 안 될 때만 최후의 수단 kill -9 12345

이름으로 여러 프로세스를 한 번에 대상으로 삼을 때는 pkill이나 killall을 쓴다.

shell
pkill -f server.ts killall node

5. 시간 복잡도 또는 성능 특성

kill 호출 자체는 시스템 콜 한 번으로 시그널을 대기열에 등록하는 가벼운 작업이다. 다만 시그널 전달은 비동기(asynchronous)이므로 kill이 반환되었다고 해서 대상 프로세스가 이미 종료된 것은 아니다. 종료 완료 여부는 kill -0 PID나 wait로 확인한다.

6. 실무 사용 사례

  • 배포 시 정상 종료: Kubernetes는 파드를 종료할 때 컨테이너 메인 프로세스에 SIGTERM을 보내고, 유예 시간(기본 30초) 후에도 살아 있으면 SIGKILL을 보낸다.
  • systemd: systemctl stop은 기본적으로 SIGTERM을 보내고, 제한 시간이 지나면 SIGKILL로 넘어간다.
  • 설정 리로드: nginx는 kill -HUP <master PID> 또는 nginx -s reload로 설정을 다시 읽는다.
  • 포트 점유 해결: lsof -i :3000으로 PID를 찾아 종료한다.

7. 주의할 점

  • SIGTERM 먼저, SIGKILL은 나중에: SIGKILL은 임시 파일 삭제, 트랜잭션 마무리, 연결 종료 같은 정리 과정을 건너뛰어 데이터 손상 위험이 있다.
  • 권한: 일반 사용자는 자신의 프로세스에만 시그널을 보낼 수 있다. 다른 사용자의 프로세스는 root 권한이 필요하다.
  • `kill -9 -1` 같은 명령 금지: PID에 -1을 주면 권한이 닿는 모든 프로세스에 시그널이 전달된다.
  • PID 재사용: 오래된 PID를 그대로 쓰면 이미 다른 프로세스가 같은 번호를 쓰고 있을 수 있다. 종료 직전에 ps나 pgrep으로 다시 확인한다.
  • 좀비 프로세스(zombie process): 이미 종료되어 부모의 wait를 기다리는 좀비는 kill로 제거되지 않는다. 부모 프로세스가 회수해야 한다.
  • `pkill`의 패턴 범위: pkill node처럼 넓은 패턴은 관련 없는 프로세스까지 종료할 수 있다. 먼저 pgrep -a로 대상을 확인한다.
  • 컨테이너의 PID 1: 컨테이너 안의 PID 1 프로세스는 핸들러를 등록하지 않은 시그널에 대해 기본 동작이 적용되지 않는다. 그래서 SIGTERM을 처리하는 코드를 직접 넣거나 init 프로세스를 사용해야 한다.

8. 핵심 정리

  • kill은 프로세스에 시그널을 보내는 명령이며, 기본 시그널은 SIGTERM(15)이다.
  • SIGTERM은 프로세스가 처리할 수 있어 정상 종료에 적합하고, SIGKILL(9)은 처리할 수 없어 즉시 강제 종료된다.
  • 종료 순서는 SIGTERM → 대기 → 필요할 때만 SIGKILL이 원칙이다.
  • 시그널 전달은 비동기이므로 종료 확인은 별도로 해야 한다.
  • 시그널은 번호보다 이름으로 지정하고, kill -0으로 생존 여부를 확인할 수 있다.