I would like to run multi-container application using docker-compose
on Mac OS X El Capitan (v10.11.2).
However, the command $ docker-compose up
command complains that it can't connect to the Docker daemon.
ERROR: Couldn't connect to Docker daemon - you might need to run
docker-machine start default
.
Only after executing $ eval "$(docker-machine env default)"
I do have access to the docker-compose
command.
Why is this and how can I overcome this extra step?
Docker.app
The Docker experience on macOS has improved since this answer was posted:
The only prerequisite is now for Docker.app
to be running. Note that starting it on demand takes a while, because the underlying Linux VM must be started.
Any shell then has access to Docker functionality.
By default, Docker.app
is launched at login time (you can change that via its preferences).
If you instead prefer starting and stopping Docker on demand from the command line, here are bash
scripts that do that, docker-start
and docker-stop
; place them anywhere in your $PATH
.
When docker-start
launches Docker.app
, it waits until Docker has finished starting up and is ready.
docker-start
:
#!/usr/bin/env bash
case $1 in
-h|--help)
echo $'usage: docker-start\n\nStarts Docker (Docker.app) on macOS and waits until the Docker environment is initialized.'
exit 0
;;
esac
(( $# )) && { echo "ARGUMENT ERROR: Unexpected argument(s) specified. Use -h for help." >&2; exit 2; }
[[ $(uname) == 'Darwin' ]] || { echo "This function only runs on macOS." >&2; exit 2; }
echo "-- Starting Docker.app, if necessary..."
open -g -a Docker.app || exit
# Wait for the server to start up, if applicable.
i=0
while ! docker system info &>/dev/null; do
(( i++ == 0 )) && printf %s '-- Waiting for Docker to finish starting up...' || printf '.'
sleep 1
done
(( i )) && printf '\n'
echo "-- Docker is ready."
docker-stop
:
#!/usr/bin/env bash
case $1 in
-h|--help)
echo $'usage: docker-stop\n\nStops Docker (Docker.app) on macOS.'
exit 0
;;
esac
(( $# )) && { echo "ARGUMENT ERROR: Unexpected argument(s) specified. Use -h for help." >&2; exit 2; }
[[ $(uname) == 'Darwin' ]] || { echo "This function only runs on macOS." >&2; exit 2; }
echo "-- Quitting Docker.app, if running..."
osascript - <<'EOF' || exit
tell application "Docker"
if it is running then quit it
end tell
EOF
echo "-- Docker is stopped."
echo "Caveat: Restarting it too quickly can cause errors."
Kevan Ahlquist's helpful answer shows what commands to add to your Bash profile (~/.bash_profile
) to automatically initialize Docker on opening an interactive shell.
Note that you can always initialize Docker in a new shell tab/window by opening application /Applications/Docker/Docker Quickstart Terminal.app
(e.g., via Spotlight).
From an existing shell, you can invoke it as open -a 'Docker Quickstart Terminal.app'
(which also opens a new shell tab).
What this answer offers is a convenient way to start Docker in the current shell.
Adding the Bash shell functions below - docker-start
and docker-stop
- improves on Kevan's approach in the following respects:
You can run docker-start
on demand, without the overhead of starting the VM on opening the shell (once the Docker VM is running, initialization is much faster, but still takes a noticeable amount of time).
(Of course, you can still opt to invoke docker-start
right from your profile.)
docker-stop
allows stopping Docker and cleaning up the environment variables on demand.
The functions ensure that Docker's error messages are not suppressed, and they pass Docker error exit codes through.
Additional status information is provided.
You may pass a VM name as a parameter; default is default
.
Example:
$ docker-start
-- Starting Docker VM 'default' (`docker-machine start default`; this will take a while)...
Starting "default"...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Machine "default" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
-- Setting DOCKER_* environment variables (`eval "$(docker-machine env default)"`)...
DOCKER_CERT_PATH="/Users/jdoe/.docker/machine/machines/default"
DOCKER_HOST="tcp://192.168.99.100:2376"
DOCKER_MACHINE_NAME="default"
DOCKER_TLS_VERIFY="1"
-- Docker VM 'default' is running.
$ docker-stop
-- Stopping Docker VM 'default' (`docker-machine stop default`)...
Stopping "default"...
Machine "default" was stopped.
-- Unsetting DOCKER_* environment variables (DOCKER_CERT_PATH, DOCKER_HOST, DOCKER_MACHINE_NAME, DOCKER_TLS_VERIFY)...
-- Docker VM 'default' is stopped.
Shell functions for on-demand starting and stopping of Docker (place them in, e.g., ~/.bash_profile
for global availability in your interactive shells).
Note: The functions work in bash
, ksh
, and zsh
, but in ksh
you have to rename them so as not to include a '-' in the function names.
function docker-start {
typeset vm=${1:-default} sts
case $vm in
-h|--help)
echo $'usage: docker-start [<vm>]\n\nEnsures that the specified/default Docker VM is started\nand the environment is initialized.'
return 0
;;
esac
sts=$(docker-machine status "$vm") || return
[[ $sts == 'Running' ]] && echo "(Docker VM '$vm' is already running.)" || {
echo "-- Starting Docker VM '$vm' (\`docker-machine start "$vm"\`; this will take a while)...";
docker-machine start "$vm" || return
}
echo "-- Setting DOCKER_* environment variables (\`eval \"\$(docker-machine env "$vm")\"\`)..."
# Note: If the machine hasn't fully finished starting up yet from a
# previously launched-but-not-waited-for-completion `docker-machine status`,
# the following may output error messages; alas, without signaling failure
# via the exit code. Simply rerun this function to retry.
eval "$(docker-machine env "$vm")" || return
export | grep -o 'DOCKER_.*'
echo "-- Docker VM '$vm' is running."
}
function docker-stop {
typeset vm=${1:-default} sts envVarNames fndx
case $vm in
-h|--help)
echo $'usage: docker-stop [<vm>]\n\nEnsures that the specified/default Docker VM is stopped\nand the environment is cleaned up.'
return 0
;;
esac
sts=$(docker-machine status "$vm") || return
[[ $sts == 'Running' ]] && {
echo "-- Stopping Docker VM '$vm' (\`docker-machine stop "$vm"\`)...";
docker-machine stop "$vm" || return
} || echo "(Docker VM '$vm' is not running.)"
[[ -n $BASH_VERSION ]] && fndx=3 || fndx=1 # Bash prefixes defs. wit 'declare -x '
envVarNames=( $(export | awk -v fndx="$fndx" '$fndx ~ /^DOCKER_/ { sub(/=.*/,"", $fndx); print $fndx }') )
if [[ -n $envVarNames ]]; then
echo "-- Unsetting DOCKER_* environment variables ($(echo "${envVarNames[@]}" | sed 's/ /, /g'))..."
unset "${envVarNames[@]}"
else
echo "(No DOCKER_* environment variables to unset.)"
fi
echo "-- Docker VM '$vm' is stopped."
}