Skip to content

서버 한 대짜리 개인 시스템의 자동 복구와 DOP-C02

시리즈: AWS 자격증, 실무로 되짚기

3 / 3편
  1. 11편 - Gen AI 자격증과 자작 RAG
  2. 22편 - 아키텍트 자격증과 Multi-AZ 운영
  3. 33편 - DevOps 자격증과 자동 복구지금 읽는 중
다른 시리즈 전체 보기 →
서버 한 대짜리 개인 시스템의 자동 복구와 DOP-C02
목차

예약해 둔 작업들이 밤새 돌고 몇 개는 조용히 실패합니다. 봇이 죽어도 제가 자는 사이 watchdog가 되살려 두기 때문에, 아침에 로그를 열면 대부분 성공에 몇 건 실패로 밤이 정리돼 있습니다. 서버 한 대에 접어 넣은 이 자동 복구는 죽으면 되살리고(watchdog), 연달아 실패하면 끊고(서킷브레이커), 위험한 명령은 사람이 승인해야 통과시키는 구성이며, 7월 기준으로 여덟 개 작업에 이 차단기가 걸려 있었습니다. DevOps 자격증(DOP-C02)이 그리는 것은 인스턴스가 죽으면 Auto Scaling이 새로 띄우고, 배포는 무중단으로 넘기다 실패하면 자동 롤백하는 구성입니다. 저는 같은 일을 서버 한 대에서 손으로 만들어 쓰고 있었습니다. 다만 무중단 배포는 업무에서 블루/그린으로 정착시켜 봤어도 이 개인 시스템에는 넣지 않았습니다. 사용자가 저 하나라 껐다 켜도 되기 때문입니다. 쿠버네티스 규모의 배포와 카나리 자동 롤백은 아직 해보지 않았습니다.

1편은 검색, 2편은 인프라 이중화였습니다. 마지막인 이번 편은 운영입니다.

아침에 로그를 열면 밤이 정리돼 있습니다

제가 자는 사이에도 예약해둔 작업들이 밤새 줄줄이 돕니다. 그중 몇 개는 조용히 실패하고 Discord 봇도 이따금 죽습니다. 그런데 아침에 로그를 열면, 죽었던 봇은 되살아나 있고 밤은 대부분 성공에 몇 건 실패로 정리돼 있습니다. 제가 손댄 건 없습니다. Jarvis라는 개인 AI 비서를 서버 한 대에 올려두고 매일 굴리는데, 이 시스템은 제가 없어도 스스로 죽고 스스로 살아납니다.

DevOps 자격증(DOP-C02)을 준비하며 자동 복구 파트를 보다가 이 밤사이 풍경이 겹쳐 떠올랐습니다. 서비스 인스턴스가 비정상 종료되어도 사용자 영향 없이 자동으로 대체되게 하려면 어떻게 구성하느냐는 주제입니다.

답은 대개 Auto Scaling 그룹 + 헬스 체크 + 자동 교체로 좁혀집니다. 죽은 인스턴스를 감지해서 사람 손 안 대고 새 인스턴스로 갈아 끼우는 구성입니다. 저는 이 일을 서버 한 대에서 손으로 만들어 매일 쓰고 있었습니다. 그래서 자격증을 딴 뒤 운영 로그를 다시 열어, 시험이 그린 그림과 제가 만든 구조가 어디서 만나고 어디서 갈라지는지 봤습니다.

죽으면 운영체제가 다시 띄웁니다

자동 복구의 핵심은 단순합니다. 죽은 걸 감지하고, 자동으로 되살린다. 규모가 큰 서비스는 이걸 Auto Scaling과 헬스 체크로 합니다. 인스턴스가 응답을 멈추면 그룹에서 빼고 새 걸 띄웁니다.

제 개인 시스템은 서버가 한 대뿐이라 인스턴스를 갈아 끼울 수가 없습니다. 대신 macOS의 프로세스 관리자(LaunchAgent)에게 “이 봇이 비정상으로 꺼지면 네가 알아서 다시 띄워라”라고 맡겨뒀습니다.

맡겨둔 설정은 이렇게 생겼습니다.

<key>KeepAlive</key>
<dict>
  <key>SuccessfulExit</key>
  <false/>  <!-- 정상 종료가 아니면(=죽으면) 다시 살림 -->
</dict>
<key>ThrottleInterval</key>
<integer>10</integer>  <!-- 죽자마자 무한 재시작하지 않게 10초 간격 -->

여기에 더해, 프로세스는 살아 있는데 실제로는 응답을 못 하는 경우(이른바 좀비 상태)를 잡으려고 감시용 크론(watchdog)을 따로 뒀습니다. 주기적으로 봇의 상태를 찔러보고, 살아 있지만 응답이 없으면 강제로 재기동합니다.

graph LR
    A[봇 상태 확인] --> B{응답 있나?}
    B -->|예| C[정상, 대기]
    B -->|아니오| D[강제 재기동]
    D --> A
    C --> A
    style A fill:#e0e7ff,stroke:#4F46E5,stroke-width:2px,color:#1a1a1a
    style D fill:#fee2e2,stroke:#dc2626,stroke-width:2px,color:#1a1a1a
    style C fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#1a1a1a

운영체제의 자동 재시작이 헬스 체크의 “죽으면 교체”라면, watchdog는 “살아는 있는데 일을 안 하는” 경우까지 잡는 한 겹 더입니다. 덩치는 Auto Scaling에 비할 게 못 되지만 목표는 같습니다. 제가 자는 동안 사람 손 없이 되살아나 있을 것.

계속 죽는 작업은 아예 꺼버렸습니다

한 번 죽는 건 되살리면 됩니다. 문제는 계속 죽는 겁니다. 되살리고, 또 죽고, 또 되살리는 무한 반복은 되살림 자체가 장애가 됩니다.

시험은 이 지점에서 CloudWatch 알람과 자동 롤백을 답으로 줍니다. 실패가 임계치를 넘으면 알림을 띄우고, 배포가 계속 실패하면 직전 버전으로 되돌립니다.

제 시스템은 여기에 서킷브레이커(circuit breaker)를 뒀습니다. 이름이 거창하지만 원리는 단순합니다. 특정 작업이 연달아 실패하면 그 작업을 잠시 멈추고, 그래도 계속 실패하면 아예 내려버립니다. 7월 기준으로 이 서버에는 여덟 개 작업에 이 차단기가 걸려 있었습니다.

코드로 옮기면 이 정도입니다.

// 실제 코드를 줄인 의사코드 — 연속 실패가 임계치를 넘으면 그 작업을 잠시 멈춘다
if (task.consecutiveFailures >= THRESHOLD) {
  task.state = 'OPEN';                 // 차단: 당분간 실행 안 함
  scheduleCooldown(task, COOLDOWN_MS); // 쿨다운 뒤 HALF_OPEN 으로 한 번만 시험 실행
}

쿨다운이 지나면 한 번만 시험 삼아 실행해 봅니다(반열림, half-open). 성공하면 정상 상태로 돌리고, 또 실패하면 다시 차단합니다. 그래도 계속 실패하는 작업은 영구 실패로 분류해서 자동으로 꺼버립니다. 이렇게 해두면 실패하는 작업 하나가 되살림을 반복하며 시스템 전체를 갉아먹는 일은 없습니다.

시험의 “실패가 임계치를 넘으면 롤백”과 제 “연속 실패를 넘으면 차단”은 결이 같습니다. 둘 다 실패를 감지하는 데서 멈추지 않고 실패가 번지지 않게 끊어냅니다.

배포는 껐다 켜는 게 전부입니다

여기서부터는 갈라집니다.

시험이 배포에서 가장 크게 다루는 건 무중단 배포입니다. CodeDeploy의 블루/그린, 카나리 같은 전략입니다. 새 버전을 옆에 띄워두고 트래픽을 조금씩 넘기다가, 문제가 없으면 완전히 갈아타고, 문제가 있으면 즉시 되돌리는 방식입니다. 사용자는 배포가 있었는지도 모르게 넘어갑니다.

제 개인 시스템은 이걸 안 합니다. 사용자가 저 하나라, 새 버전을 올릴 때는 그냥 잠깐 껐다 켜면 됩니다. 몇 초 끊김을 감수할 사람이 저뿐입니다. 업무에서는 블루/그린으로 무중단 배포를 정착시킨 적이 있지만, 사용자가 한 명인 시스템에 그 비용을 들일 이유는 없었습니다.

해본 것과 안 해본 것을 나눠 적어 둡니다. 블루/그린 무중단 배포는 업무 서비스에서 운영해 봤고 이 개인 시스템에는 넣지 않았습니다. 트래픽을 조금씩 넘기다 지표가 나빠지면 자동으로 되돌리는 카나리 배포와, EKS나 쿠버네티스 위의 대규모 배포는 아직 운영해 본 적이 없어서 학습하며 넓혀 가는 중입니다.

시험의 배포 파트에서 딱 하나, 제 방식과 만나는 지점이 있었습니다. 승인 게이트(Manual Approval)입니다. 시험은 배포 파이프라인 중간에 사람이 승인해야만 다음으로 넘어가는 관문을 둡니다. 위험한 변경을 자동으로 흘려보내지 않으려는 장치입니다.

제 시스템에도 비슷한 게 있습니다. 되돌릴 수 없는 위험한 명령(예: 대량 삭제, 저장소 공개 설정 변경)은 자동으로 실행되지 않게 막아뒀습니다. 제가 명시적으로 허락해야만 실행됩니다. 층위는 다릅니다. 시험의 승인 게이트는 배포 단계에 걸리고, 제 장치는 명령 하나하나에 걸립니다. 그래도 되돌릴 수 없는 일은 사람이 한 번 보고 넘긴다는 생각은 같습니다.

표준 이름이 생겨서 달라진 것

자동 복구도, 서킷브레이커도, 승인 게이트도 시험 보기 전부터 만들어 쓰고 있었습니다. 그래서 시험이 나한테 뭘 줬나 싶었습니다.

달라진 건 남한테 설명할 때였습니다. 감으로 만든 것들에 헬스 체크·자동 롤백·블루/그린 같은 표준 용어가 생기니 같은 걸 말하는 데 문장이 훨씬 짧아졌습니다.

안 해본 영역도 같이 선명해졌습니다. 카나리 자동 롤백, 쿠버네티스 규모의 배포, 오토스케일링을 실제 트래픽 위에서 굴리는 일입니다. 어디 있는지 알았으니 다음에 그 규모를 만나면 헤맬 시간은 줄어들 겁니다.

오늘 하나만 넣는다면

오늘 당장 넣을 수 있는 건 하나입니다. 프로세스가 죽었을 때 사람 손 없이 되살아나는 장치 하나를 거는 겁니다. 리눅스면 systemd, macOS면 LaunchAgent, 컨테이너면 재시작 정책 한 줄이면 됩니다. 이것만 있어도 새벽에 죽어서 아침까지 멈춰 있는 사고는 상당수 막을 수 있습니다.

그 위에는 한 겹씩 올리면 됩니다. 살아는 있는데 응답을 못 하는 좀비 상태까지 감지하려면 프로세스 존재 확인만으로는 부족하고 응답을 직접 확인해야 합니다. 되살림이 무한 반복되지 않게 재시작 간격과 서킷브레이커를 두고, 반복 실패하는 작업은 자동으로 격리하거나 꺼서 실패 하나가 전체를 갉아먹지 않게 합니다. 되돌릴 수 없는 위험한 작업은 사람이 한 번 승인하게 둡니다.

시리즈를 닫으며

처음엔 봇이 죽으면 아침에 제가 켰습니다. 그게 몇 번 반복되고 나서야 watchdog을 짰습니다. 자동 복구를 미리 설계해 넣은 게 아니라 새벽에 멈춰 있는 걸 몇 번 보고 나서 뒤늦게 붙였습니다. 이 글에서 다룬 나머지 장치들도 대체로 이 순서로 생겼습니다.


읽어주셔서 감사합니다.🖐


Ramsbaby
Written byRamsbaby
이 블로그는 직접 개발/운영하는 블로그이므로 당신을 불쾌하게 만드는 불필요한 광고가 없습니다.

#My Github#소개 페이지#Blog OpenSource Github