본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 15. 05:22

【Python】『뉴스 요약 사이트』를 만들어 보았다 (실전 편) ㉑

요약

Python으로 제작한 뉴스 요약 사이트를 Render 플랫폼에 배포하는 과정을 다룹니다. Windsurf 에러 해결 과정과 함께 Render 환경에서의 스케줄러, 데이터 저장, 환경 변수 설정 등 실전 배포 시 고려해야 할 핵심 사항을 정리했습니다.

핵심 포인트

  • Windsurf 사용 중 발생하는 권한 거부(Permission denied) 이슈 경험
  • Render 배포 시 Windows 작업 스케줄러 대신 Cron Job 사용 필요
  • Render 무료 플랜의 휘발성 디스크 문제를 고려한 데이터 저장 전략 필요
  • GitHub Push 및 Render 환경 변수 설정 등 배포 워크플로우 정리

로컬 환경에서 동작하는 사이트가 완성되었습니다.

이번부터는 Render로 배포(Deploy)하는 흐름으로 넘어갑니다!

Windsurf인데, 뭔가 조금 부탁하기만 해도 엄청나게 에러가 나네요…….

Windsurf에서 흔히 있는 일이라고 합니다. 다들 어떻게 하고 계신 걸까요…….

"코드는 필요 없습니다"라고 말해도, 계획을 생각하면서 무심코 파일을 건드리러 가버리는 것이 Cascade의 버릇이라고 합니다.

Cascade 패널을 Chat 모드로 설정하면 좋다고 하는데, 그래도 Permission denied(권한 거부)가 뜨고 있습니다.

폴더 액세스 권한도 문제없어 보이는데 말이죠~

갑자기 잘 될 때도 있어서 어떻게든 해결해가며 진행했지만, 시간이 나면 조사를 해보고 싶은 기분입니다.

영원히 이 에러가 나와서 정말 짜증 났습니다…….

이 에러를 조사하다 보니, 취지는 다를지 모르지만 이번 일련의 이야기에서 언급된 3가지 툴에 관한 기사가 있어서 조금 남겨둡니다.

【Windsurf로 vibe Coding을 했더니 액세스 제한이 걸렸다】

Render로의 배포 계획을 묻기 위해, 지난번 기사에서도 정리했던 과제들을 해결하면서 진행합니다.

【Render 이행 시 대응이 필요한 것들】

▼ 작업 스케줄러 (Task Scheduler)

Windows 작업 스케줄러는 Render 상에서 사용할 수 없습니다.

Render의 스케줄 기능 (Cron Job)으로 전환이 필요합니다.

▼ 데이터 저장

Render의 무료 플랜은 로컬 디스크가 휘발될 수 있습니다.

JSON 파일의 저장소를 영구 스토리지(Persistent Storage)로 이전해야 할 가능성이 있습니다.

▼ 환경 변수 (Environment Variables)

.env에 작성했던 Gemini API 키 등은 Render의 관리 화면에서 다시 설정해야 합니다.

Windsurf에게 과제를 의식한 계획을 세워달라고 부탁했습니다.

부탁한 결과는 다음과 같습니다.

*******************

  • GitHub 리포지토리(Repository)를 생성하여 코드 푸시(Push)
  • .gitignore.env가 제외되었는지 확인 (API 키를 실수로 공개하지 않기 위해 중요)
  • Render 대시보드에서 "New Web Service" 생성
  • GitHub 리포지토리 연결
  • 빌드 커맨드(Build Command):
    pip install -r requirements.txt
  • 스타트 커맨드(Start Command):
    python run.py
  • .env.example을 참고하여 환경 변수 설정

Windows 작업 스케줄러 대신 Render의 Cron Jobs를 사용합니다.

  • Render에서 "New Cron Job" 생성
  • 커맨드(Command):
    python run_batch.py
  • 스케줄: 매일 6시 (UTC) ※ 일본 시간으로는 15시에 해당하므로 주의 필요
  • Web Service가 정상적으로 기동되는지 확인
  • Cron Job이 정상적으로 실행되는지 확인

Render의 파일 시스템은 배포할 때마다 리셋됩니다.

현재는 JSON 파일로 저장하고 있기 때문에, 이대로라면 기사 데이터가 사라지게 됩니다.

대책으로는 Render Disk (유료) 또는 외부 스토리지 (S3 등)로의 이전이 필요합니다.

우선 실행해 보고, 이 문제는 나중에 대처하는 방침으로 진행하겠습니다.

*******************

위의 과제와 해야 할 일을 정리하여 표로 만들어 둡니다.

Step내용위치 및 대응 과제
Step 1GitHub 준비 (리포지토리 생성 · .gitignore 확인)배포 전 사전 준비
Step 2Render Web Service 생성 · 환경 변수 설정▼ 환경 변수: .env의 API 키를 Render 관리 화면에서 다시 설정
Step 3Render Cron Job 설정 (매일 6시 UTC 실행)▼ 작업 스케줄러: Windows 작업 스케줄러에서 Render Cron Job으로 전환
Step 4Web Service · Cron Job 동작 확인배포 후 동작 확인
Step 5데이터 영속화 검토 (Render Disk 또는 S3 등)▼ 데이터 저장: JSON 저장소를 영구 스토리지로 이전

"이 계획대로 진행해 주세요"라고 답하고 구현으로.

Cascade가 코드의 배포 준비를 해주었습니다.

【변경 내용】

run.py를 Render 대응으로 업데이트.

host="0.0.0.0"

및 PORT 환경 변수(environment variable)를 사용하도록 수정해 주었습니다.

【자동으로 체크해 준 내용】

  • .gitignore : .env가 제외됨 (API 키가 실수로 GitHub에 올라가지 않는지 확인)
  • run_batch.py : Render 호환성 있음
  • requirements.txt : Render에서 문제 없음
  • .env.example : 필요한 환경 변수가 포함되어 있음

【데이터 영속화(Data Persistence)의 과제】

현재 구현에서는 JSON 파일을 로컬의 data/ 폴더에 저장하고 있습니다.

Render의 파일 시스템은 배포(deploy)할 때마다 리셋되기 때문에, 이대로 두면 기사 데이터가 사라지게 된다고 합니다.

나중에 검토할 여지가 있다고 하네요.

포트 환경 변수? 라고 하길래 찾아보았습니다.

IT 계열에 거부감이 있는 사람은 '환경 변수'라는 단어와 친구가 될 수 있을 것 같지 않거든요!!

【PORT 환경 변수】

"이 앱은 몇 번 포트(port)에서 대기합니까?"라는 번호를 말합니다.

Render에 배포하면, 앱이 사용할 포트 번호를 Render 측에서 매번 알아서 결정합니다. 코드에 번호를 고정해서 적어버리면 동작하지 않기 때문에, "Render로부터 번호가 전달되면 그것을 사용하고, 그렇지 않으면 ○○○번을 사용한다"라는 방식으로 작성법을 변경할 필요가 있다고 합니다. 이와 함께 host="0.0.0.0"을 설정함으로써 외부에서의 액세스도 받아들일 수 있도록 되어 있습니다.

다시 한번, 향후 흐름을 확인하겠습니다.

위의 내용으로 구현을 해주었지만, 어디까지나 기존의 것을 Render 사양으로 만들어 준 것뿐입니다. Windsurf에게 맡기지 않는 부분의 작업이 다수 있습니다. 사람이 수동으로 해야만 하는 부분입니다.

그것을 하나씩 대응해 나가겠습니다.

【향후 흐름】

  • Git 초기 설정
  • GitHub로 푸시(push)
  • Render로 배포(deploy)
  • Cron Job 설정 (그리고 막혔던 이야기)

위에서부터 순서대로 처리하겠습니다.

터미널에서 다음을 실행합니다.

cd C:\dev\news-digest
git init

git init은 "이 폴더를 Git으로 관리하기 위한 준비를 한다"는 명령어입니다.

실행하면 .git이라는 숨김 폴더가 생성되며, 이후부터 파일의 변경 이력을 기록할 수 있게 됩니다.

【지금부터 나올 용어 간단 설명】

Git: 코드의 변경 이력을 관리하는 도구

커밋 (Commit): "이 상태로 저장"이라는 기록을 남기는 조작

푸시 (Push): 로컬의 기록을 GitHub로 보내는 조작

리포지토리 (Repository): 코드와 그 이력을 모아서 두는 장소 (GitHub에서 말하는 프로젝트 폴더)

git commit을 실행했더니, 이런 에러가 나왔습니다.

Author identity unknown
*** Please tell me who you are.

Git에게 "누가 커밋했는지"를 알려줄 필요가 있습니다.

GitHub에 등록한 이메일 주소와 사용자 이름을 설정합니다.

git config --global user.email "GitHub의 이메일 주소"
git config --global user.name "GitHub의 사용자 이름"

설정했다면 다시 커밋합니다.

git add .
git commit -m "first commit"

GitHub에서 리포지토리를 생성하고, 다음 명령어로 푸시합니다.

git remote add origin https://github.com/사용자명/리포지토리명.git
git branch -M main
git push -u origin main

그러자, 다음과 같이 한꺼번에 푸시되었습니다!

GitHub 조작은 일단 이것으로 일단락입니다.

로컬에서 GitHub로 코드를 푸시했으므로, 이 다음에 Render의 환경을 정비함으로써 Render가 해당 GitHub 리포지토리를 읽어 들여 자동으로 배포하는 흐름이 됩니다.

Render를 사용하여 외부 공개를 함으로써, 자신의 PC를 켜두지 않아도 URL만 있으면 어디서든 앱에 액세스할 수 있는 상태가 됩니다.

처음 사용하는 것이므로, 계정 생성부터 실시하겠습니다.

https://render.com에 접속하여, GitHub 계정으로 연동하여 계정을 생성했습니다.

image.png

대시보드에서 "New +" → "Web Service"를 선택합니다.

image.png

처음에는 「No repositories found」라고 표시되어 있습니다.

화면 하단의 「GitHub」 버튼을 눌러, Render에 GitHub 리포지토리 (Repository) 접근 권한을 허용합니다.

연동 시 「모든 리포지토리」인지 「리포지토리만 선택」할 것인지 묻습니다.

보안 측면에서 리포지토리만 선택하는 것을 추천한다고 합니다.

연동이 완료되면 리포지토리가 목록에 표시되므로 선택합니다.

그대로 설정 항목을 채워 나갑니다.

예시는 다음과 같은 내용입니다.

항목설정
빌드 커맨드 (Build Command)pip install -r requirements.txt
....env.example을 참고하여 설정

Environment Variables (환경 변수) 섹션에서 GEMINI_API_KEY를 추가하고, 실제 API 키를 value에 입력합니다.

.env 파일은 Render에 존재하지 않으므로, 여기서 다시 설정할 필요가 있다는 뜻이군요!

.env 파일은 .gitignore에 넣어두었기 때문에 GitHub에는 업로드되지 않았습니다!

업로드하면 API 키가 그대로 노출되어 여러모로 곤란해진다는 점은 이전 기사에서 정리한 바와 같습니다.

확실히 업로드되지 않았음을 나중에 육안으로도 확인했습니다 ◎

여기까지 완료했다면 「Create Web Service」를 클릭하면 배포 (Deploy)가 시작됩니다.

로그에 빨간색 WARNING이 뜨지만, Flask가 정상적으로 기동하고 있다는 신호이므로 에러가 아닙니다.

image.png

(로컬 개발 중에도 똑같은 경고가 떴었죠)

「Live」라고 표시되면 성공입니다!

이것으로 Render로의 배포가 완료되었고, 앱이 인터넷상에 공개된 셈이네요!

다음은 「매일 아침 자동으로 뉴스를 가져오고 업데이트하는」 구조를 만듭니다.

기껏 공개했더라도 수동으로 업데이트한다면 자동화의 의미가 없습니다.

여기서 문제가 되는 것이 개발 중에 설정했던 Windows 작업 스케줄러 (Task Scheduler)입니다.

당초 예상했던 대로군요.

작업 스케줄러는 어디까지나 자신의 PC 상에서 동작하는 구조이므로, Render라는 완전히 다른 서버 상의 앱에는 영향을 줄 수 없습니다.

즉, 다시 Render 측에서 자동 실행 설정을 할 필요가 있습니다.

Render에는 Cron Job이라는 정기 실행 기능이 있으므로, 이것을 사용하여 매일 아침 6시에 자동 실행할 수 있는지 시도해 보겠습니다.

Render에는 Cron Job이라는 기능이 있습니다.

이번에 하고 싶은 일을 이루려면 이 기능을 사용할 필요가 있어 보입니다.

Cron Job은 지정한 시간에 자동으로 커맨드를 실행해 주는 기능입니다.

예를 들어:

  • 「매일 아침 6시에 뉴스 취득 스크립트를 실행한다」
  • 「매주 월요일에 데이터를 집계한다」

와 같은 정기 실행을 Render 서버 상에서 할 수 있습니다.

작성 방식은 0 21 * * *와 같은 기호로 시간을 지정합니다 (이것은 매일 21시 UTC = 일본 시간 아침 6시라는 의미입니다).

Linux 서버를 운용 보수했을 때 Cron을 자주 사용했기에 바로 감이 옵니다.

(Render 서버는 Linux 상에서 동작한다고 합니다)

기시감이 있어서 간단히 설정할 수 있겠는데♪ 하며 음표까지 붙여 의기양양하게 설정하려고 했더니…….

image.png

신용카드 등록 화면이 나오는데?

아무래도 무료 플랜에서는 Cron Job을 사용할 수 없는 모양입니다.

젠장, 다들 돈을 받아먹는구먼…… 비즈니스니까…… 어쩔 수 없지…….

다른 선택지를 생각할 수밖에 없습니다.

선택지를 정리해 보겠습니다.

방법내용비용
① GitHub를 경유한다JSON을 GitHub에 푸시 (Push) → Render가 GitHub에서 읽어옴무료
...

무료로 계속하려면 ①번 GitHub 경유가 가장 현실적인 것 같습니다.

당초 GitHub는 경유하지 않기로 결정했었지만, 어쩔 수 없네요…….

【GitHub를 경유하지 않기로 했던 이유】

사용하지 않기로 판단한 이유는 커밋 히스토리 (Commit History)가 불필요하게 늘어나는 등의 이유 때문이었습니다. 뉴스 데이터의 JSON은 매일 자동으로 생성되는 파일입니다. 코드의 변경 이력을 관리하기 위한 Git에 매일 데이터 파일이 쌓여가는 것은 "용도에 맞지 않는다"라고 볼 수 있습니다. 이는 설계의 아름다움을 우선시한 판단이었다고 합니다.

이번에 OK라고 판단한 이유는 "무료로・심플하게・작동하는 것"이며, "정답은 아니지만, 현실적으로 문제가 없는" 방향으로 시프트 체인지(Shift change)를 하고 있는 듯합니다.

파트너(AI)에게 물어보니 "이상적인 설계와 현실의 트레이드오프 (Trade-off)"라는 멋진 말을 해주었습니다. GitHub는 업무에서 사용해 본 적이 없고, 아직 자세한 부분까지 깊게 파고들어 본 적은 없어서, 언젠가 제대로 공부해 두고 싶은 부분입니다.

매일 아침 JSON 생성과 GitHub로의 푸시(Push)를 자동화하는 .bat 파일을 생성하여, Windows 작업 스케줄러(Windows Task Scheduler)에 등록하는 방식으로 진행하겠습니다.

여러 가지로 조사해 본 결과, 다음과 같은 내용으로 진행하는 것이 좋을 것 같습니다.

《해결책》 작업 스케줄러 + GitHub 푸시

흐름을 시각화해 둡니다. 무엇이든 시각화하는 것. 중요합니다.

매일 아침 6시 (자동)
Windows 작업 스케줄러
→ fetch_rss_digest.py 로 JSON 생성
...

Render의 무료 플랜은 푸시(Push)할 때마다 자동으로 배포(Deploy)되는 설정으로 되어 있어서, GitHub에 푸시하는 것만으로 Render도 자동으로 업데이트된다고 합니다. 정말 좋네요…….

이 메커니즘의 구현은 다음 회차부터 진행하겠습니다.

Windows 작업 스케줄러 + GitHub 푸시를 조합하여,

매일 아침 자동으로 Render를 업데이트하는 메커니즘을 만듭니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0