서버 운영
운영 서버에서만 앱이 안 돌 때
로컬에서는 완벽한데 서버에서는 에러가 나면, 서버의 시간대나 권한, 디스크 용량을 먼저 확인해야 한다.
서버에서만 앱이 안 되는 건 답답하다. 로컬과 서버의 차이가 뭔지 찾기 어렵기 때문이다. 하지만 체계적으로 확인하면 대부분 빨리 찾을 수 있다.
서버 리소스 상태 먼저 보기
앱이 안 된다고 바로 코드를 의심하기 전에, 서버 자체가 정상인지 본다.
# CPU와 메모리 사용량
htop
# 디스크 용량 확인
df -h
# 일반 프로세스들은 정상인가?
ps aux | head -20
메모리가 가득 찼거나 디스크 용량이 없으면, 앱이 정상이라도 돌 수 없다.
시간대 확인하기
로컬과 서버의 시간이 다르면 예상치 못한 에러가 날 수 있다.
# 현재 시간과 시간대 확인
date
timedatectl
# 타임존 설정
sudo timedatectl set-timezone Asia/Seoul
예약된 작업이 실행되지 않거나, 토큰이 갑자기 만료된다고 하면 시간대를 의심해본다.
파일 권한과 디렉토리 확인하기
# 앱 파일의 소유자와 권한
ls -la /opt/myapp/
# 로그 파일을 쓸 수 있는가?
ls -la /var/log/myapp/
# 임시 파일을 쓸 수 있는가?
ls -la /tmp
서버에서 파일을 쓰려고 하는데 권한이 없으면 에러가 난다. sudo chown -R user:group /opt/myapp 같은 명령으로 권한을 설정한다.
환경 변수 다시 확인하기
# 프로세스의 환경 변수
cat /proc/<pid>/environ | tr '\0' '\n' | grep -i 'api\|db\|secret'
# 또는 직접 확인
sudo -u app_user env | grep DATABASE
로컬에서는 .env 파일에서 읽지만, 서버에서는 시스템 환경 변수에서 읽을 수도 있다. 값이 다를 수 있다.
네트워크 연결 확인하기
# 데이터베이스에 연결되는가?
telnet db-host 5432
# Redis에 연결되는가?
redis-cli -h redis-host ping
# 외부 API에 접근할 수 있는가?
curl -v https://external-api.com/health
방화벽이 차단하고 있거나, 네트워크 설정이 다를 수 있다.
로그를 자세히 읽기
# 앱 시작 로그 보기
journalctl -u myapp -n 100
# 실시간 로그
journalctl -u myapp -f
# 특정 시간대 로그
journalctl -u myapp --since "2024-06-30 14:00:00" --until "2024-06-30 15:00:00"
로그에서 다음을 찾아본다:
- "Connection refused": 데이터베이스/캐시 연결 실패
- "Permission denied": 파일 권한 문제
- "Disk quota exceeded": 디스크 가득 참
- "Out of memory": 메모리 부족
로컬과 서버의 버전 비교
# 서버의 런타임 버전
node -v
python -version
java -version
# 의존성 버전
npm list | head -20
pip list | head -20
로컬에서는 Node 20을 쓰지만 서버에서는 Node 16을 쓸 수도 있다. 버전 차이로 인한 비호환성이 있을 수 있다.
한 가지씩 고쳐보기
여러 문제가 보인다면 하나씩 고친다.
- 권한 수정
- 환경 변수 재설정
- 앱 재시작
- 로그 다시 확인
한 번에 여러 개를 고치면 뭐가 효과가 있었는지 알기 어렵다.
앞으로의 배포 체크리스트
앱을 배포할 때 이걸 체크한다:
- 서버 시간대는 맞는가?
- 앱 파일 권한은 맞는가?
- 디스크 용량은 충분한가?
- 환경 변수는 설정됐는가?
- 데이터베이스에 연결되는가?
- 필수 포트는 열려 있는가?