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]
로그는 “마지막 오류 한 줄”보다 앞뒤를 봐요
서비스가 실패한 직후의 한 줄만 복사하면 원인과 결과를 뒤집기 쉬워요. 시작 직전 환경 변수, 권한 변경, 포트 점유, 의존 서비스 상태가 먼저 나왔는지 함께 확인해야 합니다. 다음 순서로 범위를 좁혀 보세요.
- 실패한 서비스의 최근 부팅 이후 로그와 종료 코드를 저장해요.
- 실패 시각 전후로
journalctl -u와 시스템 로그를 함께 봐요. ExecStart가 실행되는 사용자, 작업 디렉터리, 환경 파일을 확인해요.- 서비스가 기다리는 소켓·포트·마운트·DNS·인증서의 상태를 별도로 검사해요.
- 원인을 고친 뒤에만 제한을 초기화하고 한 번 수동 시작해요.
여기서 서비스 파일에 비밀번호나 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는 반복 실패를 숨기지 않는 경계로 사용하세요. 마지막으로 설정 변경 전후의 로그와 실행 환경을 남겨 두면 같은 문제가 생겼을 때 복구 시간이 크게 줄어듭니다.