o2o-negosium-original/lps/Dockerfile.worker
민헌 a267326bf7 fix(lps): Docker 이미지 무시크릿화 + 배포 견고화 — 리뷰 발견사항 일괄 적용
시크릿 유출 차단(핵심):
- config.local.toml(OpenAI·DECODO·네이버 키)이 COPY . . 로 이미지에
  구워지던 문제 — .dockerignore 제외 + 빌드 시 example(플레이스홀더)
  복사로 대체. 실값은 compose env 주입(리포 루트 .env, 템플릿 .env.example)
- DECODO_PORT_START/END/SESSION_MINUTES env override 추가 — 포트가
  toml(플레이스홀더 0)에만 있으면 자격증명을 넣어도 프록시가 조용히
  꺼지는 구멍 봉합

배포 견고화:
- API Dockerfile 에 HEALTHCHECK(/healthz) 추가
- autoheal 컨테이너 추가 — compose restart 는 unhealthy 를 재시작하지
  않으므로 라벨(autoheal=true) 기반 자동 재시작 담당
- 이미지 python 3.12→3.14 정렬(로컬 개발·테스트 환경과 일치)
- API 이미지 경량화: requirements-api.txt 분리(크롤 의존성 제거, 330MB)

검증: 양 이미지 빌드 성공, 이미지 내 시크릿·.profiles 부재 확인,
무시크릿 API 이미지 스모크(healthz/readyz/HEALTHCHECK healthy) 통과

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 11:53:47 +09:00

39 lines
2.1 KiB
Docker

# LPS 워커 이미지 — 크롤용 **헤드풀 Chromium + 가상 디스플레이(Xvfb)**.
# headless Chrome 은 Akamai(쿠팡)·Cloudflare Turnstile(G마켓/옥션)에 탐지돼 통과 못 함(실측 확인).
# → 컨테이너에선 Xvfb(가상 프레임버퍼)로 headful Chromium 을 실행한다.
#
# 빌드/실행:
# docker compose build lps-worker && docker compose up -d lps-worker
# 스텔스 참고: 로컬 Mac 은 실제 Chrome(channel=chrome), 컨테이너는 시스템 chromium(executable_path).
# 프로덕션에서 stealth 가 부족하면 amd64 이미지에 google-chrome-stable 설치 후 LPS_CHROME_CHANNEL=chrome 로 전환.
FROM python:3.14-slim
# chromium(런타임 의존성 apt 가 자동 해결) + Xvfb + 한글 폰트
RUN apt-get update && apt-get install -y --no-install-recommends \
chromium xvfb xauth fonts-nanum ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# 시크릿 든 config.local.toml 은 .dockerignore 로 제외됨 → example(플레이스홀더)로 대체.
# 실값은 compose env 로 주입: DB_*, OPENAI_API_KEY, DECODO_*(포트 포함), NAVER_KEYS.
RUN cp config/config.local.toml.example config/config.local.toml
ENV APP_ENV=local \
PYTHONUNBUFFERED=1 \
LPS_CHROME_EXECUTABLE=/usr/bin/chromium \
DISPLAY=:99 \
LPS_HEARTBEAT_FILE=/tmp/lps_worker_heartbeat
# 하트비트 신선도(<120s)로 행/좀비 워커 감지. start-period 는 웜업(브라우저 기동) 여유.
HEALTHCHECK --interval=30s --timeout=8s --start-period=120s --retries=3 \
CMD python -c "import os,time,sys; p=os.environ['LPS_HEARTBEAT_FILE']; sys.exit(0 if os.path.exists(p) and time.time()-os.path.getmtime(p)<120 else 1)"
# Xvfb(가상 디스플레이)를 백그라운드로 띄우고 python 을 exec 로 승계 실행.
# → 헤드풀 Chromium 이 :99 에 뜨고, 워커 로그는 그대로 docker logs 로 나온다(xvfb-run 은 로그를 삼킴).
CMD ["bash", "-c", "Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp >/dev/null 2>&1 & sleep 1; exec python worker_main.py"]