systemd 서비스 재시작 정책, Restart=always만 넣지 않고 장애 원인을 나누는 법

라벨과 로고가 없는 소형 서버와 유선 네트워크 케이블, 옆에 열린 터미널 작업 화면이 놓인 작업대

AI를 활용하여 생성한 이미지입니다.

systemd 서비스가 몇 초마다 다시 살아나는 모습은 겉으로 보면 정상 복구처럼 보여요. 하지만 재시작이 반복되면 원인은 가려지고, 로그가 빠르게 밀리며, 의존 서비스까지 연쇄적으로 흔들릴 수 있습니다. Restart=always를 넣는 것만으로 끝내면 안 되는 이유예요. 서비스가 왜 종료됐는지, systemd가 재시작을 시도했는지, 재시작 제한에 걸렸는지를 따로 봐야 합니다.[1][2]

재시작은 복구이고, 원인 해결은 아니에요

Restart=는 프로세스가 끝난 뒤 systemd가 어떤 조건에서 다시 시작할지를 정하는 옵션이에요. 예를 들어 일시적인 네트워크 실패나 외부 API 지연에는 재시작이 도움이 될 수 있어요. 반면 잘못된 설정 파일, 만료된 인증서, 권한 오류처럼 같은 원인이 계속 남아 있으면 재시작은 같은 실패를 반복할 뿐입니다.[1]

관찰한 현상 먼저 의심할 층 다음 확인
프로세스가 종료되고 곧바로 다시 시작돼요. 서비스 종료 코드와 Restart 정책 systemctl status와 최근 journal
잠시 반복되다가 시작이 막혀요. StartLimit 제한 서비스 이벤트 간격과 제한 메시지
서비스는 살아 있지만 요청이 실패해요. 애플리케이션·의존성·네트워크 서비스 외부 로그와 포트·DNS

중요한 점은 “서비스가 active인가”와 “업무가 정상인가”가 같은 질문이 아니라는 거예요. 프로세스가 살아 있어도 포트를 열지 못했거나, 인증서 오류로 upstream에 접근하지 못하거나, 내부 큐가 멈췄을 수 있어요.

Restart 옵션을 업무 조건에 맞춰요

Restart=on-failure는 비정상 종료를 재시작 대상으로 삼는 대표적인 선택이에요. 일회성 작업이나 관리 명령처럼 정상 종료가 곧 작업 완료인 서비스에는 always가 재실행 폭주를 만들 수 있어요. 반대로 계속 떠 있어야 하는 데몬이라면 비정상 종료를 다시 올리되, 사람이 확인해야 하는 설정 오류까지 무한히 덮지 않도록 재시작 간격과 제한을 같이 정해야 합니다.[1]

RestartSec=는 실패 직후 바로 다시 띄우지 않고 잠시 기다리게 해요. 외부 저장소나 네트워크가 잠깐 흔들리는 서비스에는 완충 시간이 될 수 있습니다. 다만 기다리는 동안 서비스가 필요한 요청을 처리하지 못하므로 짧게만 잡는다고 무조건 좋은 것도 아니에요. 시작 작업이 오래 걸리는 프로그램이라면 “시작 실패”를 재시작으로 착각하지 않도록 Type=, ExecStart=, 준비 완료 신호도 함께 확인하세요.[1]

StartLimit에 걸렸을 때의 해석

재시작 제한은 서비스가 짧은 시간에 너무 많이 시작되는 상황을 막는 안전장치예요. 제한에 도달하면 systemd는 계속 재시작하지 않고 시작 요청을 거절할 수 있어요. 이 상태에서 무작정 systemctl reset-failed만 실행하면 잠시 다시 움직일 뿐, 원인은 남아 있습니다.[2]

먼저 아래처럼 상태와 로그를 저장해요. 명령은 상태를 바꾸지 않는 읽기 중심 점검입니다.

systemctl status example.service --no-pager
systemctl show example.service -p Restart -p RestartUSec -p StartLimitBurst -p StartLimitIntervalUSec
journalctl -u example.service -b --no-pager -n 200
systemctl cat example.service

배포판과 systemd 버전에 따라 표시되는 속성 이름이나 기본값이 달라질 수 있어요. 화면에 값이 없다고 해서 제한이 없다고 단정하지 말고, 실제 실패 시각과 재시작 시각을 journal에서 비교하세요. 최근 설정을 drop-in으로 덮어쓴 경우에는 원본 unit 파일만 열어봐서는 최종 구성을 알 수 없습니다. systemctl cat으로 vendor 파일과 drop-in을 함께 보는 편이 안전해요.[2]

로그는 “마지막 오류 한 줄”보다 앞뒤를 봐요

서비스가 실패한 직후의 한 줄만 복사하면 원인과 결과를 뒤집기 쉬워요. 시작 직전 환경 변수, 권한 변경, 포트 점유, 의존 서비스 상태가 먼저 나왔는지 함께 확인해야 합니다. 다음 순서로 범위를 좁혀 보세요.

  1. 실패한 서비스의 최근 부팅 이후 로그와 종료 코드를 저장해요.
  2. 실패 시각 전후로 journalctl -u와 시스템 로그를 함께 봐요.
  3. ExecStart가 실행되는 사용자, 작업 디렉터리, 환경 파일을 확인해요.
  4. 서비스가 기다리는 소켓·포트·마운트·DNS·인증서의 상태를 별도로 검사해요.
  5. 원인을 고친 뒤에만 제한을 초기화하고 한 번 수동 시작해요.

여기서 서비스 파일에 비밀번호나 API 키를 직접 넣는 방식은 피하는 게 좋아요. 값이 journal이나 진단 출력에 노출될 수 있고, 설정을 읽을 권한을 가진 사용자에게 그대로 보일 수 있습니다.

drop-in과 실행 환경을 나눠서 확인해요

운영 중인 unit을 직접 수정하기보다 /etc/systemd/system/example.service.d/override.conf 같은 drop-in으로 변경을 분리하면 되돌리기 쉽습니다. 수정 후에는 systemctl daemon-reload이 필요하지만, reload가 성공했다고 서비스의 새 설정이 정상이라는 뜻은 아니에요. 다음 시작에서 실제 환경 변수와 권한이 맞는지 확인해야 합니다.

서비스가 파일 시스템에 접근하는 범위나 권한을 줄이는 설정도 장애 원인이 될 수 있어요. ProtectSystem=, 경로 접근 제한, 사용자·그룹 지정은 보안을 높일 수 있지만 애플리케이션이 필요한 파일을 읽지 못하게 만들 수 있습니다. 이런 옵션은 한꺼번에 켜지 말고 한 항목씩 적용한 뒤 로그를 확인하세요.[3]

안전한 복구 순서

  • 현재 unit 파일, drop-in, 상태 출력, 최근 로그를 별도 파일로 보관해요.
  • 외부 요청을 받는 서비스라면 재시작 횟수와 영향 범위를 먼저 확인해요.
  • 설정·권한·포트·의존 서비스 중 하나씩만 바꾸고 수동 시작 결과를 기록해요.
  • 정상 응답과 journal 오류가 함께 사라졌을 때 자동 재시작을 다시 활성화해요.
  • 같은 장애가 반복되면 Restart 값을 더 강하게 만들기보다 알림과 원인 수집을 보강해요.

WSL2에서 systemd를 켠 뒤 서비스가 안 뜨는 경우에는 배포판 부팅 구조와 서비스 자체 설정을 먼저 분리하세요. WSL2 systemd 서비스 점검 글의 부팅·상태 확인 순서도 함께 참고하면 좋아요.

결론은 재시작 횟수가 아니에요

좋은 unit은 실패했을 때 다시 시작하는 것뿐 아니라, 실패 사실을 사람이 알아차리고 원인을 되돌릴 수 있게 만들어야 해요. Restart는 서비스 성격에 맞게 고르고, StartLimit는 반복 실패를 숨기지 않는 경계로 사용하세요. 마지막으로 설정 변경 전후의 로그와 실행 환경을 남겨 두면 같은 문제가 생겼을 때 복구 시간이 크게 줄어듭니다.

Sources

  1. [1] systemd.service | freedesktop.org
  2. [2] systemd.unit | freedesktop.org
  3. [3] systemd.exec | freedesktop.org

함께 읽을 글