/
/
/
Ansible role that deployes services on my runner machine
1---
2# Runner Services - Pull latest images and recreate containers
3#
4# Usage via update-services.yml:
5# All runner services: ansible-playbook update-services.yml --limit runner_servers
6# Single service: ansible-playbook update-services.yml --limit runner_servers --tags frigate
7# Multiple services: ansible-playbook update-services.yml --limit runner_servers --tags "frigate,immich"
8
9- name: Update Frigate
10 when: frigate_enabled
11 tags: [frigate]
12 block:
13 - name: "Frigate - Pull latest images and recreate"
14 community.docker.docker_compose_v2:
15 project_src: "{{ frigate_config_dir }}"
16 state: present
17 pull: always
18 recreate: auto
19 register: frigate_update
20
21 - name: "Frigate - Report update status"
22 debug:
23 msg: "Frigate: {{ 'updated and recreated' if frigate_update.changed else 'already up to date' }}"
24
25- name: Update Immich
26 when: immich_enabled
27 tags: [immich]
28 block:
29 - name: "Immich - Pull latest images and recreate"
30 community.docker.docker_compose_v2:
31 project_src: "{{ immich_config_dir }}"
32 state: present
33 pull: always
34 recreate: auto
35 register: immich_update
36
37 - name: "Immich - Report update status"
38 debug:
39 msg: "Immich: {{ 'updated and recreated' if immich_update.changed else 'already up to date' }}"
40
41- name: Update Forgejo
42 when: forgejo_enabled
43 tags: [forgejo]
44 block:
45 - name: "Forgejo - Pull latest images and recreate"
46 community.docker.docker_compose_v2:
47 project_src: "{{ forgejo_config_dir }}"
48 state: present
49 pull: always
50 recreate: auto
51 register: forgejo_update
52
53 - name: "Forgejo - Report update status"
54 debug:
55 msg: "Forgejo: {{ 'updated and recreated' if forgejo_update.changed else 'already up to date' }}"
56
57- name: Update Web Tools
58 when: web_tools_enabled
59 tags: [web-tools]
60 block:
61 - name: "Web Tools - Pull latest images and recreate"
62 community.docker.docker_compose_v2:
63 project_src: "{{ web_tools_config_dir }}"
64 state: present
65 pull: always
66 recreate: auto
67 register: web_tools_update
68
69 - name: "Web Tools - Report update status"
70 debug:
71 msg: "Web Tools: {{ 'updated and recreated' if web_tools_update.changed else 'already up to date' }}"
72
73- name: Update Tandoor
74 when: tandoor_enabled
75 tags: [tandoor]
76 block:
77 - name: "Tandoor - Pull latest images and recreate"
78 community.docker.docker_compose_v2:
79 project_src: "{{ tandoor_config_dir }}"
80 state: present
81 pull: always
82 recreate: auto
83 register: tandoor_update
84
85 - name: "Tandoor - Report update status"
86 debug:
87 msg: "Tandoor: {{ 'updated and recreated' if tandoor_update.changed else 'already up to date' }}"
88
89- name: Update Ghost CMS
90 when: ghost_enabled
91 tags: [ghost]
92 block:
93 - name: "Ghost CMS - Pull latest images and recreate"
94 community.docker.docker_compose_v2:
95 project_src: "{{ ghost_config_dir }}"
96 state: present
97 pull: always
98 recreate: auto
99 register: ghost_update
100
101 - name: "Ghost CMS - Report update status"
102 debug:
103 msg: "Ghost CMS: {{ 'updated and recreated' if ghost_update.changed else 'already up to date' }}"
104
105- name: Update CVAT
106 when: cvat_enabled
107 tags: [cvat]
108 block:
109 - name: "CVAT - Pull latest images and recreate"
110 community.docker.docker_compose_v2:
111 project_src: "{{ cvat_config_dir }}"
112 state: present
113 pull: always
114 recreate: auto
115 register: cvat_update
116
117 - name: "CVAT - Report update status"
118 debug:
119 msg: "CVAT: {{ 'updated and recreated' if cvat_update.changed else 'already up to date' }}"
120
121- name: Update Harbor
122 when: harbor_enabled
123 tags: [harbor]
124 block:
125 - name: "Harbor - Pull latest images and recreate"
126 community.docker.docker_compose_v2:
127 project_src: "{{ harbor_config_dir }}"
128 state: present
129 pull: always
130 recreate: auto
131 register: harbor_update
132
133 - name: "Harbor - Report update status"
134 debug:
135 msg: "Harbor: {{ 'updated and recreated' if harbor_update.changed else 'already up to date' }}"
136
137- name: Update LLM Stack
138 when: llm_stack_enabled
139 tags: [llm-stack, ollama, openwebui, litellm]
140 block:
141 - name: "LLM Stack - Pull latest images and recreate"
142 community.docker.docker_compose_v2:
143 project_src: "{{ llm_stack_config_dir }}"
144 state: present
145 pull: always
146 recreate: auto
147 register: llm_update
148
149 - name: "LLM Stack - Report update status"
150 debug:
151 msg: "LLM Stack: {{ 'updated and recreated' if llm_update.changed else 'already up to date' }}"
152
153- name: Update the always-on D&D services
154 when: dnd_enabled
155 tags: [dnd, dnd-stt, chamberlain]
156 block:
157 # Named explicitly rather than left to compose. A bare `state: present` here
158 # would act on every service without a profile, which happens to be the right
159 # set today and would silently change the moment one gains or loses a
160 # profile. The per-session services are the Chamberlain's to start.
161 - name: "dnd - Pull latest images and recreate the always-on services"
162 community.docker.docker_compose_v2:
163 project_src: "{{ dnd_config_dir }}"
164 services: [dnd-stt, dnd-chamberlain]
165 state: present
166 pull: always
167 recreate: auto
168 register: dnd_stt_update
169
170 # Pulled but not started: these belong to a session, so an update makes the
171 # new image present and the next session picks it up.
172 - name: "dnd - Pull the per-session images without starting them"
173 community.docker.docker_image:
174 name: "{{ item }}"
175 source: pull
176 force_source: true
177 loop:
178 - "{{ dnd_agent_image }}"
179 - "{{ dnd_post_image }}"
180 - "{{ dnd_table_runner_image }}"
181 - "{{ dnd_camera_image }}"
182 loop_control:
183 label: "{{ item | basename }}"
184
185 - name: "dnd - Report update status"
186 debug:
187 msg: >-
188 dnd: {{ 'updated and recreated' if dnd_stt_update.changed
189 else 'already up to date' }}
190 (per-session images pulled; they start with the next session)
191
192- name: Update Macro Checker
193 when: macros_enabled
194 tags: [macros]
195 block:
196 - name: "Macro Checker - Pull latest images and recreate"
197 community.docker.docker_compose_v2:
198 project_src: "{{ macros_config_dir }}"
199 state: present
200 pull: always
201 recreate: auto
202 register: macros_update
203
204 - name: "Macro Checker - Report update status"
205 debug:
206 msg: "Macro Checker: {{ 'updated and recreated' if macros_update.changed else 'already up to date' }}"
207
208# Mealie's image is pinned: an update run re-pulls and recreates at
209# mealie_version. Moving to a newer Mealie is a change to that variable, after
210# reading the release notes -- upstream's own advice.
211- name: Update Mealie
212 when: mealie_enabled
213 tags: [mealie, recipes]
214 block:
215 - name: "Mealie - Pull images and recreate"
216 community.docker.docker_compose_v2:
217 project_src: "{{ mealie_config_dir }}"
218 state: present
219 pull: always
220 recreate: auto
221 register: mealie_update
222
223 - name: "Mealie - Report update status"
224 debug:
225 msg: "Mealie {{ mealie_version }}: {{ 'updated and recreated' if mealie_update.changed else 'already up to date' }}"
226
227- name: Update LiveKit Stack
228 when: livekit_enabled
229 tags: [livekit, conferencing]
230 block:
231 - name: "LiveKit - Pull latest images and rebuild Meet"
232 community.docker.docker_compose_v2:
233 project_src: "{{ livekit_config_dir }}"
234 state: present
235 pull: always
236 build: always
237 recreate: auto
238 register: livekit_update
239
240 - name: "LiveKit - Report update status"
241 debug:
242 msg: "LiveKit Stack: {{ 'updated and recreated' if livekit_update.changed else 'already up to date' }}"
243
244- name: Prune unused Docker images
245 tags: [cleanup, prune]
246 community.docker.docker_prune:
247 images: true
248 images_filters:
249 dangling: "true"
250 register: prune_result
251
252- name: Report cleanup
253 tags: [cleanup, prune]
254 debug:
255 msg: "Pruned {{ prune_result.images | default([]) | length }} dangling image(s), reclaimed {{ prune_result.images_space_reclaimed | default(0) | human_readable }}"
256 when: prune_result.images | default([]) | length > 0
257