We have a generic toolkit image from ansible
podman run --rm -it \
-v "$HOME/camelot":/camelot:Z \
-v "$HOME/.ssh":/home/runner/.ssh:ro,Z \
-w /camelot \
ghcr.io/ansible/community-ansible-dev-tools:latest \
/bin/bashIt has to learn to trust eckford
# Inside a fresh Ansible container, trust the remote SSH host first.
mkdir -p ~/.ssh
ssh-keyscan -H eckford.ca >> ~/.ssh/known_hosts
chmod 700 ~/.ssh
chmod 600 ~/.ssh/known_hosts
ansible-playbook -i inventory.ini refresh_get_smart.yml --ask-passA container image should be agnostic.
But what we changed was not really “the container image.” We changed the running container instance.
Important distinction:
Image:
ghcr.io/ansible/community-ansible-dev-tools:latest
reusable, portable, unchanged
Running container:
temporary live copy of that image
got ~/.ssh/known_hosts added
disappears when --rm exits
So no, the image did not become tied to eckford.ca.
What happened:
Container image:
generic Ansible toolbox
Container runtime session:
"for this session, I trust eckford.ca"
That is actually the correct boundary.
We do not want to bake eckford.ca into the generic Ansible image. That would make the image project/site-aware, which is the thing we are pushing against.
The cleaner architecture is:
Generic Ansible container
+
Mounted project/control data
- playbooks
- inventory
- known_hosts
- maybe SSH config
=
Project-aware run
So the portable version is not:
Build a special Get Smart containerIt is:
Run a generic Ansible container with the right external SSH trust file mounted in.Example:
podman run --rm -it \
--user root \
-v "$HOME/camelot":/camelot:Z \
-v "$HOME/.ssh/known_hosts":/root/.ssh/known_hosts:ro,Z \
-w /camelot/get-smart \
ghcr.io/ansible/community-ansible-dev-tools:latest \
/bin/bashThat keeps the container agnostic. The host-specific facts live outside it.
Even better later:
~/camelot/ansible-control/
ssh/
known_hosts
inventories/
navigator/
notes/Then mount that:
-v "$HOME/camelot/ansible-control/ssh/known_hosts":/root/.ssh/known_hosts:ro,ZThat makes the model crisp:
Container = tools
ansible-control = operator memory
get-smart = project
eckford.ca = target
Today’s ssh-keyscan was a live diagnostic and first-run bootstrap. It is not the final architecture. The final architecture is externalized known_hosts, not baked-in known_hosts.
The container can still move. It just needs the local operator packet beside it: inventory, playbook, and trusted host fingerprints.
Local Config
(ansible-navigator) [CML] tux@localhost …/camelot/ansible-control $ mkdir -p ~/camelot/ansible-control/ssh
mkdir -p ~/camelot/ansible-control/bin
(ansible-navigator) [CML] tux@localhost …/camelot/ansible-control $ cp ~/.ssh/known_hosts ~/camelot/ansible-control/ssh/known_hosts
chmod 600 ~/camelot/ansible-control/ssh/known_hosts
(ansible-navigator) [CML] tux@localhost …/camelot/ansible-control $ podman run --rm -it \
-v "$HOME/camelot":/camelot:Z \
-v "$HOME/camelot/ansible-control/ssh":/home/runner/.ssh:ro,Z \
-w /camelot \
ghcr.io/ansible/community-ansible-dev-tools:latest \
/bin/bash
bash-5.2#
The container itself provides:
ansible --version
ansible-playbook --version
ansible-navigator --version
ansible-lint --version
ansible-builder --version
ansible-galaxy --version
python3 --versionwithout depending on Camelot’s local Python/venv setup.
See also:
Getting Started with Ansible Navigator by Open Source Ops.
Skipping the orientation until the machine growls once is a perfectly valid learning style. Slightly feral. Highly effective.