@@ -47,6 +47,13 @@ RUN wget -q \
4747 && rm -f Miniforge3-Linux-x86_64.sh
4848RUN mamba --version
4949
50+ # Make /root traversable so the entrypoint can `source
51+ # /root/miniforge3/bin/activate ...` when the container runs as a non-root
52+ # user (apptainer/singularity maps the host UID into the container; the
53+ # default ubuntu /root is 0700 which would block path traversal). +x only,
54+ # not +r, so the directory listing remains private.
55+ RUN chmod o+x /root
56+
5057# Setup mamba environment.
5158RUN mamba create -n streamlit-env python=3.10
5259RUN echo "mamba activate streamlit-env" >> ~/.bashrc
@@ -120,8 +127,11 @@ FROM compile-openms AS run-app
120127RUN apt-get update && apt-get install -y --no-install-recommends redis-server nginx \
121128 && rm -rf /var/lib/apt/lists/*
122129
123- # Create Redis data directory
124- RUN mkdir -p /var/lib/redis && chown redis:redis /var/lib/redis
130+ # Create Redis data directory. Default 0755 root-owned is enough: the docker
131+ # entrypoint runs as root (can write regardless of mode), and the apptainer
132+ # entrypoint relocates Redis state to /tmp/openms-runtime-* so this dir is
133+ # never written under apptainer.
134+ RUN mkdir -p /var/lib/redis
125135
126136# Create workdir and copy over all streamlit related files/folders.
127137
@@ -155,67 +165,10 @@ ENV REDIS_URL=redis://localhost:6379/0
155165# Set to >1 to enable nginx load balancer with multiple Streamlit instances
156166ENV STREAMLIT_SERVER_COUNT=1
157167
158- # create entrypoint script to start cron, Redis, RQ workers, and Streamlit
159- RUN echo -e '#!/bin/bash\n \
160- set -e\n \
161- source /root/miniforge3/bin/activate streamlit-env\n \
162- \n \
163- # Start cron for workspace cleanup\n \
164- service cron start\n \
165- \n \
166- # Start Redis server in background\n \
167- echo "Starting Redis server..."\n \
168- redis-server --daemonize yes --dir /var/lib/redis --appendonly no\n \
169- \n \
170- # Wait for Redis to be ready\n \
171- until redis-cli ping > /dev/null 2>&1; do\n \
172- echo "Waiting for Redis..."\n \
173- sleep 1\n \
174- done\n \
175- echo "Redis is ready"\n \
176- \n \
177- # Start RQ worker(s) in background\n \
178- WORKER_COUNT=${RQ_WORKER_COUNT:-1}\n \
179- echo "Starting $WORKER_COUNT RQ worker(s)..."\n \
180- for i in $(seq 1 $WORKER_COUNT); do\n \
181- rq worker openms-workflows --url $REDIS_URL --name worker-$i &\n \
182- done\n \
183- \n \
184- # Load balancer setup\n \
185- SERVER_COUNT=${STREAMLIT_SERVER_COUNT:-1}\n \
186- \n \
187- if [ "$SERVER_COUNT" -gt 1 ]; then\n \
188- echo "Starting $SERVER_COUNT Streamlit instances with nginx load balancer..."\n \
189- \n \
190- # Generate nginx upstream block\n \
191- UPSTREAM_SERVERS=""\n \
192- BASE_PORT=8510\n \
193- for i in $(seq 0 $((SERVER_COUNT - 1))); do\n \
194- PORT=$((BASE_PORT + i))\n \
195- UPSTREAM_SERVERS="${UPSTREAM_SERVERS} server 127.0.0.1:${PORT};\\ n"\n \
196- done\n \
197- \n \
198- # Write nginx config\n \
199- mkdir -p /etc/nginx\n \
200- echo -e "worker_processes auto;\\npid /run/nginx.pid;\\n\\nevents {\\n worker_connections 1024;\\n}\\n\\nhttp {\\n client_max_body_size 0;\\n\\n map \\$cookie_stroute \\$route_key {\\n \\x22\\x22 \\$request_id;\\n default \\$cookie_stroute;\\n }\\n\\n upstream streamlit_backend {\\n hash \\$route_key consistent;\\n${UPSTREAM_SERVERS} }\\n\\n map \\$http_upgrade \\$connection_upgrade {\\n default upgrade;\\n \\x27\\x27 close;\\n }\\n\\n server {\\n listen 0.0.0.0:8501;\\n\\n location / {\\n proxy_pass http://streamlit_backend;\\n proxy_http_version 1.1;\\n proxy_set_header Upgrade \\$http_upgrade;\\n proxy_set_header Connection \\$connection_upgrade;\\n proxy_set_header Host \\$host;\\n proxy_set_header X-Real-IP \\$remote_addr;\\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\\n proxy_set_header X-Forwarded-Proto \\$scheme;\\n proxy_read_timeout 86400;\\n proxy_send_timeout 86400;\\n proxy_buffering off;\\n add_header Set-Cookie \\x22stroute=\\$route_key; Path=/; HttpOnly; SameSite=Lax\\x22 always;\\n }\\n }\\n}" > /etc/nginx/nginx.conf\n\
201- \n \
202- # Start Streamlit instances on internal ports\n \
203- for i in $(seq 0 $((SERVER_COUNT - 1))); do\n \
204- PORT=$((BASE_PORT + i))\n \
205- echo "Starting Streamlit instance on port $PORT..."\n \
206- streamlit run app.py --server.port $PORT --server.address 0.0.0.0 &\n \
207- done\n \
208- \n \
209- sleep 2\n \
210- echo "Starting nginx load balancer on port 8501..."\n \
211- exec /usr/sbin/nginx -g "daemon off;"\n \
212- else\n \
213- # Single instance mode (default) - run Streamlit directly on port 8501\n \
214- echo "Starting Streamlit app..."\n \
215- exec streamlit run app.py --server.address 0.0.0.0\n \
216- fi\n \
217- ' > /app/entrypoint.sh
218- # make the script executable
168+ # Install the apptainer-compatible entrypoint that starts cron (when the root
169+ # FS is writable), Redis, RQ workers, optional nginx load balancer, and the
170+ # Streamlit server. The script falls back to /tmp paths under apptainer.
171+ COPY docker/entrypoint.sh /app/entrypoint.sh
219172RUN chmod +x /app/entrypoint.sh
220173
221174# Patch Analytics
0 commit comments