Docker中的Ubuntu无法正常使用systemctl操作
问题描述

在docker中安装Ubuntu,试图用systemctl命令来实现Ubuntu开机后自动打开ssh,发现无法实现想要的效果。

产生原因
Loaded显示enabled说明ssh开机应该会自动启动,但是实际上开机之后却是inactive(没有成功运行)
经过查阅资料,发现Docker只是提供了进程隔离,不是操作系统的虚拟,它并不是我想象中的虚拟机,不会模拟硬件,只是会为每一个应用提供隔离的运行环境。
正常的Ubuntu系统的1号进程(PID=1)是init,可以系统的初始化脚本,创建一系列的子进程,如图

Docker版本的Ubuntu的1号进程不是init,导致systemctl功能异常。

解决办法
代码
1 | docker run -tid --name ubuntu01 --privileged=true ubuntu /sbin/init |
代码解释
docker run -tid --name ubuntu01 --privileged=true ubuntu /sbin/init
ubuntu01是容器(container)名称, ubuntu是映像(images)名称
帮助中显示run的作用原文为:run Run a command in a new container
所以这条指令的含义是利用ubuntu映像创建并运行一个名为ubuntu01的容器,–privileged=true给予容器更高的特权,启动/sbin/init进程*(使系统初始化)*
注意不同系统(Centos,Ubuntu)的init位置不同,Centos在/usr/sbin/init,Ubuntu在/sbin/init
docker exec -it ubuntu01 /bin/bash
帮助中显示exec的作用原文为:exec Run a command in a running container
-it 与容器中的shell进行交流
所以这条指令的含义是在已经启动的容器中运行/bin/bash指令(启动一个bash shell)
代码正确运行结果

假如Ubuntu的/sbin/init文件不存在
问题描述
在使用docker run -tid --name ubuntu01 --privileged=true ubuntu /sbin/init代码进行操作后出现错误:
docker: Error response from daemon: OCI runtime create failed: container_linux.go:367: starting container process caused: exec: "/sbin/init": stat /sbin/init: no such file or directory: unknown.
产生原因
这说明我们使用的Ubuntu映像没有init文件,需要我们自行添加
解决办法一:修改容器的启动配置
进入一个正常的Ubuntu系统,cd /sbin然后ls -l|grep init查看init文件,显示结果如下

运行结果显示init文件实际上是systemd文件的软链接形式
lrwxrwxrwx中第一个字母l代表该文件是一个软链接
利用映像创建一个容器,并进入终端(或者直接进入旧容器)
1
2docker run -tid --name ubuntu01 ubuntu
docker exec -it ubuntu01 /bin/bash使用
apt update&&apt upgrade更新软件源使用
apt install systemd下载一个systemd到Linux系统在/sbin目录里建立一个名为init的软链接指向systemd,使用指令
ln -s /lib/systemd/systemd /sbin/init退出容器的bash shell,使用
docker info查看docker容器的存储位置,例如:Docker Root Dir: /volume1/@docker进入docker 目录下的containers/目录,找到跟容器id(
docker ps -a可以列出所有的容器相关信息)相同的目录(或者可以使用docker inspect "容器名"查看和容器有关的信息)ls 查看文件构造
config.v2.json即为配置文件
cp config.v2.json config.v2.json.origin备份配置文件vim config.v2.json修改配置文件,将Path修改为”/sbin/init”,Cmd修改为”/sbin/init”,重点:”NoNewPrivileges”改为true,否则修改后的配置文件在启动容器后又会变回原样
Path填写可执行程序,Args填写可执行程序的参数,Cmd完整的命令输入
service docker restart指令来重启docker注意是重启docker,而不是重启container
如果是群晖系统则需要使用1
2bash /var/packages/Docker/scripts/start-stop-status stop;
bash /var/packages/Docker/scripts/start-stop-status start;
11.输入docker start ubuntu01来启动容器,输入ps aux查看进程,发现Ubuntu第一个进程为init,大功告成

解决办法二:修改容器后,利用容器commit映像出来,再使用映像建立一个容器
前四步都与解决方法一一致
利用映像创建一个容器,并进入终端(或者直接进入旧容器)
1
2docker run -tid --name ubuntu01 ubuntu
docker exec -it ubuntu01 /bin/bash使用
apt update&&apt upgrade更新软件源使用
apt install systemd下载一个systemd到Linux系统在/sbin目录里建立一个名为init的软链接指向systemd,使用指令
ln -s /lib/systemd/systemd /sbin/init退出容器,使用
docker commit ubuntu01 test将修改好的容器ubuntu01 commit为test映像这下利用test映像即可以使用代码而不报错
1
2docker run -tid --name ubuntu02 --privileged=true test /sbin/init
docker exec -it ubuntu02 /bin/bash






