Skip to content

Commit 9128698

Browse files
authored
Merge pull request #386 from OpenMS/claude/fix-opendiakiosk-apptainer-dHZXJ
Extract entrypoint script to file for Apptainer compatibility
2 parents 2765119 + d85c6d8 commit 9128698

2 files changed

Lines changed: 145 additions & 1 deletion

File tree

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ RUN rm -rf openms-build
123123
# Prepare and run streamlit app.
124124
FROM compile-openms AS run-app
125125

126-
# Install Redis server for job queue and nginx for load balancing
126+
# Install Redis server for job queue and nginx for load balancing.
127+
# Redis data lives under $RUNTIME_DIR at runtime (see entrypoint.sh) so no
128+
# /var/lib/redis setup is needed - that path is not writable under Apptainer.
127129
RUN apt-get update && apt-get install -y --no-install-recommends redis-server nginx \
128130
&& rm -rf /var/lib/apt/lists/*
129131

entrypoint.sh

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#!/bin/bash
2+
# Entrypoint for the streamlit-template container.
3+
#
4+
# Designed to run under both Docker and Apptainer/Singularity. Apptainer
5+
# mounts the container filesystem read-only by default, so anything that
6+
# needs to write at runtime (Redis dump, pidfiles, nginx temp dirs) must
7+
# live under a writable path. /tmp is bind-mounted as tmpfs in both
8+
# engines, so we route runtime state to $RUNTIME_DIR (default
9+
# /tmp/opendiakiosk). Override RUNTIME_DIR to persist Redis dumps.
10+
set -e
11+
source /root/miniforge3/bin/activate streamlit-env
12+
13+
RUNTIME_DIR="${RUNTIME_DIR:-/tmp/opendiakiosk}"
14+
mkdir -p "$RUNTIME_DIR/redis" "$RUNTIME_DIR/nginx" "$RUNTIME_DIR/nginx/tmp"
15+
16+
# cron writes /var/run/crond.pid, which is not writable on read-only
17+
# container filesystems (Apptainer without --writable-tmpfs). Treat the
18+
# failure as non-fatal: the rest of the app still works, the periodic
19+
# workspace cleanup is just skipped. Run clean-up-workspaces.py from a
20+
# host cron if you need it under Apptainer.
21+
service cron start 2>/dev/null || echo "Note: cron not started (read-only filesystem?). Scheduled workspace cleanup disabled."
22+
23+
# Start Redis with an explicit runtime-generated config. This avoids the
24+
# distro default /etc/redis/redis.conf which sets dir to /var/lib/redis,
25+
# a path that is not writable on Apptainer's read-only rootfs.
26+
echo "Starting Redis server..."
27+
REDIS_CONF="$RUNTIME_DIR/redis/redis.conf"
28+
cat > "$REDIS_CONF" <<EOF
29+
port 6379
30+
bind 127.0.0.1 -::1
31+
dir $RUNTIME_DIR/redis
32+
pidfile $RUNTIME_DIR/redis/redis.pid
33+
logfile ""
34+
appendonly no
35+
daemonize yes
36+
EOF
37+
redis-server "$REDIS_CONF"
38+
39+
# Wait for Redis to be ready
40+
until redis-cli ping > /dev/null 2>&1; do
41+
echo "Waiting for Redis..."
42+
sleep 1
43+
done
44+
echo "Redis is ready"
45+
46+
# Start RQ worker(s) in background
47+
WORKER_COUNT=${RQ_WORKER_COUNT:-1}
48+
echo "Starting $WORKER_COUNT RQ worker(s)..."
49+
for i in $(seq 1 $WORKER_COUNT); do
50+
rq worker openms-workflows --url "$REDIS_URL" --name "worker-$i" &
51+
done
52+
53+
# Load balancer setup
54+
SERVER_COUNT=${STREAMLIT_SERVER_COUNT:-1}
55+
56+
if [ "$SERVER_COUNT" -gt 1 ]; then
57+
echo "Starting $SERVER_COUNT Streamlit instances with nginx load balancer..."
58+
59+
BASE_PORT=8510
60+
UPSTREAM_LINES=""
61+
for i in $(seq 0 $((SERVER_COUNT - 1))); do
62+
PORT=$((BASE_PORT + i))
63+
UPSTREAM_LINES="${UPSTREAM_LINES} server 127.0.0.1:${PORT};
64+
"
65+
done
66+
67+
# Write nginx config into the writable runtime dir and point pidfile,
68+
# logs, and all temp paths there too so nginx can run under Apptainer's
69+
# read-only rootfs (which makes the default /run, /var/log/nginx, and
70+
# /var/lib/nginx unwritable). Bash interpolates $RUNTIME_DIR and
71+
# $UPSTREAM_LINES; nginx-side variables are escaped with \$ so they
72+
# reach the file as literal $name for nginx to expand at request time.
73+
NGINX_CONF="$RUNTIME_DIR/nginx/nginx.conf"
74+
cat > "$NGINX_CONF" <<NGINX_EOF
75+
worker_processes auto;
76+
pid $RUNTIME_DIR/nginx/nginx.pid;
77+
error_log $RUNTIME_DIR/nginx/error.log;
78+
79+
events {
80+
worker_connections 1024;
81+
}
82+
83+
http {
84+
client_body_temp_path $RUNTIME_DIR/nginx/tmp/client_body;
85+
proxy_temp_path $RUNTIME_DIR/nginx/tmp/proxy;
86+
fastcgi_temp_path $RUNTIME_DIR/nginx/tmp/fastcgi;
87+
uwsgi_temp_path $RUNTIME_DIR/nginx/tmp/uwsgi;
88+
scgi_temp_path $RUNTIME_DIR/nginx/tmp/scgi;
89+
access_log $RUNTIME_DIR/nginx/access.log;
90+
91+
client_max_body_size 0;
92+
93+
map \$cookie_stroute \$route_key {
94+
"" \$request_id;
95+
default \$cookie_stroute;
96+
}
97+
98+
upstream streamlit_backend {
99+
hash \$route_key consistent;
100+
${UPSTREAM_LINES} }
101+
102+
map \$http_upgrade \$connection_upgrade {
103+
default upgrade;
104+
'' close;
105+
}
106+
107+
server {
108+
listen 0.0.0.0:8501;
109+
110+
location / {
111+
proxy_pass http://streamlit_backend;
112+
proxy_http_version 1.1;
113+
proxy_set_header Upgrade \$http_upgrade;
114+
proxy_set_header Connection \$connection_upgrade;
115+
proxy_set_header Host \$host;
116+
proxy_set_header X-Real-IP \$remote_addr;
117+
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
118+
proxy_set_header X-Forwarded-Proto \$scheme;
119+
proxy_read_timeout 86400;
120+
proxy_send_timeout 86400;
121+
proxy_buffering off;
122+
add_header Set-Cookie "stroute=\$route_key; Path=/; HttpOnly; SameSite=Lax" always;
123+
}
124+
}
125+
}
126+
NGINX_EOF
127+
128+
# Start Streamlit instances on internal ports
129+
for i in $(seq 0 $((SERVER_COUNT - 1))); do
130+
PORT=$((BASE_PORT + i))
131+
echo "Starting Streamlit instance on port $PORT..."
132+
streamlit run app.py --server.port "$PORT" --server.address 0.0.0.0 &
133+
done
134+
135+
sleep 2
136+
echo "Starting nginx load balancer on port 8501..."
137+
exec /usr/sbin/nginx -c "$NGINX_CONF" -g "daemon off;"
138+
else
139+
# Single instance mode (default) - run Streamlit directly on port 8501
140+
echo "Starting Streamlit app..."
141+
exec streamlit run app.py --server.address 0.0.0.0
142+
fi

0 commit comments

Comments
 (0)