Docker - Ansible

Hi all,

I have the followinig topology

Host server redhat 7.4
Docker version 1.13
Container Centos centos:7.3.1611
Inside my container, I have ansible 2.4.0.0
My playbooks are inside the redhat (not in the container)

When I execute the playbook from the redhat server I get error “unable to open shell”

If I execute the playbook inside the redhat server directly and not from the container I don’t have any issue.

Thanks.!

What is it you are trying to do? How did you build your ansible image?

It sounds like you are trying to run playbooks that are physically on your RedHat host from the ansible command that is inside your CentOS container which means you must share a volume between the host and the container so that the playbooks can be seen. Then when you invoke docker, you must map that volume to the location of the playbooks on your host.

Here is a sample Dockerfile using Alpine (sorry I don’t do CentOS):

FROM alpine:3.6
RUN apk update && apk add --no-cache \
    openssl \
    ca-certificates \
    python \
    py-pip \
    python-dev \
    libffi-dev \
    openssl-dev \
    build-base \
    git
RUN pip install ansible
WORKDIR /playbooks
VOLUME /playbooks
CMD [ "ansible", "--version" ]

Notice that it includes VOLUME /playbooks which exposes the WORKDIR /playbooks volume inside the container. Then when you run it, you map it to the location of the playbooks on your host.

Using this Dockerfile you can build an image called ansible:alpine like this:

docker build -t ansible:alpine .

Then, for example, if the playbooks are in the current folder, and the main playbook was called playbook.yaml, you would run it like this:

docker run --rm -it -v $(PWD):/playbooks ansible:alpine ansible-playbook -v playbook.yaml

That will run ansible-playbook from with in the container using the playbooks that are on your host mapping your current folder $(PWD) to /playbooks inside the container.

~jr

If you’re installing a full C toolchain and build environment, this will not be a small image. Alpine has some well-documented minor binary compatibility issues, depending on what you’re installing, and the usual motivation for using it is to push an image over from “small” to “tiny”. I’d start from a standard full-featured distribution here (probably ubuntu:16.04, but that’s a matter of taste).

You’re allowed to use docker run -v on any directory, even if it’s not explicitly declared as a VOLUME. I’d only use this declaration for things that are data that need to be persisted between container executions (VOLUME /var/lib/mysql). I wouldn’t use it for points where you expect the caller to inject a host directory, like here; its only real effect would be to leak empty volumes if the caller forgets to use an appropriate -v option.

(On the higher-level question, I’d re-emphasize that Docker containers and VMs are different beasts and an Ansible playbook that installs software on a VM or bare metal probably isn’t 100% right for a Docker image. My recommendation would be to use a Dockerfile and the native Docker build sequence if at all possible. If you’re really set on Ansible, you might look into Hashicorp’s Packer tool as a path to use it to build “an image”, which could be a Docker image or a VM image or an Amazon AMI or something else.)

Indeed it would not be small but I did not intend for my example to be the final solution. I assume the original poster would have done something similar using CentOS and I did not want to confuse the topic of image size since it was not relevant to their understanding of why this might not have worked for them but since you brought it up… yes, that image will be 318MB which is not only large, but it is dangerous to deploy an image with a full development environment in it just waiting to be exploited.

If I were to build that image I would use this:

FROM alpine:3.6
RUN \
  RUN_DEPS='openssl ca-certificates python py-pip' \
  BUILD_DEPS='python-dev libffi-dev openssl-dev build-base' \
  && apk update && apk add --no-cache $RUN_DEPS $BUILD_DEPS \
  && pip install ansible \
  && apk del $BUILD_DEPS \
  && rm -rf /tmp/*

WORKDIR /playbooks
VOLUME /playbooks
CMD [ "ansible", "--version" ]

Which would result in a 123MB image which is smaller than a base CentOS image which starts at 197MB and it would have no development tools left on it.

Wow, I didn’t realize that. I thought that you had to expose all volumes that you wanted to mount. That’s cool and disturbing all at the same time because any volume can be replaced at run-time. That gives a whole new meaning to immutability when you can substitute volumes like that (e.g., I think I’m running with the /usr volume I built the image with and it gets substituted for a different /usr volume at runtime and perhaps has totally different behavior). Thanks for pointing that out.

I believe that you and I read the original post very differently which is why I asked what they were trying to accomplish because it wasn’t completely clear to me. I assumed that they didn’t want to install Ansible but rather wanted to run it from a container with playbooks that were installed on the host. In this context I believe that exporting a VOLUME is appropriate because the container needs the playbooks which are its “data” source.

It sounds like you read the post as they are trying to run ansible on the container itself in order to modify it. I didn’t read it that way and I agree with you that it makes little sense and you should use a Dockerfile instead.

~jr