Ansible using a Docker Container
Purpose
Learning how Ansible works by automating updates from several of my LXC containers with services.
Hurdle
Same as always with Docker, the container runs a user root and create files not accessible by a regular user.
To solve this issue the ansible* commands are intercepted using the /usr/local/bin directory
which is first in the path from the container.
The file /usr/local/bin/ansible-reroute.sh symlinked for the ansible command.
#set -x
# Exit at first error.
set -e
if [[ ! -L "$0" ]]; then
echo "Script '$0' can only be called when symbolic linked!"
exit 1
fi
# Add the group ans user for the pass user id's.
addgroup --gid "${GROUP_ID}" ansible
adduser --uid "${USER_ID}" --ingroup ansible --disabled-password --gecos '' ansible
# The command is the name of the symlink.
cmd="$(basename "$0")"
# Call the actual ansible command as the 'ansible' user.
su - ansible -c "env ANSIBLE_LOCAL_TEMP=${ANSIBLE_LOCAL_TEMP} env ANSIBLE_HOME=${ANSIBLE_HOME} env ANSIBLE_CONFIG=${ANSIBLE_CONFIG} $(
printf '%q ' "/usr/bin/${cmd}" "${@}"
)"
The actual command is then executed as the ansible user which has the same user id as the host.
The script ansible.sh bellow, which is also symlinked for each command, is executed on the Docker host
#!/usr/bin/env bash
#set -x
# Exit at first error.
set -e
if [[ ! -L "$0" ]]; then
echo "Script '$0' can only be called when symbolic linked!"
exit 1
fi
# Get the script directory.
script_dir="$(cd "$(dirname "${0}")" && pwd)"
# Get the to execute ansible command.
ansible_command="$(basename "$0")"
# Create rerouted command symlink for root user to execute.
symlink="${script_dir}/local-bin/${ansible_command}"
echo "symbolic: ${symlink}"
if [[ ! -L "${symlink}" ]]; then
ln -sr "${script_dir}/local-bin/ansible-reroute.sh" "${symlink}"
fi
# Used image name.
docker_image="alpine/ansible:latest"
# Form the docker command.
cmd=(docker run)
cmd+=(--interactive)
cmd+=(--tty)
cmd+=(--rm)
cmd+=(--hostname ansible)
#cmd+=(--user "$(id -u):$(id -g)")
cmd+=(--env USER_ID="$(id -u)" --env GROUP_ID="$(id -g)")
# This environment variable needs to be set before anything.
# Setting the variable from the by the ANSIBLE_CONFIG set file does not solve the problem of the chicken end the egg.
cmd+=(--env ANSIBLE_LOCAL_TEMP=/home/ansible/config/tmp)
# This environment variable is not picked up from the configuration file so it is set here.
cmd+=(--env ANSIBLE_HOME=/home/ansible)
cmd+=(--env ANSIBLE_CONFIG=/home/ansible/config/ansible.cfg)
cmd+=(--volume "${script_dir}/local-bin:/usr/local/bin:ro")
cmd+=(--volume "${script_dir}/secret/ssh:/home/ansible/.ssh:ro")
cmd+=(--volume "${script_dir}/secret/aws:/home/ansible/.aws:ro")
cmd+=(--volume "${script_dir}/config:/home/ansible/config")
# To make a error go away.
cmd+=(--volume "${script_dir}/config/tmp:/.ansible")
cmd+=(--workdir "/home/ansible")
cmd+=("${docker_image}")
# The command to execute.
if [[ $# -eq 0 ]]; then
cmd+=("bash")
else
# The command is the name of the symlink.
cmd+=("${ansible_command}")
fi
# Execute the command.
#echo "${cmd[@]}" "${@}"
"${cmd[@]}" "${@}"
This script sets the /usr/local/bin symlink for the command to be intercepted.