安装DCOS,关于docker异常引发的调查
入门DCOS,刚开始安装,碰到了一个异常:
Bind for 0.0.0.0:9000 failed: port is already allocated.
调试这个问题花费了好长时间,因为无法通过netstat以及lsof看到究竟是什么应用占用了程序;后来我才发现原来是因为docker的原因;如果docker被run了两次
docker run -it -p 9000:80 mesosphere/dcos-genconf:d932fc405eb80d8e5b-b7c22f7cfb481d9f95 /bin/bash
第一次失败,那么这个端口将会被一直占用,即使docker容器并没有创建并没有。解决办法就是重启docker服务:
service docker restart
(也有人说要sudo rm /var/lib/docker/network/files/local-kv.db,但是在我看来并不需要)
这个是docker里面的bug,看到这个issue在论坛里面讨论的热火朝天,但是这是2014年的事了。
再回过头来,那么既然是run两次失败会爆这个异常,那么,docker run失败原因是什么呢?
exec: "docker-proxy": executable file not found in $PATH.
这个异常的原因是docker启动后将会执行docker-proxy指令,但是在shell中加载的$PATH中无法找到对应的指令。与之类似是docker-runc无法找到,这个原因是在/usr/libexec/docker下面,在安装的时候可能因为没有完全安装导致的两个link没有安装上,用如下方法进行修补:
1 cd /usr/libexec/docker/ 2 sudo ln -s docker-proxy-current /usr/bin/docker-proxy
daocker执行应该首先回到/usr/libexec/docker下面找执行文件,没有,再到$PATH定义的路径下找,再没有,则报错。
另外,当发生以下异常:
/usr/bin/docker-current: Error response from daemon: shim error: docker-runc not installed on system.
也是需要创建软连接方式来解决:
sudo ln -s docker-runc-current /usr/bin/docker-runc
prestart hook 1 caused \\\"error running hook: exit status 1
这个问题如果这样贴出来,是没有意义的,想要看更加详细的错误信息:
1 service docker status -l 2 journalctl -xe
这样结合起来可以看到更加详细的信息。
看到的错误信息:Failed to open file '/sys/class/net/vethf6a3cb0/operstate'
vethXXX应该是docker内部的网络接口的名称;初步推测应该是因为某个异常导致的docker内部的网卡没有启动起来。
在调查的过程中发现了一个命令:brctl show,用来显示网桥,其实docker默认的网桥是docker0(docker0并不是一个网络接口,而是一个网桥)。
至于如何来创建网桥
https://docs.docker.com/engine/userguide/networking/default_network/build-bridges/
以及相关docker的文档:
https://docs.docker.com/v1.7/articles/networking/
https://forums.docker.com/t/relationship-between-interface-vethxxxxx-and-container/12872/22
后来深入跟踪这个问题,发现其实是因为不知道什么原因会增加一个override.conf,这个override.conf将storage-driver设置成了overlay(难道是因为设docker_proxy?),至于发现这个的过程是这样的,比较docker info的差异,发现有问题的机器采用的是overlay的方式,OK机器采用的是devicemapper的方式;然后我又尝试修改为devicemapper,方式就是在/etc/docker/daemon.json文件中写入
{"storage-driver": "devicemapper"}
但是启动docker的时候爆了一个异常:
unable to configure the Docker daemon with file /etc/docker/daemon.json: the following directives are specified both as a flag and in the configuration file: storage-driver: (from flag: overlay, from file: devicemapper)\n"
这里关于option我还想了半天,最后是怀疑是启动docker服务的时候应该指定了storage-driver参数,和我在配置文件中的冲突了。我还手动启动了一下dockerd --storage-drive=devicemapper,在docker run dcos的image没有问题。
然后我使用了service docker status,来查看docer服务的详细内容,才发现status里面包含了非常丰富的内容,之前只是记得会显示执行的指令以及参数选项(option)
1 Redirecting to /bin/systemctl status docker.service 2 ● docker.service - Docker Application Container Engine 3 Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled) 4 Drop-In: /etc/systemd/system/docker.service.d 5 └─override.conf 6 Active: activating (auto-restart) (Result: exit-code) since Sat 2017-11-11 22:28:38 CST; 2s ago 7 Docs: http://docs.docker.com 8 Process: 31055 ExecStart=/usr/bin/dockerd --storage-driver=overlay (code=exited, status=1/FAILURE) 9 Process: 31050 ExecStartPre=/sbin/ip link del docker0 (code=exited, status=0/SUCCESS) 10 Main PID: 31055 (code=exited, status=1/FAILURE)
注意加粗三句话,所有的问题都是通过三句话来解开的:
第一句话是说明服务启动的文件,我进去看了,发现里面的storage-driver的配置文件里面默认配置的就是devicemapper。这个过程稍微有点复杂:/usr/lib/systemd/system/docker.service里面指定了storage的配置文件(/etc/sysconfig/docker-storage),需要查看storage的配置文件,但是呢这个配置文件还是多重继承的意思,总是最后根上是/usr/share/container-storage-setup/container-storage-setup文件,打开一看:STORAGE_DRIVER=devicemapper,这说明默认就是devicemapper的方式,那么为什么通过docker info看到的方式是overlay呢?
第二句话是说明配置项已经被覆盖了,覆盖的配置文件是 /etc/systemd/system/docker.service.d/override.conf,里面内容是:
1 art=always 2 StartLimitInterval=0 3 RestartSec=15 4 ExecStartPre=-/sbin/ip link del docker0 5 ExecStart= 6 ExecStart=/usr/bin/dockerd --storage-driver=overlay
第三句话(还有下面的process语句)是真正的执行的指令和参数,其实就是override.conf里面定义的内容。
看到这里我明白了,原来docker的启动过程被覆盖了。于是我将override.conf文件重命名了,然后重启docker服务,爆了提示:
Warning: docker.service changed on disk. Run 'systemctl daemon-reload' to reload units.
daemon-reload是指重新加载服务的核心配置文件,即单元文件(里面定义了服务以来单元以及服务定义),这里因为我已经把服务的单元文件给删掉了,所以需要重新加载配置文件(看来linux是把单元文件加载到内存中,每次重启服务并不重新读取单元文件)。重启之后,搞定了。
再看service docker status:
1 Redirecting to /bin/systemctl status -l docker.service 2 ● docker.service - Docker Application Container Engine 3 Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled) 4 Active: active (running) since Sat 2017-11-11 22:37:20 CST; 19s ago 5 Docs: http://docs.docker.com 6 Main PID: 34181 (dockerd-current) 7 CGroup: /system.slice/docker.service 8 ├─34181 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --selinux-enabled --log-driver=journald --signature-verification=false 9 └─34186 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc --runtime-args --systemd-cgroup=true
别问我为什么会有override.conf,我也不知道他是怎么出现的。
但是如果提到了override.conf,则需要提到了systemd,其实systemd是Linux的一组基础组建的工具集合(替代centos之前的initd),用于启动守护进程,监控服务等一系列操作系统的基础功能。
服务(属于单元的一种)一般是打包安装,为了不需要修改打包原生的配置文件,systemd提供了一种可以在外部覆盖原生配置文件的方式,这种就是:
systemctl edit unit
修改之后,就会生成/etc/systemd/system/unit.d/override.conf(unit.d在我们这里就是docker.service.d)
后来,安装dcos熟练了,才知道,这是因为dcos在安装的时候会把master以及agent节点都配置为overlay,而修改配置侵入最小的方式就是采用override.conf的方式。我之前的问题就是在于把boot节点(setup节点)同时作为了master节点,所以有此问题。