Docker - 从 docker 容器内重新启动树莓派主机

Abd*_*han 3 linux raspberry-pi docker docker-compose

我有一个打算在树莓派上运行的 python 应用程序。我创建了一个 docker-compose 文件来设置它,我的入口点恰好是一个 shell 脚本,它检查主机上的各种事情,例如:

  1. 确保 SPI 已启用,如果未启用,则通过访问 /boot/config.txt 并写入来启用它。
  2. 安装并启用看门狗服务。
  3. 通过将其写入 /etc/rc.local 来在重新启动时自动运行我的 docker 容器(尽管我正在考虑将其替换为重新启动:来自 docker-compose 文件的始终或除非停止标志)

问题是,如果我启用 SPI,树莓派需要重新启动才能设置它(不太清楚为什么),但是当我的 shell 脚本从 docker 容器中到达 sudo reboot 命令时,我收到以下错误:

 Failed to connect to bus: No such file or directory
 Failed to talk to init daemon.
Run Code Online (Sandbox Code Playgroud)

我知道它可能试图在 docker 容器中找到 dbus 和 init 守护进程,但它们不存在。如何让我的容器访问这些资源?我需要挂载另一个卷吗?这是我的 docker-compose.yml 文件:

version: "3"

services:
    mongoDB:
        restart: unless-stopped
        volumes:
            - "/data/db:/data/db"
        ports:
            - "27017:27017"
            - "28017:28017"
        image: "andresvidal/rpi3-mongodb3:latest"
    mosquitto:
        restart: unless-stopped
        ports:
            - "1883:1883"
        image: "mjenz/rpi-mosquitto"
    FG:
        privileged: true
        network_mode: "host"
        depends_on:
            - "mosquitto"
            - "mongoDB"
        volumes:
            - "/home/pi:/home/pi"
            - "/boot:/boot"
        #image: "arkfreestyle/fg:v1.8"
        image: "test:latest"
        entrypoint: /app/docker-entrypoint.sh
        restart: unless-stopped
Run Code Online (Sandbox Code Playgroud)

FG 是我的 python 应用程序,其入口点 docker-entrypoint.sh 如下所示:

#!/bin/sh
if [ ! -f /home/pi/.initialized ]; then                                                                                                                                                                                    
    echo "Initializing..."                                                                                                                                                                                

    # Turn spi on
    if grep -Fxq "dtparam=spi=on
dtparam=watchdog=on" /boot/config.txt
    then
        echo "\nSPI is already enabled"
        echo "Creating .initialized"
        # Create .initialized hidden file
        touch /home/pi/.initialized
        echo "Starting application..."
        sudo python3 __main__.py -debug
    else
        ### Enable SPI ###
    fi
    fi

    ### Create .initialized file ### 
    echo "Rebooting in ten seconds..."
    sleep 10
    sudo reboot # This line results in the error

else
    echo "Initialized already!"
    sudo python3 __main__.py -debug                                                                                                                                                                                     
fi       
Run Code Online (Sandbox Code Playgroud)

特权选项已经让我的容器可以访问 GPIO,我想它也可以让我访问重启,但事实并非如此。请让我知道我需要做什么才能重新启动。

lar*_*sks 5

我的第一个猜测是,您只需要公开/run/dbus/run/systemd到您的容器,如下所示:

docker run -v /run/dbus:/run/dbus -v /run/systemd:/run/systemd ...
Run Code Online (Sandbox Code Playgroud)

虽然这是必要的,但这还不够;仅使用这两个绑定安装,尝试从容器内部与主机 systemd 交互会导致:

[root@631fff40f09c /]# reboot
Failed to connect to bus: No data available
Failed to talk to init daemon.
Run Code Online (Sandbox Code Playgroud)

事实证明,为了使其工作,容器必须在主机的全局 PID 命名空间中运行,这意味着我们需要:

docker run -v /run/dbus:/run/dbus -v /run/systemd:/run/systemd --pid=host ...
Run Code Online (Sandbox Code Playgroud)

有了这个,reboot在容器内运行成功地重新启动主机。

在 a 中docker-compose.yml,这看起来像:

FG:
    privileged: true
    network_mode: "host"
    pid: "host"
    depends_on:
        - "mosquitto"
        - "mongoDB"
    volumes:
        - "/home/pi:/home/pi"
        - "/boot:/boot"
        - "/run/dbus:/run/dbus"
        - "/run/systemd:/run/systemd"
    image: "test:latest"
    entrypoint: /app/docker-entrypoint.sh
    restart: unless-stopped
Run Code Online (Sandbox Code Playgroud)