J'avais écrit dans cette PR « je n'ai pas pu construire l'image, sa base vit
derrière le certificat interne ». C'était une SUPPOSITION NON TESTÉE, et elle est
fausse : `docker pull gitea.arcodange.lab/…/runner-images:ubuntu-latest-ca` passe
sans rien configurer. En la construisant vraiment, deux défauts sont sortis — et
aucun n'était visible à la lecture du Dockerfile.
1. `runner-images:ubuntu-latest-ca` LIVRE NODE 18 (v18.20.8). Or `nuxi` importe
`node:util.styleText`, absent de Node 18 : c'est la raison d'être du
`container: node:20-bookworm` de la CI de kadans, que son CLAUDE.md interdit
de retirer. Sans correctif, basculer la CI sur cette image cassait `nuxt build`
sur un message parlant d'un import introuvable — jamais d'une version de Node.
→ Node 20 installé depuis NodeSource.
2. ET INSTALLER NE SUFFISAIT PAS. Après l'installation, `node --version` rendait
TOUJOURS v18.20.8 : l'image de base précuit un node pour le toolcache d'act et
le met EN TÊTE du PATH.
which node → /opt/acttoolcache/node/18.20.8/arm64/bin/node
/usr/bin/node --version → v20.20.2 ← le bon, mais il PERD
→ l'entrée 18 du toolcache est retirée ; la résolution retombe sur
/usr/bin/node. ⚠ Conséquence assumée : `actions/setup-node` ne trouvera plus
de Node 18 préinstallé — aucun workflow de kadans ne l'utilise, et l'image
n'est servie qu'aux jobs qui DEMANDENT le label.
Le Dockerfile porte désormais une ASSERTION DE BUILD
(`node --version | grep -q "^v${NODE_MAJOR}\."`) : l'image ne peut plus se
construire si la résolution redevient mauvaise. Et le rôle vérifie la version au
déploiement (`failed_when`), au lieu de la supposer.
MESURES RÉELLES (construite en linux/arm64, l'architecture des runners) :
TOTAL 4,58 Go
├─ playwright install chromium 1,01 Go
├─ playwright install-deps 405 Mo
├─ Node 20 (NodeSource) 183 Mo
└─ bun 179 Mo
Vérifié dans l'image : which node → /usr/bin/node v20.20.2 · bun 1.3.14 ·
chromium-1228 + headless-shell + ffmpeg · /etc/ci-base.versions cohérent.
⚠ Ce que ces chiffres tranchent : le découpage en RUN séparés N'A PAS suffi à
rendre l'image poussable — 1,01 Go pour la plus grosse couche, soit ~4× les
261 Mo que le registre accepte (runner-images:ubuntu-latest-ca). Le build LOCAL
n'est donc pas une préférence, c'est la seule voie. Mesuré, plus supposé.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Use Ansible
Run locally (uv)
A project-local venv is defined in pyproject.toml at the repo root (ansible-core + the kubernetes, jmespath, dnspython libraries that kubernetes.core and friends need at runtime).
uv sync # creates .venv/ and installs ansible-core + python deps
uv run ansible-galaxy collection install -r ansible/requirements.yml
uv run ansible-playbook -i ansible/arcodange/factory/inventory ansible/arcodange/factory/playbooks/<playbook>.yml
The localhost entry in the inventory uses ansible_python_interpreter: "{{ ansible_playbook_python }}", so uv run is enough — Ansible picks up the venv's Python automatically without any hardcoded path.
Run with docker ssh agent side proxy
build docker images
git clone -q --depth 1 --branch master https://github.com/arcodange/ssh-agent.git /tmp/ssh-agent
(cd /tmp/ssh-agent ; docker build -t docker-ssh-agent:latest -f Dockerfile . ; rm -rf /tmp/ssh-agent)
(cd ansible; docker build -t arcodange-ansible:0.0.0 .)
run in container
# git clone -q --depth 1 --branch master https://github.com/arcodange/ssh-agent.git /tmp/ssh-agent
# (cd /tmp/ssh-agent ; docker build -t docker-ssh-agent:latest -f Dockerfile . ; rm -rf /tmp/ssh-agent)
# (cd ansible; docker build -t arcodange-ansible:0.0.0 .)
docker run -d --name=ssh-agent docker-ssh-agent:latest
docker run --rm --volumes-from=ssh-agent -v ~/.ssh:/.ssh -it docker-ssh-agent:latest ssh-add /root/.ssh/id_rsa
docker run --rm -u root --name test --volumes-from=ssh-agent -v $PWD:/home/arcodange/code \
-v "$HOME"/.kube/config:/home/arcodange/.kube/config \
-e ANSIBLE_VAULT_PASSWORD_FILE=$ANSIBLE_VAULT_PASSWORD_FILE -v $ANSIBLE_VAULT_PASSWORD_FILE:$ANSIBLE_VAULT_PASSWORD_FILE \
arcodange-ansible:0.0.0 \
ansible-playbook ansible/arcodange/factory/playbooks/03_cicd.yml -i ansible/arcodange/factory/inventory -vv
use vault with single password
Important
Required for gitea mailer
kubectl create secret generic arcodange-ansible-vault --from-literal="pass=<ansible_vault_password>" -n kube-system`to be set as a file variable for gitea runners
ANSIBLE_VAULT_PASSWORD_FILE=~/.local/bin/read-vault-key.sh;
mkdir -p `dirname $ANSIBLE_VAULT_PASSWORD_FILE`; set +o histexpand;
echo -e "#!/bin/bash\nkubectl get secret -n kube-system arcodange-ansible-vault --template='{{index .data.pass | base64decode}}'" > $ANSIBLE_VAULT_PASSWORD_FILE;
set -o histexpand; chmod +x $ANSIBLE_VAULT_PASSWORD_FILE; echo "export ANSIBLE_VAULT_PASSWORD_FILE=$ANSIBLE_VAULT_PASSWORD_FILE" >> `find ~ -maxdepth 1 -type f -name '\.*profile' -or -name '\.bashrc' -or -name '\.zshenv' | head -n1`
export ANSIBLE_VAULT_PASSWORD_FILE
a tool to reuse a ssh agent (not required)
FIND_SSH_AGENT=$HOME/.local/bin/ssh-find-agent
curl -s https://raw.githubusercontent.com/wwalker/ssh-find-agent/master/ssh-find-agent.sh > $FIND_SSH_AGENT
chmod +x $FIND_SSH_AGENT
echo 'ssh_find_agent "$@"' >> $FIND_SSH_AGENT
which brew && brew install coreutils # if on macos
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa
dev
test an expression
ansible -i ,localhost -c local localhost -m raw -a "echo hello world {{ inventory_hostname }} : {{ hostvars | to_nice_json | regex_replace(\"['\n]\",' ') }}"
local python environment with uv
Install UV (one-time)
python3 -m pip install uv
python3 -m uv python install 3.12
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshenv
Bootstrap the project venv
uv sync # honors .python-version (3.12) and pyproject.toml
uv run ansible-galaxy collection install -r ansible/requirements.yml
# `--token <token>` is only needed if you hit galaxy.ansible.com rate limits
Run
uv run ansible-galaxy collection install ./ansible/arcodange/factory -f
uv run ansible-playbook -i ansible/arcodange/factory/inventory ansible/arcodange/factory/playbooks/02_setup.yml