서비스가 failed 일 때 원인 찾기
systemctl status 의 Active·status 줄을 읽고, journalctl 로 실패 직전 로그를 보고, 203/EXEC 와 start request repeated too quickly 를 고칩니다.
서비스가 failed 가 되면 status → journalctl → systemctl cat 순서로 봅니다. 출력은 일시 유닛(systemd-run)을 일부러 실패시켜 얻은 실제 결과이고, 유닛 이름은 myapp, 경로는 /srv/app 로 바꿨습니다.
[1] systemctl status 로 어떻게 죽었는지 봅니다. Active: 는 상태와 이유(Result: exit-code), Process: 는 실행한 명령과 종료 코드(code=exited, status=3), Main PID: 는 마지막에 돈 프로세스입니다.
# systemctl status myapp --no-pager× myapp.service - /bin/sh -c "echo \"myapp: cannot open /srv/app/config.yml\" >&2; exit 3" Active: failed (Result: exit-code) since Mon 2026-10-19 12:16:54 KST; 1s ago Process: 47127 ExecStart=/bin/sh -c echo "myapp: cannot open /srv/app/config.yml" >&2; exit 3 (code=exited, status=3) Main PID: 47127 (code=exited, status=3)[2] 프로그램이 남긴 오류는 journalctl 에 있습니다. -u 유닛, -b 이번 부팅, -n 50 마지막 50줄, --no-pager 페이저 없이 출력합니다.
# journalctl -u myapp -b --no-pager -n 50Oct 19 12:16:54 server1 sh[47127]: myapp: cannot open /srv/app/config.ymlOct 19 12:16:54 server1 systemd[1]: myapp.service: Main process exited, code=exited, status=3/NOTIMPLEMENTEDOct 19 12:16:54 server1 systemd[1]: myapp.service: Failed with result 'exit-code'.sh[47127]: 줄이 프로그램이 직접 쓴 메시지, 곧 원인입니다.
[3] 실제로 적용된 유닛은 systemctl cat 으로 봅니다. 유닛 파일과 드롭인(myapp.service.d/)을 파일 경로와 함께 보여 줍니다.
# systemctl cat myapp --no-pager# /run/systemd/transient/myapp.service[Service]ExecStart=ExecStart="/bin/sh" "-c" "echo \"myapp: cannot open /srv/app/config.yml\" >&2; exit 3"[4] 흔한 원인은 status=203/EXEC 입니다. 매뉴얼(systemd.exec 의 Process Exit Codes)은 execve(2) 호출이 실패한 것이고 「대개 실행 파일이 없거나 접근할 수 없어서」라고 설명합니다. 아래는 파일은 있는데 첫 줄 인터프리터(#!/usr/bin/python4)가 없는 경우입니다.
# systemctl status myapp --no-pager Process: 47581 ExecStart=/srv/app/bin/myapp (code=exited, status=203/EXEC) Main PID: 47581 (code=exited, status=203/EXEC) # journalctl -u myapp -b --no-pager -n 50Oct 19 12:16:59 server1 (myapp)[47581]: myapp.service: Failed to execute /srv/app/bin/myapp: No such file or directory[5] 재시작을 켠 서비스가 계속 죽으면 start request repeated too quickly 로 멈춥니다. 아래는 Restart=always 에 10초 안에 3번만 시작하도록 제한한 유닛의 결과입니다.
# journalctl -u myapp -b --no-pager -n 4Oct 19 12:17:05 server1 systemd[1]: myapp.service: Scheduled restart job, restart counter is at 3.Oct 19 12:17:05 server1 systemd[1]: myapp.service: Start request repeated too quickly.Oct 19 12:17:05 server1 systemd[1]: Failed to start myapp.service - /bin/sh -c "echo \"myapp: bind: address already in use\" >&2; exit 1".이 줄은 결과일 뿐입니다. 원인은 로그 위쪽 프로그램이 쓴 줄(myapp: bind: address already in use)에 있습니다. 기본 한도는 StartLimitIntervalSec=10s · StartLimitBurst=5 이고, 넘으면 reset-failed 전에는 다시 시작되지 않습니다.
[6] 원인을 고칩니다. 유닛 파일을 바꿨다면 daemon-reload 로 다시 읽게 하고, reset-failed(failed 상태를 되돌립니다)로 실패 기록과 시작 횟수 제한을 지운 뒤 시작합니다.
[Unit]Description=myapp [Service]ExecStart=/srv/app/bin/myapp --config /srv/app/config.ymlRestart=on-failure [Install]WantedBy=multi-user.target# systemctl daemon-reload# systemctl reset-failed myapp# systemctl restart myappsyslog · journal 로그를 브라우저에서 바로 분석 ↗ — 아무것도 올라가지 않습니다.