Docker 常见问题 (FAQ)

最后更新时间: 2015-06-08

内核需求

  • rhel/centos 要求内核在 2.6.32-431 (系统版本6.5) 及以上
  • debian/ubuntu 要求内核在 3.8 以上

修改镜像/容器文件的存储位置

方法一 修改 docker daemon 的启动参数

-g, --graph=""
  Path to use as the root of the Docker runtime. Default is /var/lib/docker.

docker -d --graph=/opt/docker

docker daemon 的启动参数修改方法

rhel/centos 下, 默认启动参数在 /etc/sysconfig/docker, 如:

6.x:

other_args="--graph=/opt/docker "

7.x: (update: 2015-01-21)

OPTIONS="--graph=/opt/docker "

debian/ubuntu 下, 默认启动参数在 /etc/default/docker, 如:

DOCKER_OPTS="--graph=/opt/docker "

方法二 指定挂载目录

mount -o bind /var/lib/docker /opt/docker

永久修改在需要在 /etc/fatab 添加:

/opt/docker      /var/lib/docker         none    bind            0 0

方法三 软连接

ln -s /var/lib/docker /opt/docker

容器刚运行就退出了(Exited)

很多人发现刚刚执行了一个 docker run 的命令, 再用 docker ps -a 的时候, 刚刚那个容器就已经 Exited 了, 比如

docker run -d <IMAGE> service sshd start

上述命令一执行完就会发现容器就退出了, 那是因为 service sshd start 不是一个前台进程, 这个进程执行完以后就会退出, 所以这里必须使用前台方式(nodaemon)运行进程, 上述例子中要使用

docker run -d <IMAGE> /usr/sbin/sshd -D

其他应用程序也要使用对应的 nodaemon 的参数, 没有的话就要加一个不会退出的命令, 如:

docker run -d <IMAGE> <CMD> && tail -f xxx.log

selinux (Permission denied)

当开启 selinux 经常会遇到 Permission denied 错误, 如:

docker run -i -v /data:/data ubuntu bash

然后运行 ls /data 时就会报如下错误

ls: cannot open directory .: Permission denied

解决方案有两个:

一是关闭宿主机的 selinux

二是在宿主机上添加 selinux 规则, 以上面为例:

chcon -Rt svirt_sandbox_file_t /data

其他情形下 如果是因为 selinux 引起 Permission denied 也要添加相应的规则或者直接关闭 selinux

容器固定 IP

pipework

  • OS: rhel/centos 6.x

在 rhel/centos 6.x 下使用 pipework 时会报如下错误:

Object "netns" is unknown, try "ip help".

原因是 rhel/centos 6.x 的 iproute 包默认并不支持 ip netns 命令, 所以这里需要安装新的 iproute 包

这里使用 RDO 的源:

yum install -y https://repos.fedorapeople.org/repos/openstack/openstack-icehouse/rdo-release-icehouse-4.noarch.rpm
yum install -y iproute

注意: 在这里最新的 RDO 源(openstack-juno)已经不支持 rhel/centos 6.x 了, 如有更新可以到这个目录下查看
如果已经安装了 openstack-juno 的需先卸载

进入容器

因为容器本身其实就是把进程/资源隔离了, 严格意义上讲不存在所谓的进入容器, 通常这里的所说的进入容器指的是在容器的 namespace 内执行 shell

小于 1.3 版本

小于 1.3 版本的可以使用 nsenter:

https://github.com/jpetazzo/nsenter

1.3 版本以上

如果 docker 版本已经在 1.3 以上了, 那么可以用 docker exec 这个命令:

docker exec -it <CONTAINER ID> bash

注意

ssh

不建议使用 ssh 进入容器, 关于为什么不建议使用, 请参考如下文章:

docker attach

为什么执行 docker attach 卡住了?

首先要明确的是 docker attach 不是一个用来进入容器的命令, 或者说他不是用来在容器内运行一个 bash(shell) 的命令, 它是用来连接到容器中运行中的进程, 也就是容器的 CMD, 容器内 PID=1 的那个进程, 如果这个进程没有 stdout/stderr 那么你将看不到任何输出, 如果它没有接收 stdin 你也无法发送指令给它. 这也就是为什么你运行一个 bash 的容器, 就可以 attach 进去执行命令, 而你运行一个 mysql server 的容器就无法操作的原因

如何退出 attach 的容器

这里要使用 CTRL-P CTRL-Q 来退出容器, 如果使用 CTRL+C 那么会导致容器结束(Exited), 因为它会发送 SIGKILL 给容器的进程, 然后这个容器就 Exited 了, 当然这里可以使用 docker attach --sig-proxy=false 防止发送 SIGKILL 给进程

https://docs.docker.com/reference/commandline/cli/#attach
You can detach from the container again (and leave it running) with CTRL-p CTRL-q (for a quiet exit), or CTRL-c which will send a SIGKILL to the container, or CTRL-\ to get a stacktrace of the Docker client when it quits. When you detach from the container's process the exit code will be returned to the client.

Docker 私有库自签名 SSL 报错 (Invalid registry endpoint ... unknown CA certificate)

docker 升级到 1.3 以后使用 docker pull/push 等命令时必须要求 registry 使用 SSL, 否则就会报如下错误

Error: Invalid registry endpoint https://registry.xx.com/v1/: Get https://registry.xx.com/v1/_ping: EOF. If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add `--insecure-registry registry.xx.com` to the daemon's arguments. In the case of HTTPS, if you have access to the registry's CA certificate, no need for the flag; simply place the CA certificate at /etc/docker/certs.d/registry.xx.com/ca.crt

这里是因为你使用了自签名的证书导致系统不信任, 如报错信息所描述, 解决方法有两个

一是添加 --insecure-registry registry.xx.com 参数到 docker daemon

二是把私有 docker registry 的 CA 证书放到指定的位置(/etc/docker/certs.d/registry.xx.com/ca.crt)

这里的 CA 证书是指你签发 registry.xx.com 这个域名的 SSL 证书所用的 CA
证书的制作方法可参见 http://www.lsproc.com/post/easyrsa-generate-ssl-cert/

docker daemon 重启后某些容器无法启动 (device or resource busy)

当重启 docker daemon 有时候会导致某些容器无法启动, 手动启动容器会报如下错误

Error response from daemon: Cannot start container 5e9bde9b409b:
Error getting container 5e9bde9b409b001bcc685c0b478e925a53a03bab8d8ef3210bf24aa39410e30d
from driver devicemapper:
Error mounting '/dev/mapper/docker-253:0-267081-5e9bde9b409b001bcc685c0b478e925a53a03bab8d8ef3210bf24aa39410e30d'
on
'/var/lib/docker/devicemapper/mnt/5e9bde9b409b001bcc685c0b478e925a53a03bab8d8ef3210bf24aa39410e30d':
device or resource busy

目前来看这应该是一个 bug: docker/docker#5684, docker/docker#4036

解决办法有两个:

一是发现报错后, 在启动容器之前手动 umount:

umount /var/lib/docker/devicemapper/mnt/5e9bde9b409b001bcc685c0b478e925a53a03bab8d8ef3210bf24aa39410e30d

二是 docker daemon stop 时先停止容器运行, 修改 /etc/init.d/docker 如下

stop() {
    [ -x $exec ] || exit 5

    echo -n $"Stopping $prog: "
    if [[ -n $($exec ps -q) ]]; then
        $exec stop $($exec ps -q) > /dev/null
    fi
    killproc -p $pidfile -d 300 $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

不过这样因为会停止所有容器, 所以重启速度会变慢

另外重启后所有容器默认都不会启动, 如果让容器在 daemon 启动时自动开启, 那么需要在 docker run 时添加参数 --restart always, 如:

docker run -d --restart always <IMAGE> <CMD>

docker 1.6.x 关闭 iptables 时不能 link 容器

2015-06-08 更新

使用 docker 1.6, daemon 参数关闭了 iptables 选项时(--iptables=false), link 容器时会报错:

Cannot start container 35437aa2c224d580d7555a2f900b95d6d5ab282bb91c34e96ae0cda106557ff0: (exit status 1)

解决方法一是 daemon 打开 iptables(--iptables=true), 或者手动创建 DOCKER clain:

iptables -N DOCKER

bug 详情在此: https://github.com/docker/docker/issues/12701

docker-compose 使用2进制方式安装后每过一段时间就不可用

2015-10-11 更新

使用 docker-compose 的过程中发现每过一段时间2进制文件就不可用, 报如下错误

Cannot open self /usr/bin/docker-compose or archive /usr/bin/docker-compose.pkg

解决方法为(rhel/centos):

echo "-b /usr/bin/docker-compose" > /etc/prelink.conf.d/docker-compose.conf

debian/ubuntu 也找到 prelink 相应的配置文件地址增加上述配置即可

bug 详情在此: https://github.com/docker/compose/issues/1135

延伸阅读

2015-01-08 1041 docker faq