docker non-root and healthcheck fix

This commit is contained in:
qananasikq
2026-04-10 15:14:04 +03:00
parent 3870cf4d94
commit 18dab6d48d
3 changed files with 41 additions and 8 deletions

View File

@@ -3,12 +3,17 @@ FROM mcr.microsoft.com/playwright/python:v1.58.0-noble
ENV PYTHONDONTWRITEBYTECODE=1 \ ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 PYTHONUNBUFFERED=1
RUN groupadd --system app && useradd --system --gid app --create-home app
WORKDIR /app WORKDIR /app
# Xvfb for headed Chromium in container (IAAI blocks headless) # Xvfb for headed Chromium in container (IAAI blocks headless)
RUN apt-get update -qq && apt-get install -y --no-install-recommends xvfb \ RUN apt-get update -qq && apt-get install -y --no-install-recommends xvfb \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Required for non-root Xvfb runtime in containers
RUN mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix
COPY pyproject.toml uv.lock ./ COPY pyproject.toml uv.lock ./
RUN pip install --no-cache-dir uv \ RUN pip install --no-cache-dir uv \
&& uv export --format requirements-txt --no-dev --no-hashes --no-emit-project --frozen -o /tmp/requirements.txt \ && uv export --format requirements-txt --no-dev --no-hashes --no-emit-project --frozen -o /tmp/requirements.txt \
@@ -17,9 +22,12 @@ RUN pip install --no-cache-dir uv \
COPY . . COPY . .
RUN python -m compileall -q iaai_scraper RUN python -m compileall -q iaai_scraper
RUN chmod +x entrypoint.sh RUN chmod +x entrypoint.sh
RUN chown -R app:app /app
STOPSIGNAL SIGINT STOPSIGNAL SIGINT
USER app
# По умолчанию API, но worker/beat переопределяют CMD в docker-compose # По умолчанию API, но worker/beat переопределяют CMD в docker-compose
ENTRYPOINT ["./entrypoint.sh"] ENTRYPOINT ["./entrypoint.sh"]
CMD ["uvicorn", "iaai_scraper.api.app:app", "--host", "0.0.0.0", "--port", "8000"] CMD ["uvicorn", "iaai_scraper.api.app:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -121,6 +121,7 @@ services:
<<: *worker-service <<: *worker-service
container_name: iaai-worker container_name: iaai-worker
restart: unless-stopped restart: unless-stopped
init: true
depends_on: depends_on:
migrate: migrate:
condition: service_completed_successfully condition: service_completed_successfully
@@ -130,13 +131,14 @@ services:
command: > command: >
celery -A iaai_scraper.worker.celery_app worker celery -A iaai_scraper.worker.celery_app worker
--loglevel=info --concurrency=1 --pool=prefork --loglevel=info --concurrency=1 --pool=prefork
--pidfile=/tmp/celery-worker.pid
-Q scraping --max-tasks-per-child=20 -Q scraping --max-tasks-per-child=20
healthcheck: healthcheck:
test: ["CMD", "celery", "-A", "iaai_scraper.worker.celery_app", "inspect", "ping", "-d", "celery@$$HOSTNAME"] test: ["CMD-SHELL", "test -f /tmp/celery-worker.pid && kill -0 $(cat /tmp/celery-worker.pid)"]
interval: 60s interval: 60s
timeout: 20s timeout: 10s
retries: 3 retries: 3
start_period: 40s start_period: 90s
logging: logging:
driver: json-file driver: json-file
options: options:
@@ -148,6 +150,7 @@ services:
<<: *worker-service <<: *worker-service
container_name: iaai-beat container_name: iaai-beat
restart: unless-stopped restart: unless-stopped
init: true
depends_on: depends_on:
migrate: migrate:
condition: service_completed_successfully condition: service_completed_successfully
@@ -156,12 +159,14 @@ services:
command: > command: >
celery -A iaai_scraper.worker.celery_app beat celery -A iaai_scraper.worker.celery_app beat
--loglevel=info --loglevel=info
--pidfile=/tmp/celery-beat.pid
--schedule=/tmp/celerybeat-schedule
healthcheck: healthcheck:
test: ["CMD", "python", "-c", "import pathlib,sys; p=pathlib.Path('/tmp/celerybeat-schedule'); sys.exit(0 if p.exists() else 1)"] test: ["CMD-SHELL", "test -f /tmp/celery-beat.pid && kill -0 $(cat /tmp/celery-beat.pid)"]
interval: 60s interval: 60s
timeout: 20s timeout: 10s
retries: 3 retries: 3
start_period: 60s start_period: 90s
logging: logging:
driver: json-file driver: json-file
options: options:

View File

@@ -63,15 +63,35 @@ start_xvfb_if_needed() {
# IAAI blocks headless Chromium on Linux; run headed via Xvfb virtual display # IAAI blocks headless Chromium on Linux; run headed via Xvfb virtual display
export DISPLAY=:99 export DISPLAY=:99
export IAAI_HEADLESS=false export IAAI_HEADLESS=false
local xvfb_pid_file="/tmp/xvfb-99.pid"
if [ -f "${xvfb_pid_file}" ]; then
local existing_pid
existing_pid="$(cat "${xvfb_pid_file}")"
if [ -n "${existing_pid}" ] && kill -0 "${existing_pid}" 2>/dev/null; then
echo "[entrypoint] Reusing existing Xvfb on DISPLAY=${DISPLAY} (PID ${existing_pid})"
return 0
fi
echo "[entrypoint] Removing stale Xvfb pid file"
rm -f "${xvfb_pid_file}"
fi
if [ -S /tmp/.X11-unix/X99 ] || [ -f /tmp/.X99-lock ]; then if [ -S /tmp/.X11-unix/X99 ] || [ -f /tmp/.X99-lock ]; then
echo "[entrypoint] Reusing existing Xvfb on DISPLAY=${DISPLAY}" echo "[entrypoint] Removing stale Xvfb socket/lock files for DISPLAY=${DISPLAY}"
return 0 rm -f /tmp/.X11-unix/X99 /tmp/.X99-lock
fi fi
Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp & Xvfb :99 -screen 0 1920x1080x24 -nolisten tcp &
XVFB_PID=$! XVFB_PID=$!
echo "${XVFB_PID}" > "${xvfb_pid_file}"
sleep 0.5 sleep 0.5
if ! kill -0 "${XVFB_PID}" 2>/dev/null; then
echo "[entrypoint] ERROR: Xvfb failed to start on DISPLAY=${DISPLAY}"
rm -f "${xvfb_pid_file}"
exit 1
fi
echo "[entrypoint] Xvfb started (PID ${XVFB_PID}, DISPLAY=${DISPLAY})" echo "[entrypoint] Xvfb started (PID ${XVFB_PID}, DISPLAY=${DISPLAY})"
} }