LabHub
배우기 러닝패스 코스

デバッグ実戦

うちのサーバでは動くんですが

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

같은 코드가 여기서만 안 될 때 범인은 대개 환경변수, 인코딩, 권한, 그리고 셸의 값과 프로세스의 값이 다르다는 사실 중 하나다.

概念マップ: 첫째, 환경변수.・설정한 곳과 읽는 곳이 다릅니다.・둘째, 인코딩.・자동 변환에 기대는 것

왜 이게 필요했나

FDE 가 가장 자주 듣는 문장이 "우리 서버에서는 되는데요" 입니다. 그리고 대개 그 말은 사실입니다. 코드는 같고, 환경이 다릅니다.

환경 차이는 코드 결함보다 찾기 어렵습니다. 코드는 읽으면 보이지만 환경은 읽을 것이 없기 때문입니다. 그래서 순서가 필요합니다.

어떻게 동작하나

현장에서 실제로 자주 나오는 순서대로 네 가지를 봅니다.

첫째, 환경변수. 없으면 실패한다는 것을 알려 주는 것은 대개 에러 메시지 자신입니다. missing env API_TOKEN 처럼. 문제는 이 메시지를 보고도 "설정했는데요" 라는 답이 돌아오는 경우인데, 거의 항상 설정한 곳과 읽는 곳이 다릅니다. 셸에서 export 한 값은 그 셸의 자식 프로세스에만 갑니다. systemd 로 뜬 서비스는 그 값을 보지 못합니다.

둘째, 인코딩. 한글 고객 데이터에서 압도적으로 자주 터집니다. 윈도우 환경에서 만들어진 CSV 는 UTF-8 이 아니라 EUC-KR(CP949)인 경우가 많고, 이 파일을 UTF-8 로 읽으면 글자가 깨지거나 디코딩 오류로 죽습니다. file 명령이 인코딩을 항상 정확히 맞히지는 못하므로, 한글이 깨져 보이면 iconv -f EUC-KR -t UTF-8 로 변환을 시도해 보는 것이 가장 빠릅니다.

여기서 함정은 자동 변환에 기대는 것입니다. 잘못된 인코딩으로 읽힌 문자열은 조용히 통과해서 데이터베이스에 저장되고, 몇 주 뒤 검색이 안 된다는 신고로 돌아옵니다. 인코딩은 읽는 시점에 확정해야 합니다.

셋째, 권한. 특히 자격 증명 파일이 그렇습니다. 토큰 파일이 644 로 놓여 있으면 같은 서버의 다른 사용자가 전부 읽을 수 있고, 보안 점검에서 이것 하나로 프로젝트 전체의 신뢰가 깎입니다. FDE 는 남의 집 열쇠를 다루는 사람이라 여기가 특히 무겁습니다. 최소 권한은 예의가 아니라 생존 규칙입니다.

넷째, 셸의 값과 프로세스의 값이 다르다는 것. 이게 가장 자주 사람을 속입니다. 파일 열기 한도를 예로 들면, 셸에서 ulimit -n 이 1048576 을 보여 줘도 실제로 도는 서비스의 한도는 1024 일 수 있습니다. 확인해야 할 곳은 셸이 아니라 /proc/<PID>/limits 입니다.

같은 함정이 여러 겹으로 반복됩니다. /etc/security/limits.conf 는 PAM 로그인 세션에만 적용되고 systemd 서비스에는 적용되지 않습니다. 컨테이너 안의 freenproc 은 호스트 값을 보여 주는데 실제 제한은 cgroup 에 있습니다. 원칙은 하나입니다 — 설정 파일이 아니라 실행 중인 프로세스에서 실측하라.

현장에서 만나는 모습

환경 점검 스크립트를 하나 만들어 두는 것이 이 전부를 대신합니다. 필요한 환경변수, 파일 존재와 권한, 로캘, 데이터 접근 가능 여부를 순서대로 확인하고 첫 번째 실패에서 이유를 말하며 멈추는 스크립트입니다.

이런 스크립트의 가치는 진단 시간이 아니라 대화의 질에 있습니다. "안 되는데요" 대신 "envcheck 가 API_TOKEN 없다고 합니다" 라는 문장이 오가면, 고객사 담당자와의 왕복이 세 번에서 한 번으로 줄어듭니다.

차이를 없애는 쪽으로 가기

환경 차이를 잘 찾는 것도 중요하지만, 더 나은 길은 차이가 생길 자리를 줄이는 것이다. 넘겨받은 시스템을 조금씩 그 방향으로 미는 것이 FDE 가 남기는 값어치이기도 하다.

의존하는 것을 목록으로 만든다. 이 프로그램이 무엇을 필요로 하는지가 어디에도 적혀 있지 않으면, 새 환경에서 무엇이 빠졌는지 알 방법이 없다. 필요한 환경 변수, 접근해야 하는 경로와 주소, 필요한 명령과 그 버전. 이 목록이 곧 앞에서 만든 점검 스크립트의 내용이 된다.

기본값을 두되 조용히 넘어가지 않는다. 값이 없을 때 그럴듯한 기본값으로 돌아가면 편하지만, 그 사실이 로그에 남지 않으면 나중에 "왜 다른 결과가 나오죠" 를 설명할 수 없다. 기본값을 썼다는 것 자체를 한 줄 남기는 것만으로 조사 시간이 크게 줄어든다.

시작할 때 한 번에 확인하고 죽는다. 필요한 것이 없으면 실행 도중에 아무 데서나 실패하는 대신, 시작하자마자 전부 검사해 없는 것을 한꺼번에 알리고 멈추는 편이 낫다. 그러면 세 번 왕복할 것이 한 번에 끝난다.

환경을 코드로 적는다. 손으로 설정한 것은 재현되지 않고, 재현되지 않는 것은 두 환경이 왜 다른지 설명할 방법이 없다. 컨테이너 이미지든 설정 관리 도구든, 그 환경을 만드는 절차가 파일로 남아 있으면 "여기서만 안 된다" 는 문장 자체가 성립하기 어려워진다.

이 넷을 한꺼번에 요구하면 고객은 부담스러워한다. 그래서 지금 겪은 사고 하나에서 출발하는 것이 좋다. 이번에 API_TOKEN 때문에 반나절을 썼으니 그것부터 점검 스크립트에 넣자는 제안은 받아들여지기 쉽고, 그렇게 한 줄씩 늘어난 스크립트가 몇 달 뒤에는 꽤 쓸 만한 문서가 된다.

다음 실습에서 할 것

환경 점검 스크립트가 실패하는 상태에서 시작해, 실패 원문을 확보하고, 누락된 환경변수를 특정하고, EUC-KR 한글 CSV 를 UTF-8 로 되살리고, 토큰 파일에 최소 권한을 적용해 점검을 통과시킵니다.