blackd schreef op zondag 7 december 2025 @ 20:29:
[...]
Wat betreft het eerste, snap ik wat je zegt. Momenteel heb ik ook ansible gewoon nog 'lokaal' geinstalleerd staan.
Het had juist mijn voorkeur om overal exact dezelfde dependencies te hebben. Zowel in CI als lokaal in development.
Yes. Maar dat heb ik dus

. Want lokaal gebruik ik pyenv met een virtualenv die met pip de requirements.txt installeert met daarin o.a. Ansible Core en Ansible Lint. En de CI omgeving doet setup-python hetzelfde. Allebei maken ze gebruik van dezelfde python versie dmv het
.python-version bestand. Renovate update hier (wederom) de dependencies.
Ik vind het overigens een voordeel om lokaal geen globale Ansible meer te hebben. Dan kan ik ook niet per abuis een verkeerde of oude versie gebruiken.
Dat staat nog op mijn wensenlijstje.
.pre-commit-config.yaml
YAML:
1
2
3
4
5
6
7
8
9
10
11
12
13
| repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-shebang-scripts-are-executable
- id: detect-private-key
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/ansible/ansible-lint
rev: v25.12.0
hooks:
- id: ansible-lint |
In de requirements.txt zit
pre-commit==4.5.0 en activeren is dan niets meer dan
pre-commit install.
Ik template ook mijn Compose bestanden maar het enige wat er eigenlijk gevuld wordt zijn de standaard variabelen (${}) en die worden weer gevoed door het .env bestand. En die template ik ook, die wordt gevoed door Ansible.
Ik template de Compose bestanden zelf ook. Best uitgebreid overigens

. Recent ben ik wat met Ghost in de weer geweest en dan komt er zoiets uit. Dit is een snippet als voorbeeld:
YAML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| #jinja2: lstrip_blocks: True, trim_blocks: True
---
{{ ansible_managed | comment }}
name: {{ _compose_stack_name }}
services:
ghost:
container_name: ${COMPOSE_PROJECT_NAME}
image: ghost:6.10.0-alpine
environment:
NODE_ENV: production
url: ${GHOST_URL}
database__client: mysql
database__connection__host: database
database__connection__user: ${DATABASE_USERNAME}
database__connection__password: ${DATABASE_PASSWORD}
database__connection__database: ${DATABASE_NAME}
networks:
ingress:
internal:
volumes:
- {{ ghost_uploads_dir }}:/var/lib/ghost/content
depends_on:
database:
condition: service_healthy
{% if not ghost_use_hosted_activitypub %}
activitypub:
condition: service_started
required: false
{% endif %}
{% if ghost_docker_options is defined %}
{{ ghost_docker_options | to_nice_yaml | indent(4) }}
{%- endif %}
labels:
traefik.enable: true
traefik.http.routers.{{ _compose_stack_name }}.rule: "Host(`{{ ghost_domain }}`)"
traefik.http.routers.{{ _compose_stack_name }}.middlewares: "anubis@docker"
traefik.http.routers.{{ _compose_stack_name }}.service: "{{ _compose_stack_name }}"
traefik.http.services.{{ _compose_stack_name }}.loadbalancer.server.port: "2368"
{%- if _is_unraid +%}
net.unraid.docker.icon: https://avatars.githubusercontent.com/u/2452804?s=200&v=4
net.unraid.docker.managed: ansible
net.unraid.docker.shell: /bin/bash
{% endif %} |
Secrets komen bij mij in de
.env.j2 zodat deze niet direct zichtbaar zijn.
Conditionals zijn bij mij hier enorm belangrijk omdat ik afhankelijk van variabelen nog weleens het een of het andere uitrol. Bijvoorbeeld een adguard_home_sync op een secundaire node. Dan hoef ik geen twee Compose bestanden te onderhouden. Profielen zijn uiteraard ook nog een optie, maar dat vind ik niet heel transparent. Laatst heb ik daar wel meegespeeld in OpenCloud / OCIS, maar dan wordt het heel snel, heel complex. Met name als je geen of weinig ervaring in de desbetreffende repo hebt.
Bij de labels moet ik (helaas) de Jinja expressie gebruiken omdat Docker Compose ${COMPOSE_PROJECT_NAME} deze al literal neemt in de label naam

. Volgens mij is dat niet zo bij de andere syntax, maar ik ga dat niet helemaal omgooien om zoiets doms.
Overigens is dit ook weer allemaal een kwestie van smaak en is het geheel uiteraard fluïde.