feat: container process supervision with sueprvisord
Rafael Uzarowski committed
Mar 20, 2025 at 23:22 UTC
fbcb579a91937d436f18123dfa22bdfb156bef84
8 files changed
+156
-48
docker/run/Dockerfile
+4
-2
@@ -28,5 +28,7 @@ RUN bash /ins/post_install.sh $BRANCH
28
# Expose ports
29
EXPOSE 22 80
30
31
-# initialize runtime
32
-CMD ["/bin/bash", "-c", "/bin/bash /exe/initialize.sh $BRANCH"]
\ No newline at end of file
31
+RUN chmod +x /exe/initialize.sh /exe/run_A0.sh /exe/run_searxng.sh
32
+
33
+# initialize runtime and switch to supervisord
34
+CMD ["/exe/initialize.sh", "$BRANCH"]
docker/run/DockerfileKali
+4
-2
@@ -29,5 +29,7 @@ RUN bash /ins/post_install.sh $BRANCH
29
# Expose ports
30
EXPOSE 22 80
31
32
-# initialize runtime
33
-CMD ["/bin/bash", "-c", "/bin/bash /exe/initialize.sh $BRANCH"]
\ No newline at end of file
32
+RUN chmod +x /exe/initialize.sh /exe/run_A0.sh /exe/run_searxng.sh
33
+
34
+# initialize runtime and switch to supervisord
35
+CMD ["/exe/initialize.sh", "$BRANCH"]
docker/run/fs/etc/supervisor/conf.d/supervisord.conf
new
+77
@@ -0,0 +1,77 @@
1
+[supervisord]
2
+nodaemon=true
3
+user=root
4
+logfile=/dev/stdout
5
+logfile_maxbytes=0
6
+pidfile=/var/run/supervisord.pid
7
+exitcodes=0,2
8
+directory=/
9
+
10
+[rpcinterface:supervisor]
11
+supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
12
+
13
+[supervisorctl]
14
+serverurl=unix:///var/run/supervisor.sock
15
+
16
+[program:run_sshd]
17
+command=/usr/sbin/sshd -D
18
+environment=LC_ALL=en_US.UTF-8
19
+stopwaitsecs=1
20
+stdout_logfile=/dev/stdout
21
+stdout_logfile_maxbytes=0
22
+stderr_logfile=/dev/stderr
23
+stderr_logfile_maxbytes=0
24
+autorestart=true
25
+startretries=3
26
+stopasgroup=true
27
+killasgroup=true
28
+
29
+[program:run_cron]
30
+command=/usr/sbin/cron -f
31
+environment=
32
+stopwaitsecs=1
33
+stdout_logfile=/dev/stdout
34
+stdout_logfile_maxbytes=0
35
+stderr_logfile=/dev/stderr
36
+stderr_logfile_maxbytes=0
37
+autorestart=true
38
+startretries=3
39
+stopasgroup=true
40
+killasgroup=true
41
+
42
+[program:run_searxng]
43
+command=/exe/run_searxng.sh
44
+environment=SEARXNG_SETTINGS_PATH=/etc/searxng/settings.yml
45
+user=searxng
46
+directory=/usr/local/searxng/searxng-src
47
+stopwaitsecs=1
48
+stdout_logfile=/dev/stdout
49
+stdout_logfile_maxbytes=0
50
+stderr_logfile=/dev/stderr
51
+stderr_logfile_maxbytes=0
52
+autorestart=true
53
+startretries=3
54
+stopasgroup=true
55
+killasgroup=true
56
+
57
+[program:run_ui]
58
+command=/exe/run_A0.sh
59
+environment=
60
+user=root
61
+stopwaitsecs=60
62
+stdout_logfile=/dev/stdout
63
+stdout_logfile_maxbytes=0
64
+stderr_logfile=/dev/stderr
65
+stderr_logfile_maxbytes=0
66
+autorestart=true
67
+startretries=3
68
+stopasgroup=true
69
+killasgroup=true
70
+
71
+[eventlistener:the_listener]
72
+command=python3 /exe/supervisor_event_listener.py
73
+events=PROCESS_STATE_FATAL
74
+stdout_logfile=/dev/stdout
75
+stdout_logfile_maxbytes=0
76
+stderr_logfile=/dev/stderr
77
+stderr_logfile_maxbytes=0
docker/run/fs/exe/initialize.sh
+1
-12
@@ -17,15 +17,4 @@ chmod 444 /root/.profile
17
# update package list to save time later
18
apt-get update > /dev/null 2>&1 &
19
20
-# Start SSH service in background
21
-/usr/sbin/sshd -D &
22
-
23
-# Start searxng server in background
24
-su - searxng -c "bash /exe/run_searxng.sh \"$@\"" &
25
-
26
-# Start A0 and restart on exit
27
-bash /exe/run_A0.sh "$@"
28
-if [ $? -ne 0 ]; then
29
- echo "A0 script exited with an error. Restarting container..."
30
- exit 1
31
-fi
\ No newline at end of file
20
+exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
docker/run/fs/exe/run_A0.sh
+15
-29
@@ -1,33 +1,19 @@
1
#!/bin/bash
2
3
-# Loop to restart the Python script when it finishes
4
-while true; do
3
+. "/ins/setup_venv.sh" "$@"
4
+. "/ins/copy_A0.sh" "$@"
5
6
- . "/ins/setup_venv.sh" "$@"
7
- . "/ins/copy_A0.sh" "$@"
6
+python /a0/prepare.py --dockerized=true
7
+python /a0/preload.py --dockerized=true
8
9
- python /a0/prepare.py --dockerized=true
10
- python /a0/preload.py --dockerized=true
11
-
12
- echo "Starting A0..."
13
- python /a0/run_ui.py \
14
- --dockerized=true \
15
- --port=80 \
16
- --host="0.0.0.0" \
17
- --code_exec_docker_enabled=false \
18
- --code_exec_ssh_enabled=true \
19
- # --code_exec_ssh_addr="localhost" \
20
- # --code_exec_ssh_port=22 \
21
- # --code_exec_ssh_user="root" \
22
- # --code_exec_ssh_pass="toor"
23
-
24
- # Check the exit status
25
- if [ $? -ne 0 ]; then
26
- echo "A0 script exited with an error. Restarting..."
27
- else
28
- echo "A0 script finished. Restarting..."
29
- fi
30
-
31
- # Optional: Add a small delay if needed to avoid rapid restarts
32
- sleep 1
33
-done
9
+echo "Starting A0..."
10
+exec python /a0/run_ui.py \
11
+ --dockerized=true \
12
+ --port=80 \
13
+ --host="0.0.0.0" \
14
+ --code_exec_docker_enabled=false \
15
+ --code_exec_ssh_enabled=true \
16
+ # --code_exec_ssh_addr="localhost" \
17
+ # --code_exec_ssh_port=22 \
18
+ # --code_exec_ssh_user="root" \
19
+ # --code_exec_ssh_pass="toor"
docker/run/fs/exe/run_searxng.sh
+5
-2
@@ -1,7 +1,10 @@
1
#!/bin/bash
2
3
# start webapp
4
-sudo -H -u searxng -i
4
cd /usr/local/searxng/searxng-src
5
export SEARXNG_SETTINGS_PATH="/etc/searxng/settings.yml"
7
-python searx/webapp.py
\ No newline at end of file
6
+
7
+# activate venv
8
+source "/usr/local/searxng/searx-pyenv/bin/activate"
9
+
10
+exec python /usr/local/searxng/searxng-src/searx/webapp.py
docker/run/fs/exe/supervisor_event_listener.py
new
+47
@@ -0,0 +1,47 @@
1
+#!/usr/bin/python
2
+import sys
3
+import os
4
+import logging
5
+import subprocess
6
+import time
7
+
8
+from supervisor.childutils import listener
9
+
10
+
11
+def main(args):
12
+ logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, format='%(asctime)s %(levelname)s %(filename)s: %(message)s')
13
+ logger = logging.getLogger("supervisord-watchdog")
14
+ debug_mode = True if 'DEBUG' in os.environ else False
15
+
16
+ while True:
17
+ logger.info("Listening for events...")
18
+ headers, body = listener.wait(sys.stdin, sys.stdout)
19
+ body = dict([pair.split(":") for pair in body.split(" ")])
20
+
21
+ logger.debug("Headers: %r", repr(headers))
22
+ logger.debug("Body: %r", repr(body))
23
+ logger.debug("Args: %r", repr(args))
24
+
25
+ if debug_mode:
26
+ continue
27
+
28
+ try:
29
+ if headers["eventname"] == "PROCESS_STATE_FATAL":
30
+ logger.info("Process entered FATAL state...")
31
+ if not args or body["processname"] in args:
32
+ logger.error("Killing off supervisord instance ...")
33
+ _ = subprocess.call(["/bin/kill", "-15", "1"], stdout=sys.stderr)
34
+ logger.info("Sent TERM signal to init process")
35
+ time.sleep(5)
36
+ logger.critical("Why am I still alive? Send KILL to all processes...")
37
+ _ = subprocess.call(["/bin/kill", "-9", "-1"], stdout=sys.stderr)
38
+ except Exception as e:
39
+ logger.critical("Unexpected Exception: %s", str(e))
40
+ listener.fail(sys.stdout)
41
+ exit(1)
42
+ else:
43
+ listener.ok(sys.stdout)
44
+
45
+
46
+if __name__ == '__main__':
47
+ main(sys.argv[1:])
docker/run/fs/ins/pre_install.sh
+3
-1
@@ -11,7 +11,9 @@ apt-get update && apt-get install -y \
11
curl \
12
wget \
13
git \
14
- ffmpeg
14
+ ffmpeg \
15
+ supervisor \
16
+ cron
17
18
# # Configure system alternatives so that /usr/bin/python3 points to Python 3.12
19
# sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1