Coding History/Team Project

팀플) 행성 대접근 이벤트 만들기. (도커에서의 DB 포트와 서버 이해)

BlackBirdIT 2024. 10. 17. 14:49

행성의 가시성의 대한 정보는 업데이트 되었다.

이제 행성 대접근을 계산하면 되고, 내 계획은 이렇다.

행성 대접근은 따로 만들고, 지구와의 거리가 가장 가까운 시기를 알아낸다.

이게 끝이다.

그리고 이걸 알아내려면 6개월이나 1년치를 한꺼번에 가져와야되는데 지금 2주치만 요청해도 시간은 꽤 오래 걸린다.

Horizon-api에서 가져오는 데이터 량이 많아서 그렇다.

그럼 사용사가 요청할 때 마다 한참을 기다려야된다는건데 이러면 안되니까 일단 로직을 제대로 짠 다음 미리 DB에 저장을 해두는 식으로 접근해야될 것 같다.


일단은 만들어야지..

우선 데이터는 잘 뜬다.

일단 내가 짠 로직을 설명하자면 (과부하 때문에 2주밖에 요청을 하지 않긴했다)

요청한 기간 안에서 제일 distance_to_earth 즉, 지구와 가장 가까운 광년을 가졌을 때를 알려준다.

그럼 이제 여기서 만들어둔 행성 가시성 정보를 결합해주면 된다.


가시성 정보까지 결합해서 잘 나온다!!

그런데 이제 좀 문제가 있다면 그게 문제다.

나라별로라던지, 경도 별로 시간 정보를 받아서 위도 경도를 고정값으로 만들어줘야지 DB 저장이 용이할 것 같다는 생각이 일단 들어서 그에 대한 로직을 만들어야하는데 그게 좀 어려울 것 같다.

그러니까 구두식으로 내 고민을 나열하자면

맞아 행성 대접근 이벤트에 한해서는 위도 경도 값이 고정이 되어야될 필요가 있을 것 같은데,
이유가 뭐냐면 우리가 모든 위도 경도에 따라서 DB 저장을 할 수가 없잖아? 그래서 파티션을 나누어야될 것 같다는 말이야.

그럼 내가 어딜 건드려서 여기서 고정값으로 변환을 해야되냐가 문제인데,

지금 구글 타임존으로 시간 변환을 해주고 있잖아? 여기서 받는 데이터에 아시아/서울 이런거 있지않아? 이걸 써서 요청받을 때, 대조하고 위도 경도를 고정값으로 바꿔서 요청할 수 있게 로직을 짜고 그걸 DB에 저장하는 식으로 가야되지 않을까?

우선 그렇기 때문에 timezoneId를 알아낼 필요가 있어서 기존의 timezoneInfo를 조금 수정했다.

이후에 내가 offset_sec을 변수로 저장해서 구글 타임존 api 호출을 한번으로 줄였던 로직을 그대로 적용하기 위해서 일몰 일출 -> 행성의 가시성 -> 행성의 대접근메서드로 일몰일출 메서드 실행시 뽑히는 timezoneId를 차례로 전달해줄 필요가 있어서 해당 로직들도 죄다 약간식 수정을 거쳐서 timezoneId를 행성 대접근 이벤트 로직으로 가져오는 것 까지 성공 했다.

여기 보면 timeZoneId가 보일 것이다. 그럼 이제..

DB 생성해서 테이블에 해당 정보를 우선 저장하는 로직이 있으면 된다.

일단 DB 부터 어떻게 짤지 생각을 하자.

지금 내가 DB 저장을 하려고 하는 이유는 호라이즌api 로직을 거칠 때 시간이 너무 오래결러서 빠르게 처리하기 위함이다.

그러니까 정확히 내가 저장하고 싶은 정보는 행성 대접근 이벤트인거고,

행성 대접근 이벤트에 대한 정보를 요청했을 때 요청한 정보와 일치하는 DB가 있다면 그걸 꺼내서 보여주고 싶은게 목적

을 기억하고 테이블 구조를 짜보자고.

라고 하려고 했는데 가만 생각해보니까, 행성이 거리 메서드를 그냥 만들어버려서 이걸 1년치를 저장해두고 재활용하는편이 좋을 것 같다는 생각이 들었다.

그러면 지금 해놓은 위치 정보 자체도 필요도 없을 것이고 행성간의 거리만 측정해두면 되는거니까.

그리고 문제가 되었던 horizon API 호출을 미리 계산해서 저장을 해두니까 지금 만들어둔 메서드는 horizon에서 뽑아둔걸 빼와서 쓰면 되는 것이다.


DB 테이블 생성.

하는 와중에 xampp에서 사용하는 marimbaDB 버전 이슈? 뭔지도 모르겠다. 여튼 터미널로 업그레이드 경로 찾고 업그레이드 해서 이제는 문제 없고..

SET GLOBAL event_scheduler = ON;

-- 데이터베이스 삭제 및 생성
DROP DATABASE IF EXISTS `STAR_INFO_API_DB`;
CREATE DATABASE `STAR_INFO_API_DB`;
USE `STAR_INFO_API_DB`;

CREATE TABLE IF NOT EXISTS planet_opposition_events (
    id INT AUTO_INCREMENT PRIMARY KEY,
    planet_name VARCHAR(255) NOT NULL,
    date DATE NOT NULL,
    distance FLOAT NOT NULL
);

이렇게 생성해줬다.


이제 저장 로직을 보자면.

POST 요청과 GET 요청을 처리한다는 느낌으로 생각하면 된다. (실제로도 그렇다.)

@main.route('/calculate_store_event', methods=['GET'])
def calculate_store_event_endpoint():

@main.route('/fetch_event', methods=['GET'])
def fetch_event_endpoint():

엔드포인트는 그래서 이 두개고, 로직도 이렇게 해서 DB에 접근하도록 일단은 구현해뒀다.

그리고 이제 Horizon API에서 뽑아온 지구와 해당 행성의 거리가 저장이 되는가 확인을 해봐야한다.

그래서 의기양양하게 서버를 켰는데 오류뜸.

DB 연결한다고 가상환경에 이것저것 설치를 해준게 문제가 된 것 같다.

GPT한테 물어보니까 Dockerfile이 실행될 때 설치되도록 코드 작성을 하라고 했다.

# 필요한 시스템 패키지 설치
RUN apt-get update && apt-get install -y \
    pkg-config \
    libmysqlclient-dev

그래서 해당 문구를 넣어줬다.

근데 보면 내가 설치해준 적 없는 라이브러리라 저게 왜 필요한지 궁금했다.

그래서 알아보니까

mysqlclient 라이브러리가 종속성을 필요로 한다.

pkg-configlibmysqlclient-dev 패키지가 필요한 이유는 mysqlclient 라이브러리가 특정 시스템 종속성을 필요로 하기 때문. 아래에서 각각의 이유를 설명:

  1. pkg-config:

    • pkg-config는 여러 패키지의 경로와 컴파일 정보를 제공하는 도구. mysqlclient 라이브러리를 설치할 때 의존 라이브러리의 경로나 플래그 등을 pkg-config로 확인함. 컴파일 단계에서 필요한 정보들을 제공. 이게 설치돼 있어야 파이썬 패키지를 정상적으로 설치할 수 있음.
  2. libmysqlclient-dev:

    • mysqlclient는 MySQL에 연결하기 위한 C 기반의 라이브러리인 libmysqlclient에 의존하고 있음. 그런데 slim 이미지에는 이 라이브러리가 설치돼 있지 않기 때문에, libmysqlclient-dev를 설치해줘야 파이썬에서 mysqlclient 라이브러리를 설치하고 사용할 수 있음. 이 패키지에는 MySQL 서버와 통신하는 데 필요한 헤더 파일과 라이브러리가 들어 있음.

그니까 대충 말하면 내가 프로젝트에 DB를 연결하게 되면서 필요한 도구들이 생겼다는 것이다.


여튼 다시 본론으로 돌아가서 서버를 켜보자고.


그럴려고 했는데 또 필요한게 생겨서 추가..

# 필요한 시스템 패키지 설치
RUN apt-get update && apt-get install -y \
    pkg-config \
    libmariadb-dev-compat \
    libmariadb-dev \
    gcc \ # mysqlclient 빌드에 필요한 컴파일러.
    build-essential #build-essential: 컴파일에 필요한 도구 모음.

무슨 DB 추가 했다고 이렇게 필요한게 많냐..

이제 서버 켜지는데 1분이 넘어가네 ㅋㅋㅋㅋ 그래도 정상적으로 켜진다 이제.

진짜 본론으로 돌아가서 요청해보자.

일단은 요청은 해봤고, 보면 데이터 뽑아오는 것 까지 되고 로그는 해당 메서드가 실행이 완료 되었다는거고,

DB에는 안들어갔다 ㅠ

만들고 보니까 planet_name도 나누는게 좋을 것 같긴하다.

우선 DB연결 성공!이라는 로그도 뜨지 않은 것을 보니까 여기가 문제가 있는 것 같다.

좀 알아보니까 도커에서 또 따로 DB와 연결될 수 있게 설정이 필요하다는 것을 알아냈다.

지금까지 그냥 Dockerfile로 실행시켜주고 있었는데 이런 설정들을 추가해주려면 docker-compose.yml로 실행시켜줘야한다고 한다..

일단은 기존의 설정들을 가져와서 정상 작동이 되는가 확인하고 이후에 DB 설정까지 넣는 식으로 진행해야될 것 같다.

오케이 정상 작동 확인했고, 이제 DB 설정 추가해보자.

요청을 해봤고 처음엔 DB 연결이 제대로 이루어지지 않는 줄 알았는데, 코드 변경 없이 로그를 더 상세하게 찍어보고 시도를 다시 해봤다.

그러니까 보이는 문제가 데이터 타입이 맞지않아서 생긴 문제였다.

문제의 이유

그러니까 지금 문제가 데이터 타입이 맞지 않아서인데 왜 이런 문제가 발생했냐하면, 지금 AU 값을, 그러니까 distance에 저장되는 데이터가 float으로 저장된다. 왜? AU는 1.??? 이런 식이기 때문에 그렇게 설계를 했다.
그런데 이 데이터 타입 변환 로직에서 약간 문제가 있는 것 같다.

그래서 이 값들을 그대로 넣어주는게 아니라

        cursor.execute('''
            INSERT INTO planet_opposition_events (planet_name, date, distance)
            VALUES (%s, %s, %s)
        ''', (planet_name, event_date.strftime('%Y-%m-%d'), float(distance)))
        conn.commit()

이건 이거다 라고 명시를 해줘봤다.

그래도 안되네.

일단 문제는 확실히 소수점이 문제다. 오류 메세지가 세번째 인자에 문제가 있다고 하고 있으니까.

그래서 조금 더 면밀하게 계속 살펴보다가 문득 든 생각이 float이 소수점 몇자리까지 지원하지? 였다.

mysql 5.0 이상 버전 기준으로 이렇다고 한다.

그러니까 지금 내가 저장할 값은. distance=4.43499427104088이다. 몇자리지? 14자리다. 아마 이거 때문에 float과 충동한게 아닐까? 정확하지는 않지만 예상을 해봤다. DOUBLE 타입은 16자리니까.. 일단 테이블에서 DOUBLE로 바꿔서 진행해보자.

그렇게 해도 안되네.


그래서 그냥 지금 mysqlconnector을 사용중이였는데 pymysql 로 변경해주는 식으로 가보기로 했다.

version: '3.8'

services:
  app:
    build: .
    container_name: star-info-api-container_compose
    ports:
      - "5555:5000"
    environment:
      - PYTHONUNBUFFERED=1
    volumes:
      - .:/app
      - ./config.yml:/app/config.yml  # config.yml 파일을 컨테이너에 마운트
    command: ["python", "run.py"]
    depends_on:
      - mysql_db  # MySQL 서비스가 먼저 시작되도록 설정

  mysql_db:
    image: mariadb:10.4
    container_name: mysql_container
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD:
      MYSQL_DATABASE: STAR_INFO_API_DB

도커에 새로운 설정이 필요했고.

database:
  user: root
  password:
  host: mysql_db
  port: 3306
  database: STAR_INFO_API_DB

여기서도 다시 맞춰주고..

실행해봤다.


계속 비밀번호를 못읽어서 진짜 계속 설정 만지고 터미널에서 도커 서버로 DB 접속해보고 온갖 별의 별 걸 다 해봤다.

근데 이거 하나로 해결됐다.

비번이 숫자여서 숫자를 입력해뒀는데 ""로 감쌌어야했다..

이것도 해결했고 DB로드도 전역으로 설정해서 필요할 때만 빼와서 쓸 수 있게 했고..

그런데도 계속

2024-10-17  4:31:14 16 [Warning] Access denied for user 'root'@'localhost' (using password: NO)
2024-10-17T04:31:24.738498545Z 2024-10-17  4:31:24 17 
[Warning] Access denied for user 'root'@'localhost' (using password: NO)

10초간격으로 뜨는 이 로그는 날 미치게 만들었다.

진짜 파고 파고 계속 파다보니까.

version: '3.8'

networks:
  my_network:  # 네트워크 정의
    driver: bridge

services:
  app:
    build: .
    container_name: star-info-api-container_compose
    ports:
      - "5555:5000"
    environment:
      - PYTHONUNBUFFERED=1
      - PYTHONPATH=/app  # PYTHONPATH 설정 추가
    volumes:
      - .:/app
      - ./config.yml:/app/config.yml  # config.yml 파일을 컨테이너에 마운트
    command: ["python", "run.py"]
    depends_on:
      mysql_db:
        condition: service_healthy
    networks:
      - my_network  # 네트워크 설정 추가

  mysql_db:
    image: mariadb:10.4
    container_name: mysql_container
    ports:
      - "3307:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "1234"  # 비밀번호는 문자열로 지정
      MYSQL_DATABASE: STAR_INFO_API_DB
    volumes:
      - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d  # 초기화 스크립트 마운트
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p1234" ]
      interval: 10s
      retries: 3
    networks:
      - my_network  # 네트워크 설정 추가

애진작에 여기서 비번을 태워 보냈어야했다.

하,.,,, 여튼 해결 했으니까 다시 원래 우리의 목적에 맞게 돌아가자.


2024-10-17T04:38:31.951887631Z ERROR:root:==DB 작업 중 에러 발생==: (1146, "Table 'STAR_INFO_API_DB.planet_opposition_events' doesn't exist")

이번엔 테이블이 없다고 그런다.

근데 테이블은 분명히 있긴하다.

여기 있지않은가?/???


제대로 이해를 했다. 현재 난 도커를 사용중이고 DB를 도커 서버로 컨테이너를 생성해서 사용중이였다.

그런데 내가 프로젝트에 연결한 DB는 컨테이너에 생성한 DB가 아닌, 내 로컬 DB를 연결해둬서 접근이 되지 않았던 것이고 테이블도 생성되지 않았던 것이다. 그래서 터미널에서 접근할 시에는 DB가 존재했고 테이블은 존재하지 않았다. 이를 더 쉽게 관리하기 위해서,

여기서 설정할 때 포트를 도커에서 사용중인 포트로 변경해주었고 이제 쿼리를 컨트롤 해봤을 때 제대로 작동하는지와 도커 서버를 껐을 때 작동을 하는지를 체크해보니까.

도커 서버가 꺼지면 당연하게도 DB 접근은 불가능했다.

이제 DB 접근이 진짜 제대로 된다고 생각을 하고 DB 테이블을 생성한 뒤에 요청을 보내보니까.

왜 안되는지 확인하기 위해서 찍었던 로그들도 많이 찍히고..

제일 중요한 DB에도 찍혀있다.

난 아주 큰 데이터를 다뤄야해서 개발단계이지만 영속성을 부여했다.

볼륨에 영구저장 된다는 뜻이다.

오늘을 기점으로 모든 행성 데이터 1년치를 일단 다 넣어둘 생각이다.

여튼... 해결 했다. 도커에 대한 이해력이 올라갔다!!

히히.. 재밌다.. 근데 힘들다..