Raspberry Pi with Docker

, updated 23 June 2024 🔖 iot ⏲️ 3 minutes to read

I use Raspberry Pis to host services for my home network, with Docker to keep things manageable in containers. Each Pi has a USB SSD as its boot drive running Raspberry Pi OS.

There's often a bit of boilerplate I need to keep track of to set up a new one, so I am documenting all of the snippets here for my future self.

  1. Increase Swap Size
  2. Disable DHCP for Virtual Ethernet Interfaces
  3. Install Docker
  4. Make SSH Secure
  5. Managing Docker Compose
  6. Passwordless Sudo
  7. Overclocking
  8. Temperature and Speed
  9. Architecture Emulation
  10. Disable WiFi Power Saving
  11. Create a systemd Service
  12. Disable nftables

Increase Swap Size

If you're using an SSD as a boot drive, the default 100MB limit for Swap doesn't make sense. There is a great article here documenting how to change this, but the key bits are:

$ nano /etc/dphys-swapfile

Comment out CONF_SWAPSIZE, since it is explicitly set to 100. Commenting it out makes the OS manage it automatically, and in my case made the swap size 2GB.

#CONF_SWAPSIZE=100

Then restart the Swap service:

$ /etc/init.d/dphys-swapfile restart

You can use free -m or htop to verify the change.

Disable DHCP for Virtual Ethernet Interfaces

Docker creates a lot of virtual ethernet interfaces, and they all start requesting IP addresses and it all ends very badly (the Pi will drop off the network at some point after being on for a while).

The fix is to tweak the DHCP config:

$ nano /etc/dhcpcd.conf

Add the following to the very top of the file:

denyinterfaces veth*

Then restart the DCHP daemon:

$ systemctl daemon-reload
$ systemctl restart dhcpcd

Install Docker

The best thing to do to set up Docker for the first time is the following:

$ apt-get update
$ apt-get upgrade
$ reboot

The reboot at the end is crucial, as I found some Docker installation errors when not rebooting.

$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sh get-docker.sh
$ reboot

That last reboot is just for good measure - it's probably not necessary. Then you're good to go!

Make SSH Secure

To make SSH more secure, we should disable username/password auth.

$ nano /etc/ssh/sshd_config

Comment out every entry, so the file only has the following uncommented entries (you could delete the file contents and replace it with the below, but then you lose all of the documentation):

Include /etc/ssh/sshd_config.d/*.conf
PermitRootLogin no
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM no
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem       sftp    /usr/lib/openssh/sftp-server

Then restart SSH:

$ systemctl restart ssh

Managing Docker Compose

To deploy a service with Docker Compose, go to the directory containing the docker-compose.yml file, then:

$ docker compose up -d

To update a Docker compose service:

$ docker compose pull

To remove the service:

$ docker compose down

Passwordless Sudo

To enable passwordless sudo:

$ visudo /etc/sudoers.d/010_pi-nopasswd

Then change the content to:

pi ALL=(ALL) ALL

Where pi is the username you're logging in with.

Overclocking

If you have adequate active cooling set up around your Pi, you can go for glory with the CPU clock speed:

$ nano /boot/config.txt
#uncomment to overclock the arm. 700 MHz is the default.
over_voltage=6
arm_freq=2147

This clocks the CPU up to 2.1GHz.

Temperature and Speed

Measure the current CPU frequency in Hz:

vcgencmd measure_clock arm
frequency(48)=1800457088

Get the CPU temperature:

$ vcgencmd measure_temp
temp=59.4'C

Get the CPU temperature, but update live:

$ watch --interval 0.1 -- 'vcgencmd measure_temp'

It's also possible to read this from a file:

$ cat /sys/class/thermal/thermal_zone0/temp
53069

Here's some Python code to read it as degrees celsius:

with open('/sys/class/thermal/thermal_zone0/temp') as f:
        current_cpu_temp = float(f.read()) / 1000

Architecture Emulation

If you need to run non-ARM Docker containers, you can install an emulation layer. This article has an in-depth explanation: Run AMD64 Docker Images On An ARM Computer

The below command enables amd64 support via the following library: https://github.com/tonistiigi/binfmt

$ docker run --privileged --rm tonistiigi/binfmt --install amd64

AMD64 containers will now run, just much more slowly than on the native hardware.

Disable WiFi Power Saving

The WiFi chip, by default uses power saving. To check the status of this, use the following command:

$ iw wlan0 get power_save
Power save: on

To disable WiFi Power Saving permanently, use the following command:

$ nmcli con mod preconfigured wifi.powersave disable

Note that this will not disable power saving immediately, but at the next boot.

Create a systemd Service

First, create the service definition:

$ nano /etc/systemd/system/example.service

Example, with placeholders for description, user, working directory and command.

[Unit]
Description=<description>
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=1
User=<user>
WorkingDirectory=<working directory>
ExecStart=<command>

[Install]
WantedBy=multi-user.target

The service is enabled with:

$ systemctl enable example.service

And started with:

$ systemctl start example.service

To check the status of the service:

$ systemctl status example.service

And to get logs from the service if it errors:

$ journalctl -u example.service

Disable nftables

This was a one-time problem and should be considered "deprecated" from the guide.

I ran into an issue where Raspberry Pi OS installed an update which bricked the Docker daemon, because the update forced a switch from iptables to nftables (Docker wanted iptables). I ended up fixing it by forcing the use of iptables, then re-installing docker.

$ update-alternatives --set iptables /usr/sbin/iptables-legacy
$ update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
$ update-alternatives --set arptables /usr/sbin/arptables-legacy
$ update-alternatives --set ebtables /usr/sbin/ebtables-legacy

🏷️ docker pi swap power file cpu raspberry install ssh temperature wifi containers boot os dhcp

⬅️ Previous post: Fixing UE5 Chaos Events at Runtime

➡️ Next post: Fixing UE5 Level Sequence Assertion

🎲 Random post: Generating Mipmaps for Render Targets in UE4

Comments

Please click here to load comments.