TL;DR — VM 2대가 동시에 재부팅된 후 WildFly 도메인 컨트롤러가 자동 기동되지 않았다. 증상은 슬레이브 서버의 반복 종료였지만, 근본 원인은 systemd unit 파일의
WantedBy를wantedBy로 쓴 오타 한 글자였다. 원인 추적부터 복구까지 약 40분. 이 글은 그 40분의 기록과, 거기서 건진 교훈에 대한 이야기다.
배경: WildFly Domain Mode
담당하는 인증 서비스의 개발 환경은 WildFly를 도메인 모드로 운영한다. 서버는 두 대다.
- 도메인 컨트롤러(마스터,
10.0.0.10) — 원본 WAR 배포본과 서버 그룹 설정을 보관하고, 슬레이브에 설정을 배포한다. 관리 포트는9990. - 호스트 컨트롤러(슬레이브,
10.0.0.11) — 마스터로부터 설정과 WAR를 받아 실제 서비스 JVM 인스턴스를 기동한다. 실제 코드가 돌아가는 서버다.
여러 모듈의 JVM 인스턴스를 서버 그룹 단위로 묶어 관리할 수 있다는 게 도메인 모드의 장점이지만, 뒤집어 말하면 마스터가 죽으면 슬레이브는 기동조차 못 하는 구조다. 이 사실이 이번 장애의 복선이 된다.
장애: 표준창이 열리지 않는다
어느 오후, 개발망의 인증 표준창이 HTTP 503을 반환하기 시작했다. 슬레이브 서버에 들어가 보니 이상한 패턴이 보였다. WildFly 프로세스가 기동되고 약 33초 만에 종료되기를 반복하고 있었다. 재시작해도 똑같았다.
먼저 서버에 무슨 일이 있었는지부터 확인했다.
last -x reboot shutdown | head -5
reboot system boot 3.10.0-1160.el7. Wed ... 15:16
reboot system boot 3.10.0-1160.el7. (약 4개월 전)
reboot system boot 3.10.0-1160.el7. (약 9개월 전)
마스터와 슬레이브 두 VM이 같은 시각에 재부팅되어 있었다. 재부팅 이력을 거슬러 올라가 보니 수개월 간격으로 같은 패턴이 반복된 흔적도 있었다. 즉, 이건 오늘 처음 생긴 문제가 아니라 재부팅될 때마다 터질 수 있는 문제가 잠복해 있다가 이번에 드러난 것이었다.
추적: 증상이 있는 곳에 원인이 있는 건 아니다
반복 종료하는 건 슬레이브니까 처음엔 슬레이브 설정을 의심했다. 그런데 로그를 열어보니 이야기가 달랐다.
INFO [org.jboss.as.host.controller] WFLYHC0148: Connecting to master host controller remote://10.0.0.10:9990
ERROR [org.jboss.as.host.controller] (Controller Boot Thread) WFLYHC0052: Could not connect to master. Aborting.
Error was: java.net.ConnectException: WFLYPRT0053: Could not connect to remote://10.0.0.10:9990. The connection failed
INFO [org.jboss.as.process] WFLYPC0009: Process terminated, exit code 99
슬레이브는 자기 잘못으로 죽는 게 아니었다. 마스터에 연결이 안 돼서 30초 동안 11회 재시도한 뒤 스스로 종료(exit code 99)하고 있었다. 아까 관찰한 "33초 만에 종료"는 재시도 30초 + 종료 처리 3초였던 것이다.
시선을 마스터로 옮겼다. 혹시 네트워크 문제인가 싶어 슬레이브에서 확인해 보았다.
timeout 3 bash -c 'echo > /dev/tcp/10.0.0.10/9990' && echo OPEN || echo CLOSED
# → CLOSED (connection refused)
ping -c 2 10.0.0.10
# → 정상 응답
ping은 되는데 포트는 refused. 즉 장비는 살아 있고 WildFly 프로세스만 안 떠 있는 상태다. 네트워크 단절 가설은 여기서 배제됐다. 재부팅 후 슬레이브는 자동 기동됐는데 왜 마스터는 안 떴을까?
근본 원인: 대문자 W 한 글자
마스터의 systemd 설정을 확인했다.
systemctl is-enabled wildfly
# → static
grep -i wantedby /etc/systemd/system/wildfly.service
# → wantedBy=multi-user.target
WantedBy가 아니라 wantedBy. 소문자 w 하나가 문제의 전부였다.
systemd는 unit 파일의 키 이름을 대소문자까지 정확히 구분한다. 그리고 모르는 키는 에러를 내는 대신 조용히 무시한다. [Install] 섹션에 유효한 WantedBy가 없으니 systemctl enable을 해도 multi-user.target 아래에 심볼릭 링크가 생기지 않고, 상태는 static으로 표시되며, 부팅 시 자동 시작 대상에서 조용히 빠진다.
무서운 건 이 오타가 평소엔 아무 증상도 만들지 않는다는 점이다. 수동으로 systemctl start를 하면 멀셟하게 잘 뚜다. 재부팅이라는 조건이 충족될 때만 발현되는 잠복 결함이었고, 그래서 수개월 간 아무도 모르고 있었다.
복구: 순서가 전부다
복구 자체는 단순하다. 다만 도메인 모드에서는 기동 순서가 중요하다. 마스터가 없는 채로 슬레이브를 먼저 올리면 33초 뒤 또 죽는다.
- 마스터 기동 → 관리 포트 9990이 열릴 때까지 대기 (실측 약 20~30초)
- 슬레이브 기동
- 서비스 JVM 인스턴스 기동 확인
여기서 한 가지를 덩붙였다. 슬레이브 기동이 성공했는지를 언제 판단할 수 있을까? 연결 실패 시 33초 만에 종료된다는 실측치가 있으니, 여유를 더해 "기동 후 40초가 지나도 active (running)이면 성공"이라는 판정 기준을 런북에 명시했다. "좀 기다려보고 괜찮으면 된 거에요" 같은 감으로는 다음 사람이 복구할 수 없다. 런북의 판정 기준은 숫자여야 한다.
장애 인지부터 서비스 정상화까지 약 40분이 걸렸다.
남은 숙제
- 오타 수정 — unit 파일 수정 권한이 운영 주체와 분리되어 있어 담당 부서에 수정을 요청한 상태다. 수정 전까지는 재부팅 시 동일 장애가 재발한다. 그래서 런북이 더 중요해졌다.
- VM 2대 동시 재부팅의 원인 — 수개월 간격으로 반복된 패턴이라 하이퍼바이저나 전원 이벤트 쪽을 의심하고 있지만 아직 확인되지 않았다.
- 헬스체크 알림 — 이번에는 사용자가 503을 보고 나서야 인지했다. 관리 포트 헬스체크 기반 알림을 붙이면 재부팅 직후 미기동을 먼저 탐지할 수 있다.
배운 것
- 증상이 보이는 서버가 범인이 아닐 수 있다. 반복 종료는 슬레이브에서 일어났지만 원인은 마스터에 있었다. 분산 구조에서는 "이 서버가 의존하는 것"까지 의심 범위에 넣어야 한다.
- 조용히 실패하는 설정이 제일 무석다. systemd는 모르는 키를 에러 없이 무시한다. 설정이 "적용된 것 같은 상태"와 "실제 적용된 상태"는 다르다.
systemctl is-enabled같은 명령으로 적용 상태를 검증하는 습관이 필요하다. - 재부팅은 가장 싸고 확실한 카오스 테스트다. 재부팅 후 서비스가 스스로 돌아오는지는 평소엔 절대 검증되지 않는 경로다. 이번 잠복 결함은 그 경로에 수개월간 숨어 있었다.
본 글의 IP·시각 등은 예시로 대체하였습니다.






























