• Mars Warrior
  • Registratie: Oktober 2003
  • Laatst online: 00:10

Mars Warrior

Earth, the final frontier

Haha @blackd , nog meer input voor mijn arme hersentjes :+

Vwb betreft je probleem of omweg om de keys te kunnen lezen in je .env file: daarvoor wil ik dus SOPS gebruiken. De keys blijven volledig leesbaar, enkel de values worden geencrypt.

Zo'n bestand kun je dus ook gewoon in Git gooien. Niemand kan er wat mee. Decrypten is met je SSH key, die je toch nodig hebt voor Ansible om te kunnen deployen. Dus onderdeel van de Action of een Playbook 8)

Nergens dus een bestand met leesbare secrets, zeker niet als je met vscode edit: die en/decrypt automatisch vanuit de editor. Je kunt meerdere SSH Keys gebruiken, dus dat is ook nog een plus vind ik.

En het is nu Vroooeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeem tijd :henk

Material 3 Thema's voor HA | Swiss Army Knife custom card voor HA | AmoebeLabs


  • blackd
  • Registratie: Februari 2001
  • Niet online
@Mars Warrior Ja, dat kan natuurlijk ook. Maar dat kan met Ansible Vault ook.
Ik heb ervoor gekozen om alle secrets in 1 yaml bestand te zetten en die in zijn geheel te encrypten.

Houd er in de keuze van je oplossing wel rekening mee of je nog andere tooling gebruikt om je bestanden te verwerken. Je hebt al VSCode benoemd. Maar ik draai zelf Ansible Lint en Docker Compose Lint (ook als GitHub action) bij elke pull request om de repo te valideren. Ansible Lint ondersteunt ook Ansible Vault.
https://docs.ansible.com/projects/lint/
https://docs.ansible.com/projects/lint/usage/#vaults

9000Wp o/w SolarEdge SE6K - Panasonic 5kW bi-bloc - gasloos sinds 17-7-2023


  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 20:49
T.a.v. het cachen van Ansible nog een tip, ik heb een eigen docker container in beheer (gebaseerd op ansible-dev-tools container) die ik zowel als devcontainer in VSCode gebruik als base image voor mijn Self hosted runner. Hier heb ik de versies van Python, Ansible, Ansible Lint, mijn gebruikte Galaxy Collections en pip dependencies in gefixeerd. Ik onderhoud deze docker container in een aparte repository en bouw deze met Ansible Builder als een execution environment. Ik ben alleen niet heel gelukkig met Fedora als base os. Ik zou dit op termijn nog een keer willen omzetten naar een Debian based OS.
Je zou ervoor kunnen kiezen je runner (of dat nou Woodpecker is of een Github local runner) uit te laten voeren in een eigen container met daarin alle benodigde spullen al geïnstalleerd.
Dat heb ik ook een tijdje gehad, maar vond ik onhandig. Ik wil op mijn workstation niet per se afhankelijk zijn van Docker / devcontainers en/of Visual Studio Code. Ook wilde ik graag mijn Ansible requirements graag meenemen in de container. Daardoor had ik echter twee keer dezelfde dependencies in twee aparte repo's. Dat voelde niet zo lekker.

Ter referentie mijn Ansible Dockerfile
Docker:
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
FROM node:22.17-alpine

ADD requirements.txt requirements.yml /

RUN apk add --no-cache ca-certificates \
                       git \
                       python3 \
                       py3-pip \
                       openssh-client \
                       openssl \
                       rsync \
                       sshpass \
                       sudo \
    && \
    pip3 install --ignore-installed \
                 --break-system-packages \
                 -r /requirements.txt \
    && \
    ansible-galaxy install -r /requirements.yml \
    && \
    mkdir -p /ansible \
    && \
    rm -rf /root/.cache \
           /requirements.txt \
           /requirements.yml

WORKDIR /ansible

ENTRYPOINT ["ansible-playbook"]
CMD ["--version"]

De Node versie zou best geüpgraded mogen worden. In de requirements.txt had ik dan o.a. Ansible staan:

code:
1
2
ansible-core==2.18.6
ansible-lint==25.6.1

En in de requirements.yml stonden dan mijn (externe) roles en collections.

Ik regel dit dus nu in mijn Ansible / infra / Docker repo. Om toch repeatable builds te krijgen heb ik een aantal bestanden aangemaakt:
  • .python-version
  • requirements.txt
  • requirements.yml
Bij het starten van de workflow gebruikt de Forgejo Act runner de generieke setup-python action. Die action gebruikt vervolgens het .python-version bestand om de Python versie te bepalen die geïnstalleerd wordt. Python wordt geïnstalleerd in de hosted tool cache die gedeeld wordt tussen builds. Dezelfde action zet direct ook een cache op voor Python requirements, waar Ansible ook in staat :).

In dezelfde repo heb ik ook een setup.sh script staan voor op mijn workstation. Vanuit daar wordt, wanneer nodig, pyenv geïnstalleerd en geconfigureerd. Ik heb ook nog gekeken naar uv, maar dat project was nog niet volwassen genoeg om effectief te zijn. In datzelfde script installeer ik vervolgens wederom dependencies, maar dan dus in een virtualenv binnen pyenv. Ook controleert dit script op een vault pass en kan deze direct geconfigureerd worden. Afijn, alles om te starten.

  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 20:49
Mars Warrior schreef op zondag 7 december 2025 @ 13:59:
Zo'n [SOPS] bestand kun je dus ook gewoon in Git gooien. Niemand kan er wat mee. Decrypten is met je SSH key, die je toch nodig hebt voor Ansible om te kunnen deployen. Dus onderdeel van de Action of een Playbook 8)
Dus hetzelfde als Ansible Vault, maar dan moet ik nog een extra tool hebben en integreert het niet lekker met Ansible :+.

Ik zou ook mijn SSH key kunnen gebruiken als vault pass. Dat is immers gewoon een string. Als je echter in een team werkt is dat onhandig. Bij mij is dit dus gewoon een shared secret die toevallig alleen ik gebruik.
blackd schreef op zondag 7 december 2025 @ 18:55:
@Mars Warrior Ja, dat kan natuurlijk ook. Maar dat kan met Ansible Vault ook.
Ik heb ervoor gekozen om alle secrets in 1 yaml bestand te zetten en die in zijn geheel te encrypten.
Ik heb per group en host vault bestanden. De setup die je eerder aangaf met mappings (bijv. vault.my_secret) gebruik ik expliciet niet. Ik heb liever expliciete variabelen, dus vault_my_secret. Dat komt omdat ik in het verleden wat nare ervaringen heb gehad met het samenvoegen van dergelijke objecten en onverwachte resultaten. Maar goed, dat is natuurlijk stijl :).
Houd er in de keuze van je oplossing wel rekening mee of je nog andere tooling gebruikt om je bestanden te verwerken. Je hebt al VSCode benoemd. Maar ik draai zelf Ansible Lint en Docker Compose Lint (ook als GitHub action) bij elke pull request om de repo te valideren.
:Y

Bij elke push / PR draait Ansible Lint op mijn Git server:

YAML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
jobs:
  ansible-lint:
    name: Ansible Lint
    runs-on: ubuntu-latest

    steps:
      - name: ⤵️ Checkout repository
        uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6

      - name: 🏗️ Setup Ansible
        id: setup-ansible
        uses: ./.forgejo/actions/setup-ansible
        with:
          vault-pass: ${{ secrets.ANSIBLE_VAULT_KEY }}

      - name: 🕵️‍♀️ Run Ansible Lint
        run: ansible-lint
        env:
          ANSIBLE_VAULT_PASSWORD_FILE: >-
            ${{ steps.setup-ansible.outputs.vault-pass-file }}

ansible-lint zit namelijk in de requirements.txt en wordt standaard mee geïnstalleerd :D.

Ook gebruik ik pre-commit hooks om Ansible Lint te draaien voordat ik commit. Dat heeft ook al enkele oopsies voorkomen en was verrassend eenvoudig op te zetten. Tevens heb ik een eigen pre-commit hook gemaakt die controleert op Ansible Vault files en de commit abort wanneer ik dergelijke bestanden in plain text probeer te committen.

Docker Compose Lint lijkt me interessant, behalve dan dat ik dus mijn Compose bestanden maak met Jinja :|. Daar moet ik dus nog even vanaf zien. Anderzijds valideer ik Compose bestanden sowieso voor een Up.

  • blackd
  • Registratie: Februari 2001
  • Niet online
alex3305 schreef op zondag 7 december 2025 @ 19:40:
Dat heb ik ook een tijdje gehad, maar vond ik onhandig. Ik wil op mijn workstation niet per se afhankelijk zijn van Docker / devcontainers en/of Visual Studio Code. Ook wilde ik graag mijn Ansible requirements graag meenemen in de container. Daardoor had ik echter twee keer dezelfde dependencies in twee aparte repo's. Dat voelde niet zo lekker.
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.

Ik heb nu inderdaad requirements.yml dubbel geadministreerd staan, dat vind ik wel jammer aan deze setup. Ansible-Lint heeft 'm ook gewoon in de project dir nodig.
Mijn oplossing: een sync d.m.v. een github action van de ene repo naar de andere met deze action.

Ik had eerst de execution environment in dezelfde repo staan (geinspireerd door dbrennand op GitHub) maar dat werd een rommeltje met twee aparte releases in 1 project.
alex3305 schreef op zondag 7 december 2025 @ 19:48:
Ook gebruik ik pre-commit hooks om Ansible Lint te draaien voordat ik commit. Dat heeft ook al enkele oopsies voorkomen en was verrassend eenvoudig op te zetten. Tevens heb ik een eigen pre-commit hook gemaakt die controleert op Ansible Vault files en de commit abort wanneer ik dergelijke bestanden in plain text probeer te committen.
Dat staat nog op mijn wensenlijstje.
Docker Compose Lint lijkt me interessant, behalve dan dat ik dus mijn Compose bestanden maak met Jinja :|. Daar moet ik dus nog even vanaf zien. Anderzijds valideer ik Compose bestanden sowieso voor een Up.
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.

Voorbeeldje docker-compose.yml in jellyfin role (snippet):
YAML:
1
2
3
4
5
6
7
8
services:
  jellyfin:
    image: jellyfin/jellyfin:10.11.4@sha256:aab0b50a3ce43a41621fc7040a379cc57174059aec8f9c17a90176649a0c1ab1
    container_name: jellyfin
    volumes:
      - ${HOST_VOLUME_CONFIG}:/config
      - ${HOST_VOLUME_CACHE}:/cache
      - ${HOST_VOLUME_MEDIA}:/media

.env.j2
YAML:
1
2
3
HOST_VOLUME_CONFIG="{{ jellyfin__compose_volume_config }}"
HOST_VOLUME_CACHE="{{ jellyfin__compose_volume_cache }}"
HOST_VOLUME_MEDIA="{{ jellyfin__compose_volume_media }}"

9000Wp o/w SolarEdge SE6K - Panasonic 5kW bi-bloc - gasloos sinds 17-7-2023


  • alex3305
  • Registratie: Januari 2004
  • Laatst online: 20:49
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 :F. 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.

  • Mars Warrior
  • Registratie: Oktober 2003
  • Laatst online: 00:10

Mars Warrior

Earth, the final frontier

blackd schreef op zondag 7 december 2025 @ 20:29:
[...]
Voorbeeldje docker-compose.yml in jellyfin role (snippet):
YAML:
1
2
3
4
5
6
7
8
services:
  jellyfin:
    image: jellyfin/jellyfin:10.11.4@sha256:aab0b50a3ce43a41621fc7040a379cc57174059aec8f9c17a90176649a0c1ab1
    container_name: jellyfin
    volumes:
      - ${HOST_VOLUME_CONFIG}:/config
      - ${HOST_VOLUME_CACHE}:/cache
      - ${HOST_VOLUME_MEDIA}:/media

.env.j2
YAML:
1
2
3
HOST_VOLUME_CONFIG="{{ jellyfin__compose_volume_config }}"
HOST_VOLUME_CACHE="{{ jellyfin__compose_volume_cache }}"
HOST_VOLUME_MEDIA="{{ jellyfin__compose_volume_media }}"
W44r0m z0 dµßß13 0p?? W44r0m n13t m33t33n 1n d3 3nv f1l3 d3 ju1$t3 k3¥ v4|u3z?? Nu m00t j3 t0¢h 3 d1ng3n b1jh0µd3n!! D4t 0nt9a4t m1j 3v3n…

0ƒ h33ƒt d4t t3 m4k3n m3t d3 V4µ|t??

Material 3 Thema's voor HA | Swiss Army Knife custom card voor HA | AmoebeLabs


  • blackd
  • Registratie: Februari 2001
  • Niet online
@alex3305 ja dat soort uitgebreidere jinja templating gebruik ik niet. Eigenlijk moet ik zeggen dat ik de template module gebruik, maar ik template niks, want ik kan net zo goed een copy doen. Anders snapt dclint het niet.

@Mars Warrior
In de .env file staan bij mij verschillende soorten waardes, bijv:
- secrets. Die staan zoals gezegd in een apart bestand bij mij.
- host afhankelijke waardes, die worden gevoed door group vars of host vars.

In dit voorbeeld staan absolute paden en die kunnen dus per host in theorie verschillend zijn. Dat wil je niet in je role vastleggen, die dient generiek te zijn.

Daarnaast kan ik de paden als het een variabele in ansible is, hergebruiken. Bijv voor aanmaken dataset, controleren permissies, dat soort zaken.

Ik ben overigens nog wel zoekende naar de juiste structuur qua variabelen. Ik heb laatst variabelen in playbooks gemigreerd naar group_vars. Maar e.e.a kan vast nog beter georganiseerd.

9000Wp o/w SolarEdge SE6K - Panasonic 5kW bi-bloc - gasloos sinds 17-7-2023

Pagina: 1 ... 16 17 Laatste