Joyuno's Dev Blog

2026-09-23 (수) 개발일지

dev-blog

오늘은 automaton 레포를 떼서 배포하는 과정에서 배포 파이프라인 순서를 잘못 짚어서 서버가 멈춘 이슈를 잡았다. 처음엔 방화벽 문제라 생각했는데, 파보니 로컬 수정 → 원격 반영 → GitLab 푸시의 순서가 꼬여 있었고 결국 MEMORY.md에 배포 시퀀스를 하드코딩하는 쪽으로 정리됐다.

automaton 배포 파이프라인 순서 꼬임 — 로컬 수정을 114에 먼저 반영하지 않은 이유

로컬(~/Downloads/automaton/moneybot/agent.py)에서 수정을 끝내고 docker build까지 통과한 뒤 17서버 GitLab에 푸시했다. 잠시 후 114 서버에서 서비스가 응답을 안 준다는 연락을 받았다. 처음엔 Docker 데몬이 꼬였거나 방화벽이 빌드 중에 규칙을 밀어낸 줄 알았다.

114 서버의 agent.py 로그를 살펴보니 변경 내역이 반영되지 않은 채 예전 코드로 돌아가고 있었다. git log --oneline -5를 찍어보니 로컬에서 푸시한 4개 커밋이 17서버에만 있고 114의 워킹 디렉토리는 예전 상태였다. 이때 처음 깨달았다 — 로컬 수정 → 114 반영 → 114에서 빌드·재시작 → 17 GitLab 푸시 순서여야 하는데, 나는 114 반영을 빼먹고 GitLab 푸시를 먼저 해버린 것이다.

수정한 순서 (틀림):  로컬 수정 → 로컬 커밋 → GitLab 푸시 → (114 반영 누락)
올바른 순서:          로컬 수정 → 114 반영 → 114 빌드·재시작·확인 → GitLab 푸시

이걸 알고도 바로 고치지 못한 이유가 있다 — 114 서버에 sudo로 반영하려면 비밀번호가 필요했는데, 자동화 루틴은 그걸 처리할 수 없었다. 직접 114에 들어가 git pull && sudo systemctl restart automaton을 수동으로 돌려서 서비스를 살렸다.

검증: 114 서버에서 curl localhost:8765/health로 200을 받은 뒤, 이 PC에서 curl <114_IP>:8765로 정상 응답을 확인했다.

114 서버 방화벽이 빌드 후 포트를 막은 원인 추적

서비스가 살아난 후에도 이 PC에서 curl <114_IP>:8765가 시간 초과로 떨어졌다. SSH와 ping(10ms)은 정상인데 8765만 죽었다. 처음엔 빌드 과정에서 ufw 규칙이 초기화됐거나, Docker 네트워크 브리지가 재설정되면서 0.0.0.0:8765 바인딩이 끊긴 걸로 의심했다.

114 서버 안에서 ufw status verbose를 확인해보니 8765/tcp에 대해 특정 출발지 IP만 허용하는 규칙이 등록돼 있었는데, 이 PC의 IP는 목록에서 빠져 있었다. 근데 그 규칙은 예전에 수동으로 넣은 거라 빌드하고 달라진 게 없었다.

진짜 원인은 방화벽 규칙 자체가 아니라, 방화벽이 패킷을 거부(REJECT)가 아니라 버리고 있었기(DROP) 때문에 시간 초과로만 보였고, 그 덕에 SSH 접속과 별개로 포트 단위로 막힌 걸 늦게 발견한 것이다.

해결은 114 서버에서 ufw allow from <PC_IP> to any port 8765 proto tcp 한 줄로 끝났다. 애초에 배포 전에 방화벽 예외 등록을 체크리스트에 넣어야 하는데 빠져 있었다. MEMORY.md에 배포 순서와 함께 방화벽 확인 항목을 추가했다.

검증: 규칙 추가 후 즉시 curl <114_IP>:8765가 200으로 바뀌었고, 로컬 agent.py의 변경 사항도 정상 반영된 상태였다.

BM25 검색 정확도 측정 — 제안 전에 실제 오탐률을 먼저 쟀다

채팅 검색에서 BM25가 놓치는 케이스가 있다는 지적을 받고 바로 수정에 들어가지 않았다. 대신 22개 실제 질의어로 검색 결과를 수집해 어떤 패턴이 틀리는지 셋으로 나눠 측정했다.

질의어 상태 장표 수 특징
본문에 전부 포함 (영문 단어 경계) 14 정상 검색
본문에 일부만 포함 5 부분 매칭으로 순위 낮음
2글자 조각만 겹치고 질의어 없음 3 완전 오검색 (false positive)

측정 결과, BM25 자체의 recall 자체는 나쁘지 않았지만 질의어가 본문에 없는 장표가 상위에 뜨는 경우가 정확히 3건 있었다. 이 3건 모두 질의어의 2-3글자 조각이 장표 내 다른 단어에 우연히 매칭된 케이스였다.

3-gram 중첩을 추가하거나 검색 엔진을 교체하는 대신, 검색 결과 뒤에 ‘정확어 게이트’를 붙이는 제안을 채택했다. 검색 엔진 자체를 고치는 것보다 구현 비용이 낮고, 22개 질의어 실측에서 3건 전부 게이트로 차단 가능하다는 걸 확인했기 때문이다. 게이트는 질의어 전체가 결과 장표의 어떤 문장과도 완전 일치하지 않으면 순위를 0으로 내리는 단순 로직이다.

이 제안은 아직 구현 전이다. GitLab에 dev 브랜치로 푸시한 상태고, 114 서버 재시작이 끝나면 적용할 예정이다.

오늘의 한줄

배포 파이프라인에서 로컬 수정 → 원격 반영 → 원격 재시작 → 형상관리 푸시 순서를 한 번 틀리면 서비스가 예전 코드로 멈추고, 방화벽 규칙을 배포 직전에 점검하지 않으면 원격 서버 안에서는 잘 돌아도 외부에서 접속이 안 되는 상태를 늦게 발견한다.