Get systemd installed in a Balena image

I am trying to control (start/stop/restart/etc) the bluetooth service from the command line in my application container. From what I understand to use systemctl I need to have systemd as my init system. I followed the example here and can now use systemctl, however when I issue systemctl stop bluetooth.service or systemctl start bluetooth.service I don’t get an error message but I also don’t seem to actually start or stop the service at all.

I can issue those same start and stop commands from the device cli (SSHd in locally) and they have the desired effect.

Am I missing some part of the configuration process to get systemd to work with UDEV?

Below is my Dockerfile.template:

FROM balenalib/%%BALENA_MACHINE_NAME%%-debian:latest

#################
# Install Systemd
#################
ENV container docker
RUN sudo apt-get update -y  && \
    sudo apt-get install  -y --no-install-recommends systemd-sysv && \
    sudo apt-get clean && \
    sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# We never want these to run in a container
# Feel free to edit the list but this is the one we used
RUN systemctl mask \
    dev-hugepages.mount \
    sys-fs-fuse-connections.mount \
    sys-kernel-config.mount \

    display-manager.service \
    getty@.service \
    systemd-logind.service \
    systemd-remount-fs.service \

    getty.target \
    graphical.target

COPY systemd/entry.sh /usr/bin/entry.sh
COPY systemd/balena.service /etc/systemd/system/balena.service

RUN systemctl enable /etc/systemd/system/balena.service

STOPSIGNAL 37
ENTRYPOINT ["/usr/bin/entry.sh"]
ENV INITSYSTEM on
######################
# Finish setup systemd
######################


# Download system dependencies we have during runtime as well as the ones needed to build/install TinyB, then make sure
# the WiFi radio is on and unblocked
RUN sudo apt-get update -y  && \
    sudo apt-get install build-essential cmake git libglib2.0-dev dnsmasq network-manager openjdk-8-jdk pkg-config sqlite3 wireless-tools -y && \
    sudo apt-get clean && \
    sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
#   sudo nmcli radio wifi on && sudo rfkill unblock 0 && sudo rfkill unblock 1

ARG DEBIAN_FRONTEND=noninteractive
RUN sudo apt-get update -y && ln -fs /usr/share/zoneinfo/America/Denver /etc/localtime && sudo apt-get install -y bluetooth bluez bluez-firmware bluez-tools rfkill libdbus-1-dev libudev-dev libical-dev libreadline-dev -y && dpkg-reconfigure --frontend noninteractive tzdata \
    && \
    sudo apt-get clean && \
    sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

WORKDIR /

# Prep the environment
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-armhf
ENV DBUS_SYSTEM_BUS_ADDRESS unix:path=/host/run/dbus/system_bus_socket

# Get WiFi Connect ready
WORKDIR /wifi-connect
RUN curl https://api.github.com/repos/balena-io/wifi-connect/releases/latest -s \
    | grep -hoP 'browser_download_url": "\K.*%%BALENA_ARCH%%\.tar\.gz' \
    | xargs -n1 curl -Ls \
    | tar -xvz -C /wifi-connect/

# Download, build, and install TinyB
WORKDIR /
RUN git clone https://github.com/parsyl/tinyb.git
WORKDIR /tinyb/build
RUN cmake -DBUILDJAVA=ON -DCMAKE_INSTALL_PREFIX=/usr .. && make && make install

# Copy our tarball and the start script over, then fire things up
WORKDIR /app
COPY ./gateway.tar ./
RUN tar -xvf gateway.tar

COPY ./start.sh ./

CMD ./start.sh

And here is my Docker compose file, if needed:

version: 2
services:
  gateway:
    build: ./
    labels:
      io.balena.features.dbus: "1"
      io.balena.features.supervisor-api: "1"
      io.balena.features.balena-api: '1'
    network_mode: host
    privileged: true
    restart: always
    ports:
      - "8883"
    volumes:
      - com_parsyl_commons_storage:/app/com.parsyl.commons.storage
volumes:
  com_parsyl_commons_storage:

And finally, here is a systemctl status bluetooth.service command issued from within the running application container:

root@47cd5cb:/app# systemctl status bluetooth.service
● bluetooth.service - Bluetooth service
   Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2020-01-23 10:02:18 MST; 6min ago
     Docs: man:bluetoothd(8)
 Main PID: 85 (bluetoothd)
   Status: "Running"
   Memory: 1.6M
   CGroup: /docker/63ae65800e2c265cecd4dd42c009fcd4dda177f45d27c0dde95371b774749622/system.slice/bluetooth.service
           └─85 /usr/lib/bluetooth/bluetoothd

Jan 23 10:02:17 47cd5cb systemd[1]: Starting Bluetooth service...
Jan 23 10:02:17 47cd5cb bluetoothd[85]: Bluetooth daemon 5.50
Jan 23 10:02:18 47cd5cb systemd[1]: Started Bluetooth service.
Jan 23 10:02:18 47cd5cb bluetoothd[85]: Starting SDP server
Jan 23 10:02:18 47cd5cb bluetoothd[85]: binding L2CAP socket: Address already in use
Jan 23 10:02:18 47cd5cb bluetoothd[85]: Server initialization failed
Jan 23 10:02:18 47cd5cb bluetoothd[85]: Bluetooth management interface 1.14 initialized
Jan 23 10:02:18 47cd5cb bluetoothd[85]: Failed to start listening: l2cap_bind: Address already in use (98)
Jan 23 10:02:18 47cd5cb bluetoothd[85]: Failed to create GATT database for adapter
Jan 23 10:02:18 47cd5cb bluetoothd[85]: Unable to register new adapter
root@47cd5cb:/app#

Hi, @scarson. Can you give us a bit more detail about what you are trying to do? The more context we have, the better we can help guide you to the best solution. For example, I’m not sure installing systemd in a container is necessarily the best approach not least as you can likely achieve what you want via dbus. There is some info here https://www.balena.io/docs/learn/develop/runtime/#dbus-communication-with-host-os. that might make a good starting point.

@garethtdavies, Thanks for getting back to me!

We are building an application on a Balena Fin that is constantly scanning for BLE devices, connecting, and offloading some stored data. We noticed odd behaviour where after avariable amount of time (Sometimes 6ish hours, sometimes a few days) bluez would stop reporting bluetooth devices while scanning, but we wouldn’t get any errors. After some investigation we discovered the problem can be fixed by rebooting the Fin OR restarting the Bluetooth service from the host OS. using bluetoothctl or tinyb to power off/power on the bluetooth adapter didn’t fix it, and neither did restarting the application container. We also tried restarting the service from within the container but kept getting errors regarding the fact that we weren’t using an init system like systemd.

Neither solution (rebooting the Fin or restarting the Bluetooth service) is ideal, but we decided we would rather restart the service on a fairly regular basis than reboot the Fin. Any insight into helping with this issue would be greatly appreciated. Bluez is no fun to work with.

Hi @scarson ,

Since you want to restart a hostOS service you can communicate with the systemd of the hostOS via the dbus. To enable access to the host dbus you need to add the io.balena.features.dbus label to the container. (https://www.balena.io/docs/reference/supervisor/docker-compose/#labels)

From within you container you can then restart the host bluetooth service by running the following command:

DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket dbus-send --system --print-reply --reply-timeout=2000 --type=method_call   --dest=org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager.RestartUnit string:bluetooth.service string:replace

I hope this helps.

Can you tell us what OS version and Fin version you are using? We would like to try to reproduce the underlying problem and try to fix it, so that ideally you would not have to restart the bluetooth service at all.

Thanks

Fin v1.1 and OS version 2.38.0+rev1.

Our app consists of a Kotlin/Java application utilizing tinyb for BLE running on a Debian image.

When we notice that scanning stops reporting advertisements we have ssh’d in to the application and host device to confirm that bluez is not reporting new advertisements (using bluetooth ctl/hci tool/ hci dump) so it does not seem to be just a tinyb issue.

Using bluetoothctl to turn on/off the adapter does not fix the issue, only rebooting or restarting the bluetooth service.

Hi,
Thanks for the extra information.
I’ve passed this internally and we will get back to you once we have something to share.

Kind regards,
Thodoris

Hi @scarson

I just want to follow up whether the workaround using the io.balena.features.dbus label as suggested by afitzek last week worked for you to restart the bluetooth service? In terms of getting to the root of the problem, we’re still investigating this internally and will get back to you once we have news.

Kind regards
Alida

Hi, can you enable support access and share the link to such a device when it has this issue please? And when you do that please enable support access for the longest period of time so we can have time to look into it.

Hey there, coworker of @scarson here. @AlidaOdendaal, I think he managed to restart the service using the workaround mentioned.

We’re still really curious about why this is happening and would love to prevent it altogether, so @floion, I’ll enable support access as soon as we notice a device doing it. They typically run just fine for a number of hours, then things get worse over night.

For a bit more insight into what our application is doing (in case it helps once we give you support access), our application basically performs the following steps:

  1. Make sure the BLE adapter is on.
  2. Set a discovery filter that ensures duplicate data updates are ON. We want to see every single advertisement from our devices, regardless of whether it has changed or not.
  3. Start BLE device discovery.
  4. For ~30 seconds, continuously check for devices that BlueZ has found, enable manufacturer data updates for them, and process updates as they come in. Processing may include connection to a device- we leave discovery and updates turned on during this time.
  5. Once all processing has finished and the 30-second limit is up, stop BLE device discovery.
  6. Disable manufacturer data updates for all discovered devices.
  7. “Remove” all discovered devices (this is a TinyB notion and doesn’t affect BlueZ in any way, AFAIK).
  8. Wait ~2 mins and then repeat all steps.

Thanks for the help on this stuff folks, we really appreciate it!

Hi, thanks for the details, it’s great to have context to better understand the problem.
Whenever you detect a device that is failing please let us know and if possible also grant support access to a working device, it could be useful while we investigate the issue.

Hey @floion and @tmigone, we’ve got a couple devices failing now, so I gave you support access to one of them for a week. Anything else you need from me? A device UUID or anything?

Hey there, can you send me a private message with the device(s) UUID(s) so we can take a look?

Sent!

Hi @scarson if we need to restart the running service or the device is this ok?

Also as extra info do you have any other bluetooth devices connected? Like a USB bluetooth adapter?

Hi, I noticed that on the unit you shared, you are using OS version 2.38.0+rev1. Starting with OS version v2.40.0+rev1 we have a new driver for bluetooth. Can you upgrade some units the latest OS release available for the Balena Fin and see if you still get this problem?

@mbalamat Yup, feel free to reboot and do whatever you need! No extra Bluetooth devices connected.

@floion Interesting… We’ve updated some devices to 2.46.1+rev3 and have had issues with WiFi Connect, so we’ve reverted. I haven’t noticed if this has been fixed in that version for us- I’ll do some checking to see if that’s the case and post back in here.

@floion Unfortunately, it looks like this issue happens in 2.46.1+rev3 as well. If you guys want access to a device running that OS version, let me know and I’ll grant it.

Yes please, if we can get access to a device running 2.46.1+rev3 that would be great. Can you enable support access and share a device UUID so we can take a look?