问题描述

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

产生原因

​ Loaded显示enabled说明ssh开机应该会自动启动,但是实际上开机之后却是inactive(没有成功运行)

​ 经过查阅资料,发现Docker只是提供了进程隔离,不是操作系统的虚拟,它并不是我想象中的虚拟机,不会模拟硬件,只是会为每一个应用提供隔离的运行环境。

正常的Ubuntu系统的1号进程(PID=1)是init,可以系统的初始化脚本,创建一系列的子进程,如图

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

解决办法

代码

1
2
docker run -tid --name ubuntu01 --privileged=true ubuntu /sbin/init
docker exec -it ubuntu01 /bin/bash

代码解释

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. 利用映像创建一个容器,并进入终端(或者直接进入旧容器)

    1
    2
    docker run -tid --name ubuntu01  ubuntu
    docker exec -it ubuntu01 /bin/bash
  2. 使用apt update&&apt upgrade更新软件源

  3. 使用apt install systemd下载一个systemd到Linux系统

  4. 在/sbin目录里建立一个名为init的软链接指向systemd,使用指令ln -s /lib/systemd/systemd /sbin/init

  5. 退出容器的bash shell,使用docker info查看docker容器的存储位置,例如:Docker Root Dir: /volume1/@docker

  6. 进入docker 目录下的containers/目录,找到跟容器id(docker ps -a可以列出所有的容器相关信息)相同的目录(或者可以使用docker inspect "容器名"查看和容器有关的信息)

  7. ls 查看文件构造

    config.v2.json即为配置文件

  8. cp config.v2.json config.v2.json.origin备份配置文件

  9. vim config.v2.json修改配置文件,将Path修改为”/sbin/init”,Cmd修改为”/sbin/init”,重点:”NoNewPrivileges”改为true,否则修改后的配置文件在启动容器后又会变回原样
    Path填写可执行程序,Args填写可执行程序的参数,Cmd完整的命令

  10. 输入service docker restart指令来重启docker注意是重启docker,而不是重启container
    如果是群晖系统则需要使用

    1
    2
    bash /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. 利用映像创建一个容器,并进入终端(或者直接进入旧容器)

    1
    2
    docker run -tid --name ubuntu01  ubuntu
    docker exec -it ubuntu01 /bin/bash
  2. 使用apt update&&apt upgrade更新软件源

  3. 使用apt install systemd下载一个systemd到Linux系统

  4. 在/sbin目录里建立一个名为init的软链接指向systemd,使用指令ln -s /lib/systemd/systemd /sbin/init

  5. 退出容器,使用docker commit ubuntu01 test将修改好的容器ubuntu01 commit为test映像

  6. 这下利用test映像即可以使用代码而不报错

    1
    2
    docker run -tid --name ubuntu02 --privileged=true test /sbin/init
    docker exec -it ubuntu02 /bin/bash