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/bash

It 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-pass

A 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 container

It 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/bash

That 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,Z

That 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 --version

without 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.