# 1. Start from a slim Python 3.11 base image FROM python:3.11-slim # 2. Set Environment Variables # - DEBIAN_FRONTEND: Prevents installers from asking interactive questions # - PYTHONUNBUFFERED/PYTHONDONTWRITEBYTECODE: Standard Python-in-Docker settings # - PYVISTA_OFF_SCREEN/DISPLAY: Crucial for running PyVista headless (off-screen) # by telling it to use a "virtual" display at address :99 ENV DEBIAN_FRONTEND=noninteractive \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ HOME=/home/user \ PATH=/home/user/.local/bin:$PATH \ PYVISTA_OFF_SCREEN=true \ DISPLAY=:99 \ VTK_SILENCE_GET_VOID_POINTER_WARNINGS=1 # 3. Install System Dependencies # Added 'git' here because we need it to clone aqc-research RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential cmake wget xvfb nginx git \ libosmesa6 libosmesa6-dev \ libgl1 libgl1-mesa-dev \ libegl1 libegl1-mesa-dev \ libglu1-mesa libglu1-mesa-dev \ libgles2-mesa-dev \ libx11-6 libxt6 libxrender1 libsm6 libice6 \ && rm -rf /var/lib/apt/lists/* # 4. Create a non-root user for security RUN useradd -m -u 1000 user WORKDIR /home/user/app # 5. Install Python dependencies (optimized) # We copy *only* requirements.txt first and install it. # This "layer" is cached by Docker. If you only change app.py later, # Docker skips this step, making builds much faster. COPY requirements.txt . RUN python3 -m pip install --upgrade pip setuptools wheel \ && python3 -m pip install --no-cache-dir -r requirements.txt # 6. Copy the rest of the application code # This copies app.py, delta_impulse_generator.py, etc. # We set the owner to our new 'user'. COPY --chown=user:user . . COPY docker/nginx.conf /etc/nginx/nginx.conf # --------------------------------------------------------------------------- # Create the 'aqc_venv' and install dependencies # --------------------------------------------------------------------------- RUN python3 -m venv utils/aqc_venv && \ # 1. Upgrade pip inside the new venv utils/aqc_venv/bin/pip install --upgrade pip setuptools wheel && \ # 2. Install EXACT versions FIRST (before any library that has qiskit dependency) utils/aqc_venv/bin/pip install \ "qiskit==1.3.1" \ "qiskit-aer==0.16.4" \ "qiskit-algorithms==0.4.0" \ "qiskit-qasm3-import==0.6.0" \ "qiskit-experiments==0.6.1" \ "qiskit-ibm-experiment==0.4.8" \ "numpy==1.26.4" \ "scipy==1.16.3" \ "sympy==1.14.0" \ "openfermion==1.7.1" \ "cirq-core==1.6.1" \ "physics-tenpy==1.0.7" \ "lmfit==1.3.4" \ "h5py==3.15.1" && \ # 3. Clone aqc-research inside utils cd utils && \ git clone https://github.com/bjader/aqc-research.git && \ # 4. Install aqc-research with --no-deps (won't upgrade qiskit) /home/user/app/utils/aqc_venv/bin/pip install --no-deps ./aqc-research && \ # 5. Install adapt-aqc with --no-deps /home/user/app/utils/aqc_venv/bin/pip install --no-deps -e ./adapt-aqc && \ # 6. VERIFY: Print versions to confirm echo "=== Qiskit versions ===" && \ /home/user/app/utils/aqc_venv/bin/pip list | grep -i qiskit && \ /home/user/app/utils/aqc_venv/bin/python --version # Prepare writable directories for nginx (running as non-root later) RUN mkdir -p /tmp/nginx/body /tmp/nginx/proxy /tmp/nginx/fastcgi /tmp/nginx/uwsgi /tmp/nginx/scgi \ && touch /tmp/nginx.access.log /tmp/nginx.error.log \ && chown -R user:user /tmp/nginx /tmp/nginx.access.log /tmp/nginx.error.log # 7. Switch to the non-root user USER user # Note: We do NOT set PYTHONPATH for adapt-aqc here because it is installed # inside the 'aqc_venv' which your code calls via subprocess. # Default runtime configuration for multiprocess layout ENV OMP_NUM_THREADS=1 \ APP_HOST=127.0.0.1 \ APP_PORT=8700 \ EM_APP_PORT=8701 \ QLBM_APP_PORT=8702 \ EM_HOST=127.0.0.1 \ QLBM_HOST=127.0.0.1 \ EM_IFRAME_SRC=/em/ \ QLBM_IFRAME_SRC=/qlbm/ # 8. Expose the port the app will run on EXPOSE 7860 # 9. Healthcheck (good practice for hosting platforms) HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT:-7860}/ || exit 1 # 10. Start Command # This command does two things: # a) Starts the X Virtual FrameBuffer (Xvfb) in the background (&) on display :99 # b) 'exec' runs your app. Using 'exec' is important as it makes the Python # process the main one, which properly handles signals (like stopping the container). # '--host 0.0.0.0' is ESSENTIAL to make the server accessible from outside the container. CMD ["sh", "-c", "Xvfb :99 -screen 0 1024x768x24 >/dev/null 2>&1 & nginx && exec python3 app.py --server --host ${APP_HOST:-127.0.0.1} --port ${APP_PORT:-8700}"]