mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-02-20 13:16:03 +00:00
Compare commits
2 Commits
master
...
722-docker
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
423b201d6a | ||
|
|
839cf7fd9d |
18
Dockerfile
18
Dockerfile
@@ -86,6 +86,7 @@ LABEL org.opencontainers.image.licenses="Apache-2.0"
|
||||
LABEL org.opencontainers.image.vendor="changedetection.io"
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gosu \
|
||||
libxslt1.1 \
|
||||
# For presenting price amounts correctly in the restock/price detection overview
|
||||
locales \
|
||||
@@ -101,18 +102,29 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libxrender-dev \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create unprivileged user and required directories
|
||||
RUN groupadd -g 911 changedetection && \
|
||||
useradd -u 911 -g 911 -M -s /bin/false changedetection && \
|
||||
mkdir -p /datastore /extra_packages && \
|
||||
chown changedetection:changedetection /extra_packages
|
||||
|
||||
# https://stackoverflow.com/questions/58701233/docker-logs-erroneously-appears-empty-until-container-stops
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
RUN [ ! -d "/datastore" ] && mkdir /datastore
|
||||
# Redirect .pyc cache to a writable location since /app is root-owned.
|
||||
# To disable bytecode caching entirely, set PYTHONDONTWRITEBYTECODE=1 at runtime.
|
||||
ENV PYTHONPYCACHEPREFIX=/tmp/pycache
|
||||
# Disable pytest's .pytest_cache directory (also writes to /app, which is root-owned).
|
||||
# Only has an effect when running tests inside the container.
|
||||
ENV PYTEST_ADDOPTS="-p no:cacheprovider"
|
||||
# Redirect test logs to the datastore (writable) instead of /app/tests/logs (read-only in container).
|
||||
ENV TEST_LOG_DIR=/datastore/test_logs
|
||||
|
||||
# Re #80, sets SECLEVEL=1 in openssl.conf to allow monitoring sites with weak/old cipher suites
|
||||
RUN sed -i 's/^CipherString = .*/CipherString = DEFAULT@SECLEVEL=1/' /etc/ssl/openssl.cnf
|
||||
|
||||
# Copy modules over to the final image and add their dir to PYTHONPATH
|
||||
COPY --from=builder /dependencies /usr/local
|
||||
ENV PYTHONPATH=/usr/local
|
||||
ENV PYTHONPATH=/usr/local:/extra_packages
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
|
||||
@@ -39,8 +39,9 @@ def per_test_log_file(request):
|
||||
"""Create a separate log file for each test function with pytest output."""
|
||||
import re
|
||||
|
||||
# Create logs directory if it doesn't exist
|
||||
log_dir = os.path.join(os.path.dirname(__file__), "logs")
|
||||
# Create logs directory if it doesn't exist.
|
||||
# TEST_LOG_DIR can be overridden e.g. to a writable path when /app is read-only (Docker).
|
||||
log_dir = os.environ.get('TEST_LOG_DIR', os.path.join(os.path.dirname(__file__), "logs"))
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
# Generate log filename from test name and worker ID (for parallel runs)
|
||||
|
||||
@@ -9,6 +9,12 @@ services:
|
||||
# - ./proxies.json:/datastore/proxies.json
|
||||
|
||||
# environment:
|
||||
# Run as a specific user/group (UID:GID). Defaults to 911:911.
|
||||
# The container will automatically fix datastore ownership on first start if needed.
|
||||
# Set SKIP_CHOWN=1 to disable the ownership migration (e.g. if you manage permissions yourself).
|
||||
# - PUID=1000
|
||||
# - PGID=1000
|
||||
#
|
||||
# Default listening port, can also be changed with the -p option (not to be confused with ports: below)
|
||||
# - PORT=5000
|
||||
#
|
||||
@@ -80,8 +86,9 @@ services:
|
||||
# RAM usage will be higher if you increase this.
|
||||
# - SCREENSHOT_MAX_HEIGHT=16000
|
||||
#
|
||||
# HTTPS SSL Mode for webserver, unset both of these, you may need to volume mount these files also.
|
||||
# HTTPS SSL Mode for webserver, volume mount the cert files and set these env vars.
|
||||
# ./cert.pem:/app/cert.pem and ./privkey.pem:/app/privkey.pem
|
||||
# Permissions are fixed automatically on startup.
|
||||
# - SSL_CERT_FILE=cert.pem
|
||||
# - SSL_PRIVKEY_FILE=privkey.pem
|
||||
#
|
||||
@@ -95,6 +102,8 @@ services:
|
||||
ports:
|
||||
- 127.0.0.1:5000:5000
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
# Used for fetching pages via WebDriver+Chrome where you need Javascript support.
|
||||
# Now working on arm64 (needs testing on rPi - tested on Oracle ARM instance)
|
||||
|
||||
@@ -1,28 +1,68 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
set -eu
|
||||
|
||||
# Install additional packages from EXTRA_PACKAGES env var
|
||||
# Uses a marker file to avoid reinstalling on every container restart
|
||||
INSTALLED_MARKER="/datastore/.extra_packages_installed"
|
||||
CURRENT_PACKAGES="$EXTRA_PACKAGES"
|
||||
DATASTORE_PATH="${DATASTORE_PATH:-/datastore}"
|
||||
|
||||
if [ -n "$EXTRA_PACKAGES" ]; then
|
||||
# Check if we need to install/update packages
|
||||
if [ ! -f "$INSTALLED_MARKER" ] || [ "$(cat $INSTALLED_MARKER 2>/dev/null)" != "$CURRENT_PACKAGES" ]; then
|
||||
echo "Installing extra packages: $EXTRA_PACKAGES"
|
||||
pip3 install --no-cache-dir $EXTRA_PACKAGES
|
||||
# -----------------------------------------------------------------------
|
||||
# Phase 1: Running as root — fix up PUID/PGID and datastore ownership,
|
||||
# then re-exec as the unprivileged changedetection user via gosu.
|
||||
# -----------------------------------------------------------------------
|
||||
if [ "$(id -u)" = '0' ]; then
|
||||
PUID=${PUID:-911}
|
||||
PGID=${PGID:-911}
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "$CURRENT_PACKAGES" > "$INSTALLED_MARKER"
|
||||
echo "Extra packages installed successfully"
|
||||
else
|
||||
echo "ERROR: Failed to install extra packages"
|
||||
exit 1
|
||||
groupmod -o -g "$PGID" changedetection
|
||||
usermod -o -u "$PUID" changedetection
|
||||
|
||||
# Keep /extra_packages writable by the (potentially re-mapped) user
|
||||
chown changedetection:changedetection /extra_packages
|
||||
|
||||
# One-time ownership migration: only chown if the datastore isn't already
|
||||
# owned by the target UID (e.g. existing root-owned installations).
|
||||
if [ -z "${SKIP_CHOWN:-}" ]; then
|
||||
datastore_uid=$(stat -c '%u' "$DATASTORE_PATH")
|
||||
if [ "$datastore_uid" != "$PUID" ]; then
|
||||
echo "Updating $DATASTORE_PATH ownership to $PUID:$PGID (one-time migration)..."
|
||||
chown -R changedetection:changedetection "$DATASTORE_PATH"
|
||||
echo "Done."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fix SSL certificate permissions so the unprivileged user can read them.
|
||||
# SSL_CERT_FILE / SSL_PRIVKEY_FILE may be relative (to /app) or absolute.
|
||||
fix_ssl_perm() {
|
||||
local file="$1" mode="$2"
|
||||
[ -z "$file" ] && return
|
||||
[ "${file:0:1}" != "/" ] && file="/app/$file"
|
||||
if [ -f "$file" ]; then
|
||||
chown changedetection:changedetection "$file"
|
||||
chmod "$mode" "$file"
|
||||
fi
|
||||
}
|
||||
fix_ssl_perm "${SSL_CERT_FILE:-}" 644
|
||||
fix_ssl_perm "${SSL_PRIVKEY_FILE:-}" 600
|
||||
|
||||
# Re-exec this script as the unprivileged user
|
||||
exec gosu changedetection:changedetection "$0" "$@"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Phase 2: Running as unprivileged user — install any EXTRA_PACKAGES into
|
||||
# /extra_packages (already on PYTHONPATH) then exec the app.
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# Install additional packages from EXTRA_PACKAGES env var.
|
||||
# Uses a marker file in the datastore to avoid reinstalling on every restart.
|
||||
if [ -n "${EXTRA_PACKAGES:-}" ]; then
|
||||
INSTALLED_MARKER="${DATASTORE_PATH}/.extra_packages_installed"
|
||||
if [ ! -f "$INSTALLED_MARKER" ] || [ "$(cat "$INSTALLED_MARKER" 2>/dev/null)" != "$EXTRA_PACKAGES" ]; then
|
||||
echo "Installing extra packages: $EXTRA_PACKAGES"
|
||||
pip3 install --target=/extra_packages --no-cache-dir $EXTRA_PACKAGES
|
||||
echo "$EXTRA_PACKAGES" > "$INSTALLED_MARKER"
|
||||
echo "Extra packages installed successfully"
|
||||
else
|
||||
echo "Extra packages already installed: $EXTRA_PACKAGES"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Execute the main command
|
||||
exec "$@"
|
||||
|
||||
Reference in New Issue
Block a user