웹페이지 모니터링 하다 다운되면 이메일로 알려주는 시스템 만들기

재미 삼아 개인적 용도로 웹 페이지를 몇 개 테스트로 운용하고 있다. 문제는 클라우드 서버가 아니라 버리는 컴퓨터 몇 대를 짜집기 해서 한 대를 돌리고 있다는 것이다. 이로 발생되는 문제는 당연하게도 간헐적인 다운… 이 비정기적인 이벤트로 인해 고통 받던 중에 서버나 웹 페이지에 이상이 있어서 다운되면 이메일로 알려주는 도커 이미지를 만들어 볼까? 하고 생각했다.

참고로 이미 서버에 설치해서 이벤트를 알려주는 서비스들은 이미 나온 게 있다. (예: 와탭) 그런데 이런 서비스들은 웹 페이지만 감시하는 것이 아니라 서버 자체를 모니터링 해주기 때문에 너무 많은 정보와 적당히 많은 홍보성 안내 메일로 인해 오히려 모니터링을 모니터링하게 된다. 나에게 필요한 건 웹 페이지 다운되면 이메일로 “니 사이트 죽었음!” 하고 간단히 알려주는 것이 되시겠다.

진행은 다음과 같다.

  1. 도커 설치 (생초보라 도커부터 설치해야 하는 분은 여기서부터 시작)
  2. 도커 이미지 빌드 (도커가 이미 설치된 분은 이리로 바로 가면 됨)
  3. 파이선 파일 이식 (파이썬을 그냥 돌리거나 코드만 필요한 분은 여기로 바로 가면 됨)

당연히 모니터링하는 서버는 24시간 풀로 돌아가야 하니까 나는 아마존에 무료 계정 하나 파서 구동해 주고 있다. 1달 31일 기준으로 1개만 돌리면 무료로 사용 가능하다. (처음엔 이 개념을 잘 몰라서 바가지 쓸뻔!!!)

도커 설치

인터넷에서 가끔 보면 sudo apt-get install docker.io 같은 간단한 설치법이 있는데, 이것은 공식 지원이 아니므로 삭제하고 설치하라는 식의 안내가 나와 있다. 설치 방법은 다음과 같다.

  1. 기존에 설치된 비공식 도커 삭제

    $ for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
    
  2. 도커 저장소 설치 (Docker official GPG key:)

    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    sudo apt-get update
    
  3. 도커 설치

    $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    

도커 이미지 빌드

도커를 설치했다면 도커 이미지를 만들어 보자.

별 건 아니고 파이선이 설치된 이미지를 불러와서 우리가 만든 파이선 파일을 구동시킬 환경을 만들 뿐이다.

  1. Docker 파일을 만든다.

    sudo nano Dockerfile
    
  2. Dockerfile 안에 다음 내용을 붙여 넣고 저장한다.

    FROM python:3.9-slim-bookworm
    
    WORKDIR /app
    
    RUN pip install --no-cache-dir requests
    
    CMD [ "python", "./monitor.py" ]
    

    파일 안의 내용은 간단하다. 이미지는 python:3.9-slim-bookworm으로 해라, /app 폴더가 메인 작업장이다, pip install --no-cache-dir requests라는 명령어를 실행해라, 컨테이너를 실행하면 “python”을 실행하고 app 폴더에 있는 “monitor.py” 파이선 파일을 실행해라.

    참고로 저 파이선 이미지는 이루로 나온 3.10 이후 버전을 모두 테스트해 봤는데 메일 서버의 ssl 인증관련 문제가 있어서 메일 발송이 안되었다. (보안 없는 25포트는 실행 가능) 이메일의 ssl인증 관련 이슈가 발생할 경우 파이선 이미지 버전을 지켜 주기 바란다(이전 버전 가능).

  3. 도커 이미지를 monitor란 이름으로 만들어 준다.

    docker build -t monitor .
    

파이선 파일 만들기

이 부분은 고민을 좀 했는데 python 안에 메일 계정 및 설정을 넣는 방법과 별도 파일을 만들어서 넣는 방법 가운데 나는 별도 계정 정보를 넣어서 보관하는 방법을 선택했다.

  1. 도커 이미지에서 설정한 대로 monitor.py라는 이름의 파이선 파일을 만들어 준다.

    sudo nano monitor.py
    
  2. 파일 안에 다음 내용을 그대로 복사해서 붙여 넣고 저장한다.

    import time
    import smtplib
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    import requests
    import configparser
    
    # config.ini 파일을 읽어오자.
    config = configparser.ConfigParser()
    config.read('config.ini')
    
    # 구성 파일 안의 설정을 추출해오자.
    SMTP_SERVER=config.get('SMTP','server')  # SMTP 서버 주소 가져오기
    SMTP_PORT=config.getint('SMTP','port')  # SMTP 포트 번호 가져오기
    GMAIL_USERNAME=config.get('SMTP','username')  # Gmail 계정 사용자 이름 가져오기
    GMAIL_PASSWORD=config.get('SMTP','password')  # Gmail 계정 비밀번호 가져오기
    USE_SSL=config.getboolean('SMTP', 'ssl')  # SSL 사용 여부 가져오기 (True 또는 False)
    
    SITES=[site.strip() for site in config.get('SITES', 'urls').split(',')] # 모니터링할 웹사이트 URL 목록 가져오기
    CHECK_INTERVAL=config.getint('MONITORING', 'interval') # 체크 간격 설정 (초 단위)
    ERROR_PERSISTENCE=config.getint('MONITORING', 'errors_before_alert') # 에러 발생 횟수 설정
    
    RECIPIENT_ADDRESS=config.get("EMAIL", "recipient_address").split(',') # 이메일 수신자 주소 목록 가져오기
    
    def send_email(site):
        msg=MIMEMultipart()
        msg['From']=GMAIL_USERNAME # 발신자 메일 계정 설정
        msg['To'] = ", ".join(RECIPIENT_ADDRESS)  # 수신자 설정 (여러 수신자에게 메일 보내기 위해 쉼표로 구분하여 합침)
        msg['Subject']=f"Website Down Alert: {site}"  # 이메일 제목 설정
        message_body_content=f"Hello,{site} is down.Thanks"  # 이메일 내용 설정
    
        msg.attach(MIMEText(message_body_content,'plain'))  # 이메일 내용을 MIME 형식으로 추가
    
        server=smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) if USE_SSL else smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
    
        server.login(GMAIL_USERNAME,GMAIL_PASSWORD)  # SMTP 서버에 로그인하기
    
        text=msg.as_string()  # 메시지를 문자열로 변환
    
        server.sendmail(GMAIL_USERNAME, RECIPIENT_ADDRESS, text)  # 메일 전송
       
    error_counts={site:0 for site in SITES}  # 각 사이트의 에러 카운트를 저장하는 딕셔너리 초기화
    
    # 사이트에 GET 요청 보내고 응답 받아옴
    while True:
        for site in SITES:
            try:
                response=requests.get(site)
                if response.status_code !=200:
                    error_counts[site]+=1
                    if error_counts[site]>=ERROR_PERSISTENCE:
                        send_email(site)
                        error_counts[site]=0
                else:
                    error_counts[site]=0
    
            except requests.exceptions.RequestException as err:
                print ("OOps: Something Else Happened",err)
    
        time.sleep(CHECK_INTERVAL) # 지정된 시간만큼 대기 후 다음 반복 실행
    
  3. 구성 파일을 만든다.

    sudo nano config.ini
    
  4. 구성 파일 안에 내용을 붙여 넣고, 구성 내용을 자신의 계정에 맞게 수정하여 저장한다.

    [SMTP]
    server = smtp.server.url  # SMTP 서버 주소 설정 (자신의 메일 서버 주소 입력)
    port = 465  # SMTP 포트 번호 설정 (보안 없으면 25, 보안 있으면 465 또는 587)
    username = yourmail@mail.mail  # Gmail 계정 사용자 이름 또는 발신자 메일 계정 설정 (자신의 메일 계정 입력)
    password = yourmailpassword  # Gmail 계정 비밀번호 또는 발신자 메일 계정 비밀번호 설정 (자신의 메일 계정 비밀번호 입력)
    ssl = yes  # SSL 사용 여부 설정 ('yes' for SSL, 'no' for non-SSL)
    
    [SITES]
    urls = http://monitorring1.site.com,http://monitorring2.site.com,http://monitorring3.site.com  # 모니터링할 웹사이트 URL 목록 설정 (여러 개일 경우 쉼표로 구분)
    
    [MONITORING]
    interval = 600  # 체크 간격 설정 (초 단위)
    errors_before_alert = 2  # 에러 발생 횟수 설정
    
    [EMAIL]
    recipient_address=recipient@mail.mail,recipient2@mail.mail,recipient3@mail.mail  # 이메일 수신자 주소 목록 설정 (여러 개일 경우 쉼표로 구분)
    

    smtp.server.url에는 자신의 메일 SMTP 서버 주소를 입력한다. port에는 SMTP 메일을 발송할 포트를 입력한다. (보안 없으면 25, 보안 있으면 465 또는 587) yourmail@mail.mail은 발신할 SMTP 메일 계정을 입력하고 yourmailpassword는 해당 계정의 비밀번호를 입력한다. ssl은 SSL 사용 여부를 설정하며 ‘yes’로 설정하면 SSL을 사용하고, ‘no’로 설정하면 SSL을 사용하지 않는다. urls에는 모니터링할 웹사이트의 URL 목록을 입력한다. 여러 개의 URL일 경우 쉼표(,)로 구분하여 입력한다. interval은 체크 간격을 초 단위로 설정하며, errors_before_alert는 에러 발생 횟수를 설정한다.

  5. 도커 이미지를 사용해 도커 컨테이너를 실행해 보자. 실행할 때 꼭 /app을 마운트 해주어야 한다.

    sudo docker run --name web-monitor -v $pwd:/app -d monitor
    

    $pwd 부분은 monitor.py 파일과 config.ini 파일이 있는 폴더의 경로를 입력해야 한다. 만약 코드 복사 후 오류가 발생한다면, monitor.py의 주석 부분을 제거하고 다시 시도해 보자.


IT 5