• Docker停电事件未解之谜


    事件简介:

    周末出现了一次偶然的停电事故,供电恢复后,按照惯例重启服务器,并重新运行各项服务。然而,一台Ubuntu 16.04服务器的Docker容器无法启动了……

    1. 启动容器报错

    1. # docker start nginx_test
    2. Error response from daemon: cgroups: cgroup mountpoint does not exist: unknown
    3. Error: failed to start containers: nginx_test

    错误信息指出:cgroup的挂载点不存在!

    2. 手动挂载cgroup

    从网络查询可知,很多用户都遇到过该错误,一个临时的解决办法是执行以下两条命令:

    1. # sudo mkdir /sys/fs/cgroup/systemd
    2. # sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd

    由于这仅仅是一个临时处理办法,系统重启后失效。因此,重启系统后,需要再次执行以上命令,才能正常启动容器,目前暂时没有找到可行的持久化解决方案。

    参考资料:https://github.com/docker/for-linux/issues/219

    3. 再次尝试启动容器,出现新的报错

    1. # docker start nginx_test
    2. Error response from daemon: OCI runtime create failed: container with id exists: 6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8: unknown
    3. Error: failed to start containers: nginx_test

    以上错误信息较容易理解:由于运行时已经存在,创建运行时失败!

    4. 删除错误的容器运行时信息

    以上错误是我们第一次启动容器失败造成的:容器虽然启动失败,但已经产生了一些垃圾信息。

    我们需要到容器运行时目录,列出运行时信息,删除启动失败的容器运行时ID文件夹:

    1. # cd /run/docker/runtime-runc/moby
    2. # ll
    3. total 0
    4. drwx------ 6 root root 120 7月   4 22:05 ./
    5. drwx------ 3 root root  60 7月   4 22:02 ../
    6. drwx--x--x 2 root root  80 7月   4 22:05 6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8/
    7. # rm -rf 6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8/

    5. 第三次启动容器,似乎启动成功

    1. # docker start nginx_test
    2. nginx_test

    6. 确认容器运行状态

    通过docker ps确认容器运行状态,发现容器并没有启动,实际情况是容器启动后又自动退出了。

    1. # docker ps
    2. CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

    7. 查看容器日志

    a. 找出日志路径。

    1. # docker inspect nginx_test
    2. [
    3.     {
    4.         "Id": "6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8",
    5.         "Created": "2022-07-04T13:59:30.590052488Z",
    6.         "Path": "nginx",
    7.         "Args": [
    8.             "-g",
    9.             "daemon off;"
    10.         ],
    11.         "State": {
    12.             "Status": "exited",
    13.             "Running": false,
    14.             ......
    15.         },
    16.         ......
    17.         "LogPath": "/var/lib/docker/containers/6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8/6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8-json.log",
    18.         ......
    19.     }
    20. ]

    b. 查看日志

    1. # tail -n 10 /var/lib/docker/containers/6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8/6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8-json.log
    2. {"log":"2022/07/04 21:59:30 [emerg] 1#1: socket() 0.0.0.0:80 failed (13: Permission denied)\n","stream":"stderr","time":"2022-07-04T13:59:30.980187208Z"}
    3. {"log":"nginx: [emerg] socket() 0.0.0.0:80 failed (13: Permission denied)\n","stream":"stderr","time":"2022-07-04T13:59:30.980199187Z"}
    4. {"log":"2022/07/04 22:08:04 [emerg] 1#1: socket() 0.0.0.0:80 failed (13: Permission denied)\n","stream":"stderr","time":"2022-07-04T14:08:04.4140586Z"}
    5. {"log":"nginx: [emerg] socket() 0.0.0.0:80 failed (13: Permission denied)\n","stream":"stderr","time":"2022-07-04T14:08:04.414142635Z"}

    错误信息表现为权限问题,尝试启动其它容器,结果类似,皆因为权限问题而启动失败。

    8. 关闭apparmor

    根据网络资料,docker的权限问题可能与系统安全应用程序apparmor有关,一些用户关闭或者卸载apparmor后问题解决,这一点特别涉及的是Deepin操作系统。

    当前的操作系统Ubuntu与Deepin一样基于Debian,于是同样尝试了关闭apparmor的效果:

    # systemctl stop apparmor

    结果证明,问题依旧。

    随后还确认了SELinux状态,发现SELinux并没有开启。

    9. 开启docker容器的特权模式

    在普通权限模式下,docker容器中的root用户并不具备宿主机的root权限。为了让容器中的root用户成为真正的root用户,可以通过--privileged参数来运行容器。

    docker run --privileged

    由于容器已经存在,不想重新创建容器,此时可以直接修改容器运行配置。

    注:

    修改容器运行配置需要关闭docker。

    不关闭docker,仅仅关闭容器,修改容器运行配置无效,并且修改后的配置还可能会被docker回写覆盖。

    a. 关闭docker

    # systemctl stop docker

    b. 到达容器运行配置目录,找到配置文件hostconfig.json

    1. # cd /var/lib/docker/containers/
    2. # ll
    3. total 40
    4. drwx------ 10 root root 4096 7月   4 21:59 ./
    5. drwx--x--x 14 root root 4096 7月   4 22:02 ../
    6. drwx------  4 root root 4096 7月   4 22:08 6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8/
    7. # cd 6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8/
    8. 8# ll
    9. total 44
    10. drwx------  4 root root 4096 7月   4 22:08 ./
    11. drwx------ 10 root root 4096 7月   4 21:59 ../
    12. -rw-r-----  1 root root  578 7月   4 22:08 6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8-json.log
    13. drwx------  2 root root 4096 7月   4 21:59 checkpoints/
    14. -rw-------  1 root root 3150 7月   4 22:08 config.v2.json
    15. -rw-r--r--  1 root root 1558 7月   4 22:08 hostconfig.json
    16. -rw-r--r--  1 root root   13 7月   4 22:08 hostname
    17. -rw-r--r--  1 root root  174 7月   4 22:08 hosts
    18. drwx------  2 root root 4096 7月   4 21:59 mounts/
    19. -rw-r--r--  1 root root   42 7月   4 22:08 resolv.conf
    20. -rw-r--r--  1 root root   71 7月   4 22:08 resolv.conf.hash

    c. 编辑容器运行配置文件hostconfig.json,将privileged的值由false改为true

    # vi hostconfig.json

     

    d. 启动docker

    # systemctl start docker

    e. 确认容器的特区模式为开启状态

    1. # docker inspect nginx_test
    2. [
    3.     {
    4.         "Id": "6d3477dce19d76a2c22f21e5140a290a5dc16aa23c3ef0cf45600ad2a7b806b8",
    5.         "Created": "2022-07-04T13:59:30.590052488Z",
    6.         "Path": "nginx",
    7.         "Args": [
    8.             "-g",
    9.             "daemon off;"
    10.         ],
    11.         "State": {
    12.             "Status": "exited",
    13.             "Running": false,
    14.             ......
    15.         },
    16.         ......
    17.         "HostConfig": {
    18.             ......
    19.             "Privileged": true,
    20.             ......
    21.         }
    22.     }
    23. ]

    f. 启动容器

    注:

    这时启动容器也不一定能够一次启动成功。实践中,容器启用特权模式后,需要第二次启动容器才能启动成功。

    1. # docker start nginx_test
    2. # docker ps
    3. CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    4. # docker start nginx_test
    5. nginx_test
    6. # docker ps
    7. CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                          NAMES
    8. 6d3477dce19d        nginx               "nginx -g 'daemon of…"   23 minutes ago      Up 2 seconds        80/tcp, 0.0.0.0:443->443/tcp   nginx_test

    总结

    为何停电后,原本正常运行的容器无法启动了?问题虽然得以解决,但本次docker事故仍然是未解之谜:

    1. 为何docker运行容器时突然出现cgroup无法自动挂载的现象。

    2. 为何原本不需要特权模式的容器在停电事件后需要开启特权模式才能正常运行;虽然有说法使用小于1024的端口需要root权限,但是在停电之前,没有以特权模式运行的容器可以正常使用小于1024的端口。

  • 相关阅读:
    VS2019中配置C++ OpenCV 4.5.4完整指南
    利用注解和反射,在Java后端开发里偷一个不该偷的懒
    【C语言】程序环境深度剖析
    计算机视觉所需要的数学基础
    Google Earth Engine(GEE)——计算不同美国州的气温折线图和散点图
    合并有序链表
    复制或移动文件时,导入所有文件素材的几种方法
    .NET周刊【8月第2期 2023-08-14】
    【附源码】计算机毕业设计JAVA家庭记账系统
    数据分析入门全攻略:从新手到专家
  • 原文地址:https://blog.csdn.net/Dancen/article/details/125627013