Important preliminary note: I urge you to read the comments from DavidMaze and β.εηοιτ.βε above regarding good practice to understand why you don't want to go through ansible in your specific case and you should not modify a running container.
Meanwhile, since there are other use cases (like testing ansible roles inside a docker container), I'll still answer the overall question hopping that all the above warnings were enough for you to use that information very wisely.
To start with, if you want to deploy and run your image with ansible, it should be done using the relevant docker_container
module rather than calling shell
.
Once this is done, ansible has a docker
connection plugin that will let you interact with containers on your host 1. The idea is to have an entry in your inventory for the relevant container using the correctly configured connection. You can then use a normal play host loop with usual ansible tasks to reach your remote target container 2.
In my example below, I deploy an image and add it to the in-memory inventory in the same playbook using the add_host
module. Those two actions can be done totally independently and there are several options to add your containers to an inventory among which the docker_containers
dynamic inventory plugin.
I used the following test.j2
template for this test
Dummy template
Node name: {{ ansible_nodename }}
Environment:
{{ ansible_env | to_nice_yaml }}
This the demo playbook.yml
:
---
- name: spin-up container and add to inventory
hosts: localhost
gather_facts: false
vars:
container_name: my_test_container
tasks:
- name: Deploy a dummy container
docker_container:
name: "{{ container_name }}"
image: python:latest
command: tail -f /dev/null
state: started
- name: store container name as a fact on localhost for later use in last play
set_fact:
container_name: "{{ container_name }}"
- name: Add the created container to inventory
add_host:
name: "{{ container_name }}"
groups:
- docker_test
ansible_connection: docker
- name: do some stuff on container
hosts: docker_test
tasks:
- name: show a gathered info from the container
debug:
var: ansible_os_family
- name: test our template is deployable
template:
src: test.j2
dest: /test.txt
- name: get result back to check
slurp:
path: /test.txt
register: deploy_template
- name: show result
debug:
msg: "{{ (deploy_template.content | b64decode).split('\n') }}"
# Put here anything else that should target your container(s)
- name: do some cleanup
hosts: localhost
gather_facts: false
tasks:
- name: destroy test container
docker_container:
name: "{{ container_name }}"
state: absent
Which gives:
$ ansible-playbook playbook.yml
PLAY [spin-up container and add to inventory] *******************************
TASK [Deploy a dummy container] *********************************************
changed: [localhost]
TASK [store container name as a fact on localhost for later use in last play] *
ok: [localhost]
TASK [Add the created container to inventory] *******************************
changed: [localhost]
PLAY [do some stuff on container] *******************************************
TASK [Gathering Facts] ******************************************************
ok: [my_test_container]
TASK [show a gathered info from the container] ******************************
ok: [my_test_container] => {
"ansible_os_family": "Debian"
}
TASK [test our template is deployable] **************************************
changed: [my_test_container]
TASK [get result back to check] *********************************************
ok: [my_test_container]
TASK [show result] **********************************************************
ok: [my_test_container] => {
"msg": [
"Dummy template",
"Node name: 1608185a4e43",
"Environment:",
"GPG_KEY: A035C8C19219BA821ECEA86B64E628F8D684696D",
"HOME: /root",
"HOSTNAME: 1608185a4e43",
"LANG: C.UTF-8",
"PATH: /usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"PWD: /",
"PYTHON_GET_PIP_SHA256: c518250e91a70d7b20cceb15272209a4ded2a0c263ae5776f129e0d9b5674309",
"PYTHON_GET_PIP_URL: https://github.com/pypa/get-pip/raw/3cb8888cc2869620f57d5d2da64da38f516078c7/public/get-pip.py",
"PYTHON_PIP_VERSION: 21.2.4",
"PYTHON_SETUPTOOLS_VERSION: 57.5.0",
"PYTHON_VERSION: 3.10.2",
""
]
}
PLAY [do some cleanup] ******************************************************
TASK [destroy test container] ***********************************************
changed: [localhost]
PLAY RECAP ******************************************************************
localhost: ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
my_test_container: ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1 docker
plugin uses the docker cli to run commands. If you prefer to use the api directly, you can do the same thing with the docker-api
plugin
2 Note that your target container will need to satisfy to ansible managed nodes requirements and have python installed