如何在mac中使用docker

如何在mac中使用docker

Docker可以很轻松的运行、管理应用程序。docker一般运行在linux环境中,也可以运行在max和windows环境中

Docker的工作原理

Docker是一个CS模型。Docker的服务端是一个守护进程,进行各种繁杂的操作:包括编译、下载镜像,启动、停止容器等。它也有rest接口以供远程操控。

Docker客户端是一个命令行工具,它通过rest风格的api来和服务端交互。我们通过客户端来向服务端发送命令。

Docker服务端运行在我们的服务器(或者个人电脑)上,称之为host,因为docker默认运行在linux上,所以我们的服务器操作系统一般为linux(或者更精确的说法,linux内核的操作系统)。

Linux上的Docker

比如我们在笔记本电脑上运行Docker,docker的工作原理如下:


这台笔记本同时运行着服务端和客户端,很简单的模型。

Mac上的Docker

OS X的问题是:它不是linux。它没有运行原生docker的内核。

boot2docker是一个可以运行Docker容器的轻量级linux分支。意思是:我们要在Mac电脑的虚拟机中运行boot2docker。

docker on mac

我们在OS X系统运行原生的Docker客户端,但是Docker服务端运行在boot2docker上,也就是说boot2docker才是上面讲的host,而不是OS X.

安装

  1. 安装VirtualBox
    点击这里进行安装,不再赘述。
  2. 安装Docker & boot2docker
    有两种安装方式:官方的安装包或者使用homebrew,这里使用homebrew为例:

    brew update
    brew install docker
    brew install boot2docker
    
  3. 初始化 & 启动boot2docker
    首先,需要初始化boot2docker(只需要初始化一次):

    > boot2docker init
    2014/08/21 13:49:33 Downloading boot2docker ISO image...
     [ ... ]
    2014/08/21 13:49:50 Done. Type `boot2docker up` to start the VM.
    

    然后,启动:

    > boot2docker up
    2014/08/21 13:51:29 Waiting for VM to be started...
    .......
    2014/08/21 13:51:50 Started.
    2014/08/21 13:51:51 Trying to get IP one more time
    2014/08/21 13:51:51 To connect the Docker client to the Docker daemon, please set:
    2014/08/21 13:51:51 export DOCKER_HOST=tcp://192.168.59.103:2375
    export DOCKER_CERT_PATH=/Users/kongkong/.boot2docker/certs/boot2docker-vm
    

    export DOCKER_TLS_VERIFY=1

  4. 设置环境变量
    docker客户端默认服务端是本机。我们需要设置DOCKER_HOST环境变量:

    export DOCKER_HOST=TCP://192,168.59.103:2375
    

你自己的虚拟机可能是其他的ip地址,这个IP地址,在执行boot2docker up时会输出出来。

  1. 查看信息
    让我们来查看一下docker的信息:

    > docker info
    Containers: 0
    Images: 0
    Storage Driver: aufs
     Root Dir: /mnt/sda1/var/lib/docker/aufs
     Dirs: 0
    Execution Driver: native-0.2
    Kernel Version: 3.15.3-tinycore64
    Debug mode (server): true
    Debug mode (client): false
    Fds: 10
    Goroutines: 10
    EventsListeners: 0
    Init Path: /usr/local/bin/docker
    Sockets: [unix:///var/run/docker.sock tcp://0.0.0.0:2375]
    

docker安装成功。

常见问题

我们安装了docker,下面来看一看常见的问题

问题1:端口代理

Docker在容器和host之间代理端口,这里的host是指boot2docker,而不是OS X.

启动一个nginx:

    > docker run -d -P --name web nginx
    Unable to find image 'nginx' locally
    Pulling repository nginx
     [ ... ]
    0092c03e1eba5da5ccf9f858cf825af307aa24431978e75c1df431e22e03b4c3

这条命令已守护进程的方式启动了一个容器[-d],自动代理端口[-P],将容器命名为”web”[–name web],使用的是nginx镜像。这个容器的唯一id是0092c03e1eba...

检查一下容器是否在运行:

    > docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    0092c03e1eba nginx:latest nginx 44 seconds ago Up 41 seconds 0.0.0.0:49153->80/tcp web

如上输出,我们的容器监听的是80端口,Docker将80端口的请求代理到host上的一个随机端口上,49153。

curl发送请求:

    > curl localhost:49153
    curl: (7) Failed connect to localhost:49153; Connection refused

请求失败,为什么呢?

Docker将容器80端口的请求,转发到host的49153端口上。如果是linux,host的ip地址就是localhost,但是在mac上,host不是localhost,而是boot2docker。

解决办法: 使用虚拟机的ip地址
boot2docker使用一条命令就可以获取到虚拟机的ip地址:

    > boot2docker ip
The VM’s Host only interface IP address is: 192.168.59.103

再试一下curl请求:

    > curl $(boot2docker ip):49153
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    [ ... ]

也可以在浏览器中请求:

Alt text

成功了,下面可以停止、删除这个容器:

    docker stop web
    docker rm web

问题2: 挂载Volumes

问题描述:Docker从boot2docker中挂载Volumes,而非OS X
Docker支持Volumes:我们可以将host机器上的一个目录挂载到容器里。Volumes是容器方位host机器资源的一种方式。比如我们可以启动一个nginx容器,它可以访问host机器上的资源文件。

首先,创建一个目录,新建index.html文件:

    > cd /Users/Chris
    > mkdir web
    > cd web
    > echo 'yay!' > index.html

在你自己的机器上,记得使用自己的路径。

然后,我们启动另外一个nginx容器,这一次把上面新建的目录挂载到nginx中:

    > docker run -d -P -v /Users/Chris/web:/usr/local/nginx/html --name web nginx
    485386b95ee49556b2cf669ea785dffff2ef3eb7f94d93982926579414eec278

配置端口:

    > docker port web 80
    0.0.0.0:49154

curl一下:

    > curl dockerhost:49154
    <html>
    <head><title>403 Forbidden</title></head>
    <body bgcolor="white">
    <center><h1>403 Forbidden</h1></center>
    <hr><center>nginx/1.7.1</center>
    </body>
    </html>

问题出现了,Docker尝试去挂载host机器的/Users/Chris/web路径到容器中,但是在mac上host机器是boot2docker, 不是OS X. boot2docker不会访问MS X的资源。

解决方法: 将OS X的/Usres目录挂载到虚拟机中。

/Users路径挂载到虚拟机中,boot2docker就能访问/Users中的资源了。

boot2docker不支持VirtualBox挂载文件,我们需要安装特定的boot2docker。
首先,删除容器,关掉虚拟机:

    > docker stop web
    > docker rm web
    > boot2docker down

然后,下载特定的boot2docker:

    > curl http://static.dockerfiles.io/boot2docker-v1.2.0-virtualbox-guest-additions-v4.3.14.iso > ~/.boot2docker/boot2docker.iso

最后,挂载目录,启动虚拟机:

    > VBoxManage sharedfolder add boot2docker-vm -name home -hostpath /Users
    > boot2docker up

更换boot2docker镜像,不会造成数据丢失,不要担心。

再试一下:

    > docker run -d -P -v /Users/Chris/web:/usr/local/nginx/html --name web nginx
    0d208064a1ac3c475415c247ea90772d5c60985841e809ec372eba14a4beea3a
    > docker port web 80
    0.0.0.0:49153
    > curl dockerhost:49153
    yay!

如果你修改了index.html文件,但是curl的时候,没有效果。那是因为nginx默认打开了sendfile,这个命令在VirtualBox中兼容的不是很好。结果办法是在nginx配置文件中关闭sendfile

问题3:进入容器内部

问题: 如何进入到容器内部?
如何通过shell进入到容器内容呢。

解决方法:Linux Magic

使用nsenter. nsenter允许你在内核空间中执行命令。由于docker容器就是运行在它自己的内核空间中的一个程序,所以我们也可以在docker容器中打开一个shell。

下面的命令会运行在不同的shell下,这些环境用下面的符号表示:

  • > 表示OS X环境
  • $ 表示boot2docker虚拟机环境
  • % 表示Docker容器内部环境

首先,我们进入到boot2docker虚拟机中:

    > boot2docker ssh

然后,安装nsenter:

    $ docker run --rm -v /var/lib/boot2docker:/target jpetazzo/nsenter

最后,把/var/lib/boot2docker加入到虚拟机的环境变量中:

    $ echo 'export PATH=/var/lib/boot2docker:$PATH' >> ~/.profile
    $ source ~/.profile

我们可以使用nsenter了:

    $ which nsenter
    /var/lib/boot2docker/nsenter

启动nginx容器,来看一下是否生效(注意,此时仍旧在虚拟机的ssh中):

    $ docker run -d -P --name web nginx
    f4c1b9530fefaf2ac4fedac15fd56aa4e26a1a01fe418bbf25b2a4509a32957f

想要进入到容器内部,nsenter需要知道容器的pid:

    $ PID=$(docker inspect --format '{{ .State.Pid }}' web)

最终:

    $ sudo nsenter -m -u -n -i -p -t $PID
    % hostname
    f4c1b9530fef

当前就是在容器内部了。来确认下,我们在容器内部,通过ps来查看当前的进程(当然需要先安装ps)

    % apt-get update
    % apt-get install -y procps
    % ps -A
    PID TTY TIME     CMD
      1 ?   00:00:00 nginx
      8 ?   00:00:00 nginx
     29 ?   00:00:00 bash
    237 ?   00:00:00 ps
    % exit

还可以这样用:

    $ sudo docker-enter web ps -A
    PID TTY TIME     CMD
      1 ?   00:00:00 nginx
      8 ?   00:00:00 nginx
    245 ?   00:00:00 ps

ok,现在进入到容器内部已经完全没有问题了,但是我们想更方便一下,如何在OS X中直接在容器中执行命令。这个也是支持的,不过要一段bash脚本:

    #!/bin/bash
    set -e
    # Check for nsenter. If not found, install it
    boot2docker ssh '[ -f /var/lib/boot2docker/nsenter ] || docker run --rm -v /var/lib/boot2docker/:/target jpetazzo/nsenter'
    # Use bash if no command is specified
    args=$@
    if [[ $# = 1 ]]; then
      args+=(/bin/bash)
    fi
    boot2docker ssh -t sudo /var/lib/boot2docker/docker-enter "${args[@]}"

将这段脚本保存成shell文件,加到环境变量中,就可以如下执行:

    > docker-enter web
    % hostname
    f4c1b9530fef

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

(Spamcheck Enabled)