安装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节点,所以有此问题。

posted on 2017-11-19 15:09  张叫兽的技术研究院  阅读(7091)  评论(0编辑  收藏  举报

导航