docker non-root and healthcheck fix
This commit is contained in:
@@ -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"]
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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})"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user