在Mac OS X上无法连接到Docker守护程序

58
我想在Mac OS X El Capitan (v10.11.2)上使用docker-compose运行多容器应用程序。
但是,命令$ docker-compose up会报错不能连接到Docker守护进程。
引用块中写到:

错误:无法连接到Docker守护进程 - 你可能需要运行docker-machine start default

只有执行$ eval "$(docker-machine env default)"后,我才能访问docker-compose命令。
为什么会这样,我该如何避免这个额外的步骤?

你是从 Docker Quickstart 终端(假设你正在使用 Docker Toolbox)还是普通终端运行 docker-compose 的?只有在第二种情况下才需要这个额外的步骤。 - Frank Schmitt
1
我从普通终端运行它。 - ndequeker
2
Docker在正常使用之前需要设置一些环境变量,这就是为什么每次重新启动docker-machine时都需要使用eval命令的原因。 - Xiongbing Jin
5个回答

46

更新 Docker.app 版本

自这个答案发布以来,macOS 上的 Docker 经验已经得到了改进:

  • 唯一的前提条件是现在必须运行 Docker.app。请注意,按需启动需要一段时间,因为必须启动底层的 Linux 虚拟机。

  • 然后,任何 shell 都可以访问 Docker 功能。

默认情况下,Docker.app 在登录时启动(您可以通过其首选项更改)。 如果您希望从命令行按需启动和停止 Docker,则这里有bash脚本可供使用,名称为docker-startdocker-stop; 将它们放置在您的$PATH中即可。

docker-start 启动 Docker.app 时,它会等待 Docker 完成启动并准备就绪。


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提供的有用回答 展示了在你打开交互式shell时,添加到Bash配置文件 (~/.bash_profile)的命令来自动初始化Docker。

请注意,您可以通过打开应用程序/Applications/Docker/Docker Quickstart Terminal.app(例如通过Spotlight)在新的 shell选项卡/窗口中始终初始化Docker。
从现有的shell中,您可以调用它为open -a 'Docker Quickstart Terminal.app'(这也会打开新的 shell 选项卡)。
此回答提供了一种在当前 shell 中启动 Docker 的便捷方式。

添加下面的Bash shell 函数 - docker-startdocker-stop - 在以下方面改进了Kevan的方法:

  • 您可以随时运行docker-start,而无需在打开 shell时启动虚拟机 (一旦Docker虚拟机正在运行,初始化速度会更快,但仍需要明显的时间)。
    (当然,您仍然可以选择从您的个人资料中调用docker-start。)

  • docker-stop 允许按需停止Docker并清除环境变量。

  • 函数确保不抑制Docker的错误信息,并将Docker错误退出代码通过。

  • 提供了其他状态信息。

  • 可以将虚拟机名称作为参数传递;默认值为default

例如:

$ 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.

用于按需启动和停止Docker的Shell函数(将它们放在例如~/.bash_profile中,以便在您交互式shell中全局使用)。

注意:这些函数适用于bashkshzsh,但是在ksh中,您必须重命名它们,以免在函数名称中包含“-”符号。

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."
}

1
@BrianArmstrong:该功能确实随Docker一起提供,但作为单独的应用程序/Applications/Docker/Docker Quickstart Terminal.app,它会在一个新的终端窗口中初始化Docker。我认为这个单独的入口点之所以存在是因为在OSX上运行Docker需要启动基于VirtualBox的Linux VM(除了设置环境变量),这是您不想每次打开shell时都要承担的额外开销。这个答案提供了一种方便的方法,可以从现有的shell中随时启动Docker。 - mklement0
@mklement0 很棒!你会在某个存储库中保存这些命令吗? - Bas Peeters
@ManeatingKoala:不好意思,本答案目前是唯一的来源。 - mklement0
我通过ssh登录到MacBook Pro,但在命令行上运行“open -g -a Docker.app”无法正常工作: LSOpenURLsWithRole() failed for the application /Applications/Docker.app with error -54. 如果必须在GUI环境下运行命令行,则命令行的帮助不大... - zerox
@zerox:你是说当在本地运行时 open -g -a Docker.app 可以工作,但通过 SSH 失败了吗?通常情况下,open -a 也可以通过 SSH 工作(但显然只会在目标机器上可见地启动应用程序)。 - mklement0

24

我在~/.bash_profile中添加了以下内容,这样我就不必每次运行env命令:

docker-machine start default 2>/dev/null # Hide output if machine is already running
eval `docker-machine env default`

3
在快速入门终端中,我重新启动了“默认”虚拟机,解决了我的问题。原始答案翻译成“最初的回答”。
docker-machine restart default
eval $(docker-machine env default)

然后我就可以使用 docker-compose up -d --build 命令开始构建我的容器了。将会生成最初的回答。

1

在我的情况下,我帮助了:停止+删除所有Docker容器(Docker版本1.13.0-rc4)

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

在执行“docker-compose up”命令后,如果没有出现错误提示“ERROR: Couldn't connect to Docker daemon. You might need to start Docker for Mac.”,则表示运行成功。
也许在某些情况下,这个错误信息只是由其他错误引起的,比如内存空间问题。

0

我已经编写了一个Homebrew存储库,位于这里: https://github.com/nejckorasa/mac-docker-go

它包括一个脚本来启动/重新启动Docker守护程序。

Usage: dckr [options]

Options:
  -k  | --kill        Kill Docker daemon
  -s  | --start       Start Docker daemon
  -r  | --restart     Restart Docker daemon
  -ka | --killall     Kill all running Docker containers
  -h                  Display help

  Defaults to restart if no options are present

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接