\#0 序言坑.实在是坑.网上都让我去装显卡驱动,我一破集显哪来的显卡驱动?请先参考问题的基本表现,因为此问题可能由多种原因导致.\#1 什么鬼?只要满足其中之一,即满足此解决方案的使用条件.若安装了桌面环境,关机时长时间卡在Ubuntu Logo屏,硬盘指示灯几乎没有动静.未安装桌面环境,关机时看见A stop job is running for...的日志输出.\#2 为什么?出现此问题是因为某些系统服务在关机时不能正常停止,导致系统无法达到关机时所需要的条件.最典型的就是Snap Daemon以及MariaDB,这两货就没好好停过.\#3 怎么办?去他妈的显卡驱动.去他妈的/etc/modules.去他妈的grub.以上方案对于这种情况都是扯淡.对于桌面环境用户,当你关机时卡在Ubuntu Logo时,按下F1键,即可显示关机日志,然后同下无桌面环境的操作.对于无桌面环境的用户,当你看见A stop job is running for...时,记下这个服务的名称.例如A stop job is running for Snap Daemon,即Snap Daemon.然后根据你的常识与经验尝试猜测此服务的真实名称.例如Snap Daemon,可猜测真实名称为snap-daemon,snap,snapd.通过sudo systemctl status {ServiceName}来检测你的猜测是否准确.如果找到了此服务且显示名称相同,那就对了.例如猜测MariaDB Server为mysqld,验证时获得以下输出:mariadb.service - MariaDB 10.1.44 database server Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)则猜测正确.如果经验不足或运气实在不好,可以尝试上网搜索有关信息.在验证猜测正确后,会获得指向该服务文件的路径.如上面的/lib/systemd/system/mariadb.service,使用root权限打开并编辑它.在文件末加一行:TimeoutStopSec=10意味着10秒后如果该服务还没有老老实实的去死,那systemd就会亲自动手强行弄死它.当然,你可以设置得更短,但是这可能会导致你手动关闭服务时也会超时然后服务被强行终止而无法保存数据.一般情况下,10秒已经够了,对于某些服务,可以根据实际情况设置超时.然后保存文件,退出.重载systemd:sudo systemctl daemon-reload.然后重启查看情况.可能会有多个服务阻止你关机,这时需要多查看几次日志把这些服务统统击毙.如果到最后所有阻止你关机的服务都击毙了还是没法关机,那可能就是什么其他的问题了.自己看着办吧.
这一开始本来是一个QQ机器人的问题.我需要让机器人的Docker容器跟随系统开关机自动启停,在失败时自动重启,就像一个普通的Systemd服务一样.然后折腾了一个小时,终于解决了.很简单,先说一下基本思路:写一个监控容器状况的脚本,容器退出后脚本也退出,装作自己是容器的守护进程.在Service里ExecStartPre和ExecStop里控制容器的启停,ExecStart里跑伪装的守护进程.开始我们假设这里需要将一个叫contain的容器作为服务.伪·守护进程好,让我们先写一个监控容器状况的脚本,这里暂且叫daemon.sh.先来一个死循环,让脚本保持运行:#!/bin/bash while sleep 1 done再判断一下Docker容器是否在运行,这里用docker ps -af "name=<容器名称>"获得容器的信息,如果返回里会包含Exited,那就代表容器已经停止运行,用grep判断一下即可:#!/bin/bash echo Example Docker contain started. while sleep 1 do if docker ps -af "name=contain" | grep Exited; then fi done在容器停止运行时退出,顺便润色两下:#!/bin/bash echo Example Docker contain started. while sleep 1 do if docker ps -af "name=contain" | grep Exited; then echo Example Docker contain stopped exit fi done保存,反手一个chmod +x,给个权限.真·系统服务在/etc/systemd/system下面创建一个service,我们暂且叫他为contain.service先开个头:[Unit] Description=Example Docker Contain Service After=Docker.service Wants=Docker.service跑俩下:[Unit] Description=Example Docker Contain Service After=Docker.service Wants=Docker.service [Service] User=root WorkingDirectory=/path/to/fake/daemon ExecStartPre=/usr/bin/docker start contain ExecStart=/path/to/fake/daemon/daemon.sh ExecStop=/usr/bin/docker stop contain Type=simple StartLimitInterval=600收个尾:[Unit] Description=Example Docker Contain Service After=Docker.service Wants=Docker.service [Service] User=root WorkingDirectory=/path/to/fake/daemon ExecStartPre=/usr/bin/docker start contain ExecStart=/path/to/fake/daemon/daemon.sh ExecStop=/usr/bin/docker stop contain Type=simple StartLimitInterval=600 [Install] WantedBy=multi-user.target保存,反手一个systemctl daemon-reload,载入服务.拍拍手,完事,撤.