4

I have a python application that's meant to be run on a raspberry pi. I've created a docker-compose file to set it up, and my entry point happens to be a shell script that checks various things on the host such as:

  1. Making sure SPI is enabled, if it is not then enabling it by accessing /boot/config.txt and writing to it.
  2. Installing and enabling the watchdog service.
  3. Running my docker container automatically on reboot by writing it into /etc/rc.local (although I am considering replacing this with the restart: always or unless-stopped flag from the docker-compose file)

The problem is, if I enable SPI, the raspberry pi needs to reboot to set it up (not quite sure why), but when my shell script reaches the sudo reboot command from within the docker container, I get the following error:

 Failed to connect to bus: No such file or directory
 Failed to talk to init daemon.

I understand that it's probably trying to find dbus and the init daemon within the docker container but they don't exist. How do I give my container access to these resources? Do I need to mount another volume? This is my docker-compose.yml file:

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

FG is my python application with the entry point docker-entrypoint.sh which looks like:

#!/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       

The privileged option already gives my container access to the GPIO, I imagined it would give me access to reboot as well, however it seems that is not the case. Please let me know what I need to do to be able to reboot.

1 Answer 1

6

My first guess is that you simply need to expose /run/dbus and /run/systemd to your container, as in:

docker run -v /run/dbus:/run/dbus -v /run/systemd:/run/systemd ...

But while that is necessary, it isn't sufficient; with just those two bind mounts, attempting to interact with the host systemd from inside the container results in:

[root@631fff40f09c /]# reboot
Failed to connect to bus: No data available
Failed to talk to init daemon.

It turns out that the in order for this to work, the container must be running in the host's global PID namespace, which means we need:

docker run -v /run/dbus:/run/dbus -v /run/systemd:/run/systemd --pid=host ...

With this in place, running reboot inside the container successfully reboots the host.

In a docker-compose.yml, that would look something like:

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
Sign up to request clarification or add additional context in comments.

3 Comments

Hey thank you so much for your help! It turns out, just mounting /run/dbus was enough, and my container successfully rebooted the host :) I am curious as to why it worked without using the host's pid though, could it be that --net=host or --privileged cover that?
Not sure. I couldn't get it to work w/o using --pid=host. Glad it turned out to be simpler for you!
@AbdurRehmanKhan Just a guess, but I think Raspberry pi kernel doesn't support pid namespaces, so --pid=host is implied when running docker on rpi

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.