조회수: 2
리눅스 서버를 운영하다 보면 서비스가 갑자기 죽고 systemctl status로 확인했을 때 Active failed 메시지를 마주치는 일이 자주 있다. 여기서 많은 사람이 status 출력만 대충 보고 재시작부터 시도하지만 이런 방식은 같은 장애를 반복해서 겪는 지름길이 된다.
systemd 환경에서 서비스가 실패 상태에 빠졌다면 가장 먼저 해야 할 일은 정확한 실패 지점을 로그로 확인하는 것이다. 단순히 에러 한 줄만 보는 것이 아니라
어떤 프로세스가
어느 시점에
무슨 이유로 종료됐는지
연속적인 흐름을 파악해야 한다.
이 글에서는 systemctl status로 실패를 확인한 뒤 journalctl과 여러 옵션을 조합해 로그를 보는 정확한 방법을 단계별로 정리한다. 실무에서 자주 쓰는 패턴 중심으로 설명하니 그대로 따라 하면서 자신만의 점검 루틴으로 만들면 도움이 될 것이다.
목차
Active failed가 의미하는 내용 이해하기
먼저 Active failed 상태가 정확히 어떤 상황을 말하는지 짚고 넘어가자. systemd에서 서비스는 크게 다음과 같은 상태를 가진다.
- active running
- active exited
- inactive
- failed
이 중 failed는 단순 종료와 다르다. 서비스가 시작 과정에서 비정상 종료됐거나 systemd가 정의한 조건을 만족하지 못했을 때 실패 상태로 표시된다. 즉 실패 상태는
- 프로세스가 시작 도중 오류 코드와 함께 끝났거나
- StartLimit 관련 정책에 걸렸거나
- 준비 단계에서 타임아웃이 발생했거나
같은 경우에 나타난다.
그래서 Active failed를 확인했다는 것은 이미 시스템이 문제라고 알려 준 것이고 이제 해야 할 일은 그 근거가 되는 로그를 정확한 순서대로 읽어 가는 일이다.
첫 단계 systemctl status에서 힌트 뽑아내기
systemctl status 서비스이름
을 실행하면 서비스의 전반적인 상태와 함께 최근 로그 일부를 보여 준다. 여기서 다음 네 가지를 집중해서 보는 편이 좋다.
1 서비스 상태 줄
Active failed 문구뿐 아니라 바로 옆에 나오는 since와 몇 초 전 혹은 몇 분 전이라는 시간 정보를 같이 본다. 언제부터 실패했는지 감이 잡힌다.
2 Process 관련 줄
메인 프로세스의 PID와 종료 코드가 간단히 표시되는데 종료 코드가 1인지 2인지 아니면 특정 신호로 죽었는지 파악할 수 있다.
3 Main PID가 있는지 여부
시작 직후 죽은 경우에는 PID가 잠깐 생겼다가 사라지기도 한다. 상태 출력의 Main PID 정보와 로그 시간을 연결해서 보면 도움이 된다.
4 하단의 최근 로그
status 출력 아래에 최근 몇 줄의 저널 로그가 함께 나오는데 여기에서 이미 에러 메시지가 보이는 경우가 많다. 다만 이 부분은 앞뒤 문맥이 잘려 있는 경우가 많기 때문에 참고용으로만 보고 바로 journalctl로 넘어가는 것이 좋다.
정리하면 systemctl status 단계에서는
언제부터 실패했는지
무슨 코드로 끝났는지
최근 로그에서 대략 어떤 에러였는지만
대강 감을 잡는 수준으로 이해하면 된다.
핵심 도구 journalctl로 해당 유닛 로그만 모아서 보기
실제 원인 분석은 journalctl 명령으로 한다. 가장 기본이 되는 패턴은 다음과 같다.
journalctl -u 서비스이름
이렇게 입력하면 해당 유닛에 속한 모든 로그가 시간순으로 출력된다. 여기서 중요한 점은 유닛 이름 전체를 정확히 사용하는 것이다. 예를 들어
- nginx가 아니라 nginx service
- myapp이 아니라 myapp service
이런 식으로 service 접미어까지 써 주는 것이 안전하다.
로그를 오래 쓰는 서버라면 이렇게만 실행했을 때 스크롤이 끝도 없이 길어질 수 있다. 그래서 실무에서는 보통 두 가지 옵션을 기본으로 더 붙인다.
journalctl -u 서비스이름 -n 100
journalctl -u 서비스이름 -f
첫 번째는 마지막 100줄만 보는 옵션이고 두 번째는 실시간으로 tail처럼 끝을 따라가며 보는 방식이다. 장애가 발생한 직후라면 먼저 n 옵션으로 최근 몇 줄을 훑어보고, 서비스를 재시작하면서 f 옵션으로 변화를 보는 식으로 조합하면 좋다.
실패한 마지막 부팅에서만 로그 보기
장기간 돌아간 서버에서는 예전 부팅에서 발생한 장애 로그까지 섞여 있을 수 있다. 이때는 현재 부팅 혹은 이전 부팅에서만 로그를 추려 보는 것이 유용하다.
대표적인 명령 패턴은 다음과 같다.
journalctl -u 서비스이름 -b
journalctl -u 서비스이름 -b -1
첫 명령은 현재 부팅 이후의 로그만 보여 주고 두 번째는 직전 부팅의 로그를 보여 준다. 만약 새 버전을 배포한 뒤 재부팅을 했고 그 이후로만 문제가 있다면 b 옵션을 함께 사용하는 것이 훨씬 분석하기 편하다.
Active failed가 된 직후 시간대만 집중해서 보는 방법
status 출력에서 since 정보와 failed로 바뀐 시간을 확인했다면 그 근처 시간대만 좁혀서 보는 것이 효율적이다. journalctl에서는 시간 범위를 지정하는 옵션을 제공하는데 많이 사용하는 예시는 아래와 같다.
journalctl -u 서비스이름 --since "10 min ago"
journalctl -u 서비스이름 --since "2025-11-24 10:00" --until "2025-11-24 10:10"
첫 줄은 최근 10분 동안의 로그만 보여 주고, 두 번째는 특정 날짜와 시간 범위로 딱 잘라서 로그를 확인할 수 있게 해 준다. Active failed가 표시된 시간이 대략 10시 03분 정도였다면 그 전후 5분 정도를 기준으로 범위를 잡으면 대부분의 원인을 찾을 수 있다.
ExecStart와 실제 실행 명령을 연결해서 해석하기
서비스가 실패할 때는 실제로 실행되는 명령이 어떤 것인지도 중요하다. 특히 자체 개발한 애플리케이션이나 스크립트를 서비스로 등록한 경우라면 유닛 파일의 ExecStart 라인을 반드시 확인해야 한다.
유닛 파일 내용은 다음과 같이 확인할 수 있다.
systemctl cat 서비스이름
이 명령은 기본 유닛 파일과 drop in 설정이 모두 포함된 최종 내용을 보여 준다. 여기에서 ExecStart에 어떤 명령이 정의돼 있는지 확인하고 journalctl 로그에 나오는 에러 메시지를 함께 보는 방식으로 분석한다.
예를 들어 ExecStart에 가상환경의 파이썬 경로가 들어 있는데 해당 경로가 존재하지 않는다면 로그에는 no such file 혹은 permission denied 같은 메시지가 남는다. 서비스 정의와 실제 파일 시스템 상태를 함께 보는 습관을 들이면 원인을 찾는 속도가 훨씬 빨라진다.
자주 나오는 실패 패턴과 로그 읽는 요령
Active failed 상태에서 특히 자주 마주치는 실패 패턴 몇 가지와 로그를 읽을 때의 포인트를 정리해 보자.
첫째 포트 바인딩 실패
웹 서버나 애플리케이션 서버에서 이미 사용 중인 포트에 바인딩하려 할 때 발생한다. 로그에는 address already in use 같은 문구가 보이는 경우가 많다. 이때는
- 동일 포트를 쓰는 기존 프로세스가 있는지
- 이전 인스턴스가 제대로 종료됐는지
를 함께 확인한다.
둘째 권한 문제
실행 파일 혹은 설정 파일에 대한 권한이 부족할 때는 permission denied 메시지가 남는다. 서비스가 특정 사용자 계정으로 실행되도록 설정되어 있다면 해당 계정 기준으로 파일 접근 권한을 다시 확인해야 한다.
셋째 환경변수 누락
유닛 파일에서 Environment 옵션이나 EnvironmentFile을 사용했는데 실제 파일 경로나 변수 값이 틀린 경우다. 로그에는 종종 구성 파일을 찾지 못했다거나 데이터베이스 연결에 실패했다는 메시지가 남는다. 이 경우 systemctl show 서비스이름 명령으로 환경 관련 설정을 함께 확인해 보면 좋다.
넷째 초기화 시간 초과
서비스가 준비 완료 신호를 보내기 전에 너무 오래 걸리면 systemd에서 타임아웃으로 판단하고 프로세스를 종료시킬 수 있다. 로그에는 start operation timed out 같은 문구가 남고 status에는 start job이 일정 시간을 초과했다는 표시가 함께 보이는 경우가 많다. 이때는
- 실제 애플리케이션 초기화 시간이 얼마나 걸리는지
- 유닛 파일에서 TimeoutStartSec 값을 늘려야 하는지
를 함께 검토해야 한다.
서비스 재시작과 로그 추적을 함께 묶는 절차 만들기
실무에서는 보통 장애가 발생하면 재시작부터 하고 보는 경우가 많지만, 재시작 전에 최소한 다음 절차만은 지키는 것이 좋다.
1 systemctl status로 실패 상태와 대략적인 발생 시간을 확인한다
2 journalctl -u 서비스이름 -n 50으로 바로 직전 로그를 훑어 대략적인 실패 원인을 추정한다
3 필요하다면 시간 범위를 줄여서 해당 시점의 전체 로그를 다시 본다
4 ExecStart와 환경 설정을 검토해 실제 실행 명령과 로그 메시지를 연결해 본다
5 원인을 어느 정도 짐작한 뒤에 systemctl restart로 재시작하고 journalctl -u 서비스이름 -f로 실시간 로그를 보며 정상 기동 여부를 확인한다
이 과정을 습관처럼 반복하다 보면 비슷한 종류의 장애가 재발했을 때 매우 빠르게 진단할 수 있게 된다.
정리 Active failed일 때 가장 중요한 한 가지
결국 systemctl status에서 Active failed 상태를 봤을 때 가장 중요한 한 가지는 status 출력만 보고 판단하지 말고 반드시 journalctl로 해당 유닛의 전체 로그를 시간 흐름대로 확인하라는 것이다.
서비스 장애는 대부분 로그 안에 단서를 남긴다. 성공적으로 기동된 경우의 로그 흐름과 실패했을 때의 흐름을 비교해 보면 어느 지점에서 비정상 행동이 시작됐는지 자연스럽게 눈에 들어온다. 이 글에서 정리한 기본 명령 패턴과 절차를 자신의 서버 환경에 맞게 조금씩 응용해 두면, 이후 비슷한 상황에서도 당황하지 않고 차분히 원인을 추적해 나갈 수 있을 것이다.