Run Command Inside of Docker Container Using Ansible

54,091

Solution 1

You should be able to execute a script (with your sequence of command in it) with docker exec:

docker exec container-name bash -l -c /path/to/script > /path/to/log

(See also "Why do I have to use bash -l -c inside my container?")

  • /path/to/script should be accessible by your Ansible process.
  • /path/to/log is a path inside the container, that could be shared in a volume.

Solution 2

After discussion with some very helpful developers on the ansible github project, a better way to do this is like so:

- name: add container to inventory
  add_host:
    name: [container-name]
    ansible_connection: docker
  changed_when: false

- name: run command in container
  delegate_to: [container-name]
  raw: bash

If you have python installed in your image, you can use the command module or any other module instead of raw.

If you want to do this on a remote docker host, add:

ansible_docker_extra_args: "-H=tcp://[docker-host]:[api port]"

to the add_host block.

See the Ansible documentation for a more complete example.

Solution 3

You can run commands within docker containers using the command module For example this code will execute echo "Hello remote machine" within my_container on the remote machine:

   tasks:
        - name: Execute commands in docker container
          command: docker exec -it my_container bash -c 'echo "Hello remote machine"'

For running the same command within the local machine, just use the local_action flag:

   tasks:
        - name: Execute commands in docker container
          local_action: command docker exec -it my_container bash -c 'echo "Hello local machine"'

Solution 4

Since Ansible 2.10 docker_container_exec is part of the community.docker collection:

- name: Run a simple command (command)
  community.docker.docker_container_exec:
    container: foo
    command: /bin/bash -c "ls -lah"
    chdir: /root
  register: result

- name: Print stdout
  debug:
    var: result.stdout
Share:
54,091
Nigel Earle
Author by

Nigel Earle

Always learning and growing. Love building full-stack JavaScript web applications!

Updated on July 09, 2022

Comments

  • Nigel Earle
    Nigel Earle almost 2 years

    what I'm trying to accomplish is to run commands inside of a Docker container that has already been created on a Digital Ocean Ubuntu/Docker Droplet using Ansible.

    Can't seem to find anything on this, or I'm majorly missing something. This is my Ansible task in my play book. I'm very new to Ansible so any advice or wisdom would be greatly appreciated.

    - name: Test Deploy
        hosts: [my-cluster-of-servers]
    
    tasks: 
      - name: Go Into Docker Container And Run Multiple Commands
        docker:
          name: [container-name]
          image: [image-ive-created-container-with-on-server]
          state: present
          command: docker exec -it [container-name] bash
    
  • schmidlop
    schmidlop over 8 years
    Could you clarify the meaning of "should be accessible by your Ansible process."? Does that mean the script should be on the ansible control machine? The docker host? or inside the container?
  • VonC
    VonC over 8 years
    @schmidlop I meant: there is an container already running. Inside that container, there is /path/to/script which did not execute properly. A way to try again that script is to execute it (from a docker exec command run from the Linux host) and log its results on the host in /path/to/log
  • VonC
    VonC over 8 years
    @schmidlop I agree. My answer is meant to be run from the docker host.
  • Bernie
    Bernie over 7 years
    This works if the docker container is on the same machine on which the ansible script is running. What if the docker container is running on a different machine?
  • VonC
    VonC over 7 years
    Interesting, and more precise than my answer. +1
  • techraf
    techraf over 7 years
    Thanks for help. As usually, restarting from scratch resolved problems.
  • DMCoding
    DMCoding over 7 years
    I don't believe that's true, @Bernie. My understanding is that local_action does as you describe, but the command module always runs on the remote host, unless the delegate_to parameter is supplied.
  • RichVel
    RichVel about 7 years
    This does require Docker API access to the host with the Docker Engine (if not localhost) - if firewall rules block this, you may need to use the docker exec ... bash -c ... approach. I don't see how you could use delegate_to for the remote host, since it's already being used for the docker connection to container.
  • vikas027
    vikas027 almost 7 years
    I had to use docker exec -i <my_container> to avoid this error the input device is not a TTY
  • Christian Berendt
    Christian Berendt about 6 years
    The PR was not merged and the author closed it with the note "I admit now, there is no point to my module.".
  • idjaw
    idjaw almost 6 years
    This answer should be updated to reflect that the MR is closed. The upvotes are misleading as well. Unless the code can be directly shared as an alternative where someone can leverage this as their own custom plugin to do this?
  • Bernie
    Bernie almost 6 years
    @idjaw See the first line of the answer. Also, if you read through the comments in the pull request it seems like there may be some value to the plugin after all. I was able to solve my problem at the time without using the plugin, so have left it for others to take the code from my pull request and use it as they see fit. The code is still available in the pull request: github.com/ansible/ansible/pull/20112/files. I haven't copied it here as I think it's easily enough accessible from GitHub.
  • idjaw
    idjaw almost 6 years
    @Bernie Thanks for the message back! (I just noticed the 'other' answer is your answer as well.... :)). The other answer did in fact help me get on track to solving my problem. I ended up doing something like this when it came to the execution of the actual command. My challenge was having to copy a templated file to the container, while wanting to minimize custom docker commands in shell to facilitate testing for idempotent behaviour. Thanks again. :)
  • Ayra
    Ayra over 5 years
    I know it's been a long time but anyone would be abble to explain why did he put the "changed_when: false" to make it worked ?
  • Jack_Hu
    Jack_Hu over 5 years
    @Ayra - It's not strictly necessary. It will just make the play feedback show: ok: [127.0.0.1], instead of: changed: [127.0.0.1] -- It's just arguably more descriptive of what's going on, as the host has been added, rather than changed (when talking about it in English anyway).
  • Mani
    Mani almost 5 years
    Is there a way to use this to run commands inside docker container in remote hosts?
  • Mani
    Mani almost 5 years
    @Bernie No that's not the proper thing to do when you use Ansible. I was looking into something like using docker_container with delegate_to.
  • Bernie
    Bernie almost 5 years
    @Mani Well, if you say so. You can read through my discussion with the Ansible devs here, along with the link to the Ansible documentation on non-ssh connections at the end of the answer. This answer is more than 2 years old, if it doesn't answer your question, perhaps you need to ask a new one.
  • Vano
    Vano over 4 years
    @Mani has a point. One don't necessarily has to configure custom remote docker deamon access. Just access docker locally from the target host... Mani plz share if you found a way...
  • Liam
    Liam over 3 years
    Just a note to be careful if you're using ansible_ssh_user, especially via the CLI, as it'll try to login to that user on the container.
  • shgnInc
    shgnInc about 3 years
    The link for non-ssh-connection-types has been broken and the right one is: docs.ansible.com/ansible/latest/user_guide/…
  • VonC
    VonC almost 3 years
    That seems a more up-to-date approach than my answer. Upvoted.