Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
99 lines (87 loc) · 5.57 KB
/
Copy pathDockerfile
File metadata and controls
99 lines (87 loc) · 5.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
FROM python:3.12-slim@sha256:ddb0207ae1f0356c2b724d740769b0c5f5f51cc54a0525178f721825f78fe74c
LABEL org.label-schema.name="PegaProx"
LABEL org.label-schema.description="Modern Multi-Cluster Management for Proxmox VE"
LABEL org.label-schema.vendor="PegaProx"
LABEL org.label-schema.url="https://pegaprox.com"
LABEL org.label-schema.vcs-url="https://github.com/PegaProx/project-pegaprox"
LABEL maintainer="support@pegaprox.com"
# Install system dependencies
# MK 2026-06-10 — `apt-get upgrade -y` pulls the latest Debian security patches
# at build time (incl. the openssl ~deb13u2 fix for CVE-2026-45447/7383 et al
# that Aikido flagged). For that to actually take effect the release build runs
# with no cache (docker.yml: no-cache: true) — otherwise the GHA layer cache
# kept this step frozen and the stale openssl got republished. Build is
# tag-triggered so the full rebuild cost is fine.
# NS Oct 2026 - 32-bit ARM (arm/v7) has no wheels for gevent, greenlet, cffi, pynacl,
# pillow and a few more: they compile below, which wants a C++ compiler, make and the
# headers pillow builds against
ARG TARGETARCH
ARG TARGETVARIANT
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
gcc libffi-dev libssl-dev \
openssh-client sshpass \
$(if [ "$TARGETARCH/$TARGETVARIANT" = "arm/v7" ]; then echo g++ make zlib1g-dev libjpeg62-turbo-dev; fi) \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN groupadd -r pegaprox && useradd -r -g pegaprox -d /app -s /bin/false pegaprox
WORKDIR /app
# Install Python dependencies first (better layer caching)
# MK Sep 2026 — upgrade pip before the install. The base image pins whatever pip shipped
# with that python:3.12-slim build, and `apt-get upgrade` above can't touch it (it isn't a
# dpkg package), so a pip advisory sat in the published image until the base digest moved.
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir -r requirements.txt
# Copy application
COPY --chown=pegaprox:pegaprox pegaprox_multi_cluster.py .
COPY --chown=pegaprox:pegaprox pegaprox/ pegaprox/
COPY --chown=pegaprox:pegaprox web/ web/
COPY --chown=pegaprox:pegaprox static/ static/
COPY --chown=pegaprox:pegaprox images/ images/
COPY --chown=pegaprox:pegaprox plugins/ plugins/
COPY --chown=pegaprox:pegaprox version.json .
COPY --chown=pegaprox:pegaprox requirements.txt .
COPY --chown=pegaprox:pegaprox update.sh .
# the witness installer: "Add witness" checks the download against this copy's SHA-256,
# and serves it to a witness host without internet; the unit goes into the witness code
# bundle this instance serves (#625)
COPY --chown=pegaprox:pegaprox packaging/witness/install.sh packaging/witness/install.sh
COPY --chown=pegaprox:pegaprox systemd/pegaprox-witness.service systemd/pegaprox-witness.service
# the branch this image is built from (docker-testing.yml passes Testing): "Add witness"
# names the image of that branch for the witness, and update.sh follows it (#625)
ARG PEGAPROX_BRANCH=main
ENV PEGAPROX_BRANCH=${PEGAPROX_BRANCH}
# Create runtime directories
# /app/witness: the state of the witness, for the command `witness` (#625)
RUN mkdir -p /app/config /app/logs /app/backups /app/witness \
&& chown -R pegaprox:pegaprox /app
# Persistent volumes for config and logs
VOLUME ["/app/config", "/app/logs"]
# Switch to non-root user
USER pegaprox
EXPOSE 5000 5001 5002
# the witness, when the container runs the command `witness`
EXPOSE 5005
# MK May 2026 — start_period bumped from 15s to 120s and retries from 3 to 5
# to give the one-time plain→SQLCipher DB migration room to finish on first
# boot post-update. Empirical timing: ~0.5s per MB of DB. start_period covers
# DBs up to ~240MB cleanly; retries (5×30s = 150s extra) extend the tolerance
# to ~4.5 minutes total before the container gets marked unhealthy. After the
# initial migration, all subsequent boots short-circuit (state == 'encrypted')
# so the long start_period only costs operators on the upgrade boot.
# MK 2026-06-01 (#516 prueckls): probe /api/health; either protocol counts.
# MK 2026-07-10 (#614 wwwlde): pick the scheme from PEGAPROX_BEHIND_PROXY and
# always dial 127.0.0.1 — NEVER the hostname 'localhost'. In behind-proxy mode
# the built-in SSL is off (gevent serves plain HTTP), so the old HTTPS-first
# probe fired a TLS ClientHello (SNI=localhost) against the HTTP socket every
# interval — harmless to health (we fell back to HTTP) but it spammed
# "Invalid HTTP method '\x16\x03\x01...'" into the logs. Now the FIRST attempt
# matches the served protocol; the opposite scheme is only a misconfig fallback.
# MK Oct 2026 (#625): a container that runs the witness (its state file in /app/witness)
# has no app on 5000 - it is healthy when `witness health` says so, and only then.
HEALTHCHECK --interval=30s --timeout=5s --start-period=120s --retries=5 \
CMD if [ -f /app/witness/ha_witness.json ]; then exec python3 pegaprox_multi_cluster.py witness health; fi; \
python3 -c "import os,urllib.request,ssl; s=('http' if os.environ.get('PEGAPROX_BEHIND_PROXY','').lower() in ('1','true','yes') else 'https'); urllib.request.urlopen(s+'://127.0.0.1:5000/api/health', context=(ssl._create_unverified_context() if s=='https' else None), timeout=4)" 2>/dev/null \
|| python3 -c "import os,urllib.request,ssl; s=('https' if os.environ.get('PEGAPROX_BEHIND_PROXY','').lower() in ('1','true','yes') else 'http'); urllib.request.urlopen(s+'://127.0.0.1:5000/api/health', context=(ssl._create_unverified_context() if s=='https' else None), timeout=4)" \
|| exit 1
ENTRYPOINT ["python3", "pegaprox_multi_cluster.py"]