/
/
/
Ansible role that deployes services on my runner machine
1# D&D session agent stack.
2#
3# One compose project so the whole system has a single on/off switch:
4# dnd_enabled: false -> every part of it goes away.
5#
6# Three services with deliberately different lifecycles:
7#
8# dnd-stt always up. A generic OpenAI-compatible speech endpoint that
9# anything on the runner can use, not just this stack.
10# dnd-agent started per session and stopped afterwards. It only makes sense
11# while people are in the room, and leaving it idling would keep a
12# participant in the conference all week.
13# dnd-post runs to completion and exits. Under a compose profile so a plain
14# `up` never starts it.
15
16services:
17 dnd-stt:
18 container_name: dnd-stt
19 image: "{{ container_images.dnd_stt }}"
20 restart: unless-stopped
21
22 ports:
23 - "{{ dnd_stt_host_port }}:8000"
24
25 env_file:
26 - stt.env
27
28 volumes:
29 - /etc/localtime:/etc/localtime:ro
30 # Whisper weights are several hundred MB and fetched on first use, so
31 # this must persist or every restart re-downloads them.
32 - {{ dnd_stt_model_dir }}:/home/ubuntu/.cache/huggingface
33
34{% if gpu_enabled %}
35 runtime: nvidia
36 deploy:
37 resources:
38 reservations:
39 devices:
40 - driver: nvidia
41 count: 1
42 capabilities: [gpu]
43{% endif %}
44
45 healthcheck:
46 test: ["CMD", "curl", "-fsS", "http://localhost:8000/health"]
47 interval: 30s
48 timeout: 10s
49 start_period: {{ dnd_stt_start_period }}
50 retries: 3
51
52 networks:
53 {{ runner_docker_network }}:
54 aliases:
55 - dnd-stt
56
57 dnd-agent:
58 container_name: dnd-agent
59 build:
60 context: {{ dnd_config_dir }}/src
61 dockerfile: Dockerfile.agent
62 args:
63 UID: "{{ dnd_uid }}"
64 GID: "{{ dnd_gid }}"
65 image: dnd-agent:{{ dnd_agent_version }}
66
67 # Never restarted automatically. A session ends when people leave, and a
68 # restarting agent would silently rejoin an empty room and record silence.
69 restart: "no"
70 profiles: ["session"]
71
72 env_file:
73 - agent.env
74
75 depends_on:
76 dnd-stt:
77 condition: service_healthy
78
79 volumes:
80 - /etc/localtime:/etc/localtime:ro
81 - {{ dnd_media_dir }}:/media/dnd
82
83 networks:
84 {{ runner_docker_network }}:
85 aliases:
86 - dnd-agent
87
88 dnd-post:
89 container_name: dnd-post
90 build:
91 context: {{ dnd_config_dir }}/src
92 dockerfile: Dockerfile.post
93 args:
94 UID: "{{ dnd_uid }}"
95 GID: "{{ dnd_gid }}"
96 image: dnd-post:{{ dnd_agent_version }}
97
98 restart: "no"
99 # Only started explicitly, so `docker compose up -d` brings up the STT
100 # service alone and never kicks off an hour of summarisation.
101 profiles: ["post"]
102
103 env_file:
104 - post.env
105
106 volumes:
107 - /etc/localtime:/etc/localtime:ro
108 - {{ dnd_media_dir }}:/media/dnd
109 # pyannote weights, kept out of the image so a rebuild does not refetch
110 # them and so the gated download happens exactly once.
111 - {{ dnd_model_dir }}:/models
112
113{% if gpu_enabled %}
114 runtime: nvidia
115 deploy:
116 resources:
117 reservations:
118 devices:
119 - driver: nvidia
120 count: 1
121 capabilities: [gpu]
122{% endif %}
123
124 networks:
125 {{ runner_docker_network }}:
126 aliases:
127 - dnd-post
128
129networks:
130 {{ runner_docker_network }}:
131 external: true
132