웹/배포

[Final 17] 서비스 모니터링 기법과 17일간의 로드맵 회고,"로그 관리

jumemory 2025. 9. 12. 19:13

[Final 17] 서비스 모니터링 기법과 17일간의 로드맵 회고

서비스를 배포한 후 가장 무서운 상황은 "사용자는 안 된다고 하는데, 개발자는 이유를 모를 때"입니다. 이를 방지하기 위해 서버의 심박수를 체크하는 모니터링과 과거의 기록을 살피는 로그 관리가 필수적입니다.


1. 로그 관리의 정석 (Logging)

로그는 서버에서 일어나는 모든 일의 '기록'입니다. Django와 Nginx의 로그를 체계적으로 관리해야 트래픽 급증이나 에러 발생 시 원인을 빠르게 파악할 수 있습니다.

① Django 로깅 설정 (settings.py)

콘솔뿐만 아니라 파일로도 로그를 남기도록 설정합니다.

Python
 
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'ERROR',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': 'logs/django_error.log',
            'maxBytes': 1024 * 1024 * 5, # 5MB
            'backupCount': 5,
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'ERROR',
            'propagate': True,
        },
    },
}

② 도커 실시간 로그 확인

컨테이너 환경에서는 아래 명령어가 가장 강력한 무기입니다.

  • docker-compose logs -f --tail=100 web: Django 앱의 최근 로그 100줄을 실시간으로 추적합니다.
  • docker-compose logs -f nginx: 접속 요청(Access Log)과 서버 에러를 확인합니다.

2. 서버 모니터링 기법

서버가 죽기 전에 미리 징후를 파악하는 것이 중요합니다.

① 리소스 모니터링 (CPU, RAM, Disk)

  • htop: 리눅스 터미널에서 CPU와 메모리 점유율을 시각적으로 확인합니다.
  • df -h: 디스크 용량을 확인합니다. 로그 파일이 쌓여 용량이 꽉 차면 서버가 멈추므로 주의해야 합니다.

② 외부 모니터링 도구 활용

  • UptimeRobot: 5분마다 내 사이트에 접속해보고 응답이 없으면 메일/텔레그램으로 알림을 보내주는 무료 서비스입니다.
  • Sentry (에러 트래킹): Django 코드에서 에러가 발생하면 어떤 유저가 어떤 기기에서 에러를 겪었는지 상세히 분석해서 알려줍니다. (실무 필수 도구)

3. 트러블슈팅 체크리스트 (에러 유형별)

에러 메시지 주요 원인 해결 방법
502 Bad Gateway Gunicorn이 꺼져 있거나 Nginx 설정 오류 docker ps로 컨테이너 확인 및 Nginx config 체크
504 Gateway Timeout 로직 처리가 너무 오래 걸림 쿼리 최적화 또는 Celery(비동기) 도입 검토
403 Forbidden 권한 설정 또는 CSRF 토큰 누락 ALLOWED_HOSTS 및 Django Permission 체크
Connection Refused DB 서버(RDS) 접속 불가 보안 그룹(Security Group) 인바운드 규칙 확인

4. 17일간의 로드맵 회고: 우리는 무엇을 배웠는가?

지난 17개의 포스팅을 통해 우리는 한 명의 개발자가 서비스를 세상에 내놓기 위해 필요한 Full-Cycle을 경험했습니다.

  1. Backend (01~05): Django와 DRF로 탄탄한 비즈니스 로직과 API를 구축했습니다.
  2. Infrastructure (06~09): Linux와 Docker로 어디서든 돌아가는 컨테이너 환경을 만들었습니다.
  3. Cloud (10~13): AWS의 넓은 생태계에서 EC2, RDS, Route53을 유기적으로 연결했습니다.
  4. DevOps (14~17): S3 저장소, HTTPS 보안, CI/CD 자동화와 모니터링으로 서비스의 완성도를 높였습니다.

✍️ 마지막 블로그 포스팅을 마치는 인사말

독자들에게 **"이 17단계는 끝이 아니라 새로운 시작입니다"**라고 격려해 주세요. 이제 여러분은 단순히 코드를 짜는 사람이 아니라, 서비스를 기획하고 운영하며 관리하는 **'엔지니어'**가 되었습니다. 앞으로는 성능 최적화, 마이크로서비스 아키텍처(MSA), 쿠버네티스 등 더 넓은 세상으로 나아가길 응원하며 시리즈를 마무리해 보세요.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

vim ~/.bashrc

 

export AIRFLOW_HOME=/home/ec2-user/airflow



mkdir ~/airflow



pip install apache-airflow==2.11.0



airflow standalone



 

- airflow 종료 후 

 

cd ~/airflow 

 

ls -al

 

vim airflow.cfg

 

43번째 라인 

default_timezone = Asia/Seoul

 

497 라인 

sql_alchemy_conn = mysql://airflow:1q2w3e@10.0.0.10:3306/airflow

 

1425 라인

default_ui_timezone = Asia/Seoul

 

124 라인 

load_examples = False




Host db

HostName 43.201.116.207

User ubuntu

IdentityFile C:/Users/play/.ssh/skn15-scw.pem




sudo mysql -uroot 

 

create database airflow;

create user airflow@'%' identified by '1q2w3e';

grant all privileges on airflow.* to airflow@'%';


추가

sudo dnf install -y mariadb-connector-c-devel gcc

 

pip install mysqlclient 



airflow webserver -p 8080

 

airflow scheduler 



airflow db migrate



airflow users create --username play --firstname seo --lastname woong --role Admin --email afasf@encore.com




mkdir ~/airflow/dags





dag_test.py

 

from datetime import datetime

from airflow import DAG

from airflow.operators.python import PythonOperator

from pendulum import timezone

 

kst = timezone("Asia/Seoul")

 

def hello_world():

    print("Hello, Airflow!")

 

def print_date(execution_date=None, **context):

    # execution_date는 논리 실행 시간(Logical Date)

    print(f"Execution date: {execution_date}")

 

with DAG(

    dag_id="example_basic_python",

    description="A simple DAG with two Python tasks",

    start_date=datetime(2023, 1, 1, tzinfo=kst),

    schedule_interval="0 9 * * *",  # 매일 09:00 KST

    catchup=False,                  # 과거 날짜에 대한 백필 방지

    tags=["example", "basic"],

) as dag:

    t1 = PythonOperator(

        task_id="hello_world",

        python_callable=hello_world,

    )

 

    t2 = PythonOperator(

        task_id="print_date",

        python_callable=print_date,

    )

 

    t1 >> t2




---

get_stock.py 

 

from airflow import DAG

from airflow.operators.python_operator import PythonOperator

import datetime  

import requests

import pandas as pd

 

args = {

    'start_date' : datetime.datetime(2025,9,11),

}

def get_krx():

    pass

 

def get_naver():

    pass

 

dag = DAG(

    'stock_crawler',

    default_args = args,

    description="stock 수집",

    schedule_interval= "30 15 * * 1-5",

    catchup=False

)

 

t1 = PythonOperator(

    task_id='krx',

    python_callable = get_krx,

    dag=dag

)

 

t2 = PythonOperator(

    task_id='naver_stock',

    python_callable = get_naver,

    dag=dag

)

 

t1 >> t2

 

sudo dnf install -y mariadb-connector-c-devel gcc

 

pip install mysqlclient

형제관계여서 오류 x?

 

import sqlalchemy

user = 'play'

password = '1q2w3e4r!'

port = 3306

host="10.0.0.10"

engine = sqlalchemy.create_engine(f"mysql://{user}:{password}@{host}:{port}")