Linux 강좌 / 장애를 재현하고 증거로 복구하는 종합 실습
장애 복구 실습은 별도 환경에서 정상 상태를 먼저 검증한 뒤 원인 하나만 바꾸고, 관찰한 증거에 맞춰 복원하는 방식으로 진행합니다. 서비스 실행 상태와 실제 사용자 응답을 함께 확인해야 복구 완료를 판단할 수 있습니다.
실습 전에 VM 스냅샷과 콘솔 복구를 준비하고, 로그로 원인을 좁히는 절차에 따라 변경 전후의 증거를 비교하세요.
시스템 설정 실습의 기준은 Ubuntu 26.04 LTS와 Rocky Linux 9 계열의 일반 설치 VM입니다. 컨테이너·WSL·다른 릴리스에서는 서비스와 패키지 구성이 다를 수 있습니다. 가상 머신 실습 환경 만들기에서 콘솔 복구와 버전 확인을 먼저 준비하세요.
실습 범위와 정상 기준 준비하기
systemd 사용자 관리자, Python 3와 curl이 있는 Ubuntu·Rocky Linux 실습 VM을 사용합니다. 운영 Nginx·SSH·방화벽·디스크는 변경하지 않습니다. 루프백 18080 포트가 비어 있는지 ss -lnt로 확인하고, 이미 사용 중이라면 이 실습의 모든 포트 값을 다른 빈 번호로 바꿉니다.
아래 예제는 /usr/bin/python3을 사용하므로 먼저 command -v python3로 실제 경로를 확인합니다. 기존 linux-course-recovery.service나 ~/linux-recovery-lab이 있으면 덮어쓰지 말고 새 이름을 선택합니다. Python의 간이 HTTP 서버는 이 로컬 실습에만 사용하며 인터넷 운영 서버로 공개하지 않습니다.
mkdir -p "$HOME/linux-recovery-lab/site" "$HOME/.config/systemd/user"
printf "recovery baseline\n" > "$HOME/linux-recovery-lab/site/index.html"
cat > "$HOME/.config/systemd/user/linux-course-recovery.service" <<'EOF'
[Unit]
Description=Isolated Linux recovery lab
[Service]
Type=simple
WorkingDirectory=%h/linux-recovery-lab/site
ExecStart=/usr/bin/python3 -m http.server 18080 --bind 127.0.0.1
EOF
systemctl --user daemon-reload
systemctl --user start linux-course-recovery.service
systemctl --user is-active linux-course-recovery.service
curl --fail --max-time 5 http://127.0.0.1:18080/
cp "$HOME/.config/systemd/user/linux-course-recovery.service" "$HOME/linux-recovery-lab/service.good"
active와 recovery baseline 응답을 확인한 뒤에만 장애를 만듭니다. 정상 유닛 파일을 service.good에 저장했고 서비스는 enable하지 않았으므로 부팅 자동 시작도 추가하지 않았습니다. 정상 상태가 성립하지 않으면 먼저 Python 경로·유닛 구문·포트 충돌부터 해결하세요.
실험 1: 잘못된 실행 경로로 실패 재현하기
sed -i 's@ExecStart=/usr/bin/python3 @ExecStart=/nonexistent/course-python @' "$HOME/.config/systemd/user/linux-course-recovery.service"
systemctl --user daemon-reload
systemctl --user restart linux-course-recovery.service
systemctl --user status linux-course-recovery.service --no-pager
journalctl --user -u linux-course-recovery.service --since "5 minutes ago" --no-pager
유닛이 존재하지 않는 실행 파일을 가리키므로 활성 상태를 유지하지 못합니다. 시점에 따라 시작 명령이나 이후 status에서 실패를 확인할 수 있습니다. 저널에서 실행 실패와 203/EXEC 같은 상태를 찾아보고 실제 메시지를 기록합니다. 서비스 실패를 모두 네트워크 문제로 판단하지 마세요.
정상 설정을 복원하고 응답까지 재검증하기
cp "$HOME/linux-recovery-lab/service.good" "$HOME/.config/systemd/user/linux-course-recovery.service"
systemctl --user daemon-reload
systemctl --user reset-failed linux-course-recovery.service
systemctl --user start linux-course-recovery.service
systemctl --user is-active linux-course-recovery.service
curl --fail --max-time 5 http://127.0.0.1:18080/
정상 파일을 되돌리고 systemd가 다시 읽게 한 뒤 서비스를 시작합니다. reset-failed는 실패 기록과 시작 제한 카운터를 초기화할 수 있지만 잘못된 설정 자체를 고치는 명령은 아닙니다. 상태와 실제 페이지가 모두 돌아오면 이번 실험의 복구가 끝난 것입니다.
실험 2: 포트가 닫힌 경우와 HTTP 오류 비교하기
curl -i --max-time 5 http://127.0.0.1:18080/missing-resource
systemctl --user stop linux-course-recovery.service
curl -i --connect-timeout 2 --max-time 5 http://127.0.0.1:18080/
ss -lnt
systemctl --user start linux-course-recovery.service
curl --fail --max-time 5 http://127.0.0.1:18080/
첫 요청은 실행 중 서버가 없는 경로에 HTTP 404로 답하는 경우입니다. 서비스 중지 뒤 요청은 연결 거부 등 전송 단계 실패이며 정상 HTTP 404 응답과 다릅니다. curl에 --fail을 붙이지 않으면 404를 받아도 종료 상태 0일 수 있다는 점도 비교하세요. 원격 방화벽을 끄지 않고도 서비스·전송·HTTP 실패를 구분하는 연습입니다.
한 번에 한 조건만 바꾸고 기록하기
| 기록 항목 | 이 실습에서 남길 내용 |
|---|---|
| 정상 기준 | active·대기 포트·예상 페이지 |
| 변경 | ExecStart 경로 또는 서비스 정지 하나 |
| 증거 | 시각·종료 상태·저널·HTTP·소켓 |
| 복구 | 정상 파일 복원 또는 서비스 시작 |
| 재검증 | 동일 URL·포트·응답 본문 |
| 재발 방지 | 배포 전 구문·경로 검사와 상태 점검 |
디스크 가득 채우기, SSH 차단, 무작위 파일 삭제처럼 실제 복구 경로까지 잃을 수 있는 실험은 이 단계에서 하지 않습니다. 그런 실험은 별도 복제 VM·제한된 가상 디스크·검증된 콘솔과 백업이 있는 환경에서 범위를 정해 수행해야 합니다. 목적은 장애를 크게 만드는 것이 아니라 관찰에서 복구까지의 판단 과정을 익히는 것입니다.
실습 서비스를 중지하고 만든 파일만 정리하기
systemctl --user stop linux-course-recovery.service
systemctl --user reset-failed linux-course-recovery.service
rm -- "$HOME/.config/systemd/user/linux-course-recovery.service"
systemctl --user daemon-reload
ss -lnt
루프백 18080 대기가 사라졌는지 확인합니다. 작업 폴더에는 정상 설정 백업과 정적 파일만 남아 있으므로 내용을 검토한 뒤 파일 관리자로 정리할 수 있습니다. 실패 상태 정리도 해당 실습 유닛에만 적용하고 다른 사용자 서비스의 기록은 유지합니다.




