Systemd service to maintain IPFS daemon on low-end system

Hello everyone. I deployed IPFS daemons on the several low-end machines, including OrangePI (4x ARM cores CPU, 1GB RAM) and Debian-equipped server (Pentium IV 1.8 GHz single-core CPU, 2 GB RAM), running as systemd services. These machines require strong limits on CPU resources, memory consumption, kernel requests. To enforce the limitations I use systemd for running IPFS daemon. The daemon itself is wrapped with the following script:

#!/usr/bin/env bash

export IPFS_PATH="/util/ipfs" 
PID_FILE="${IPFS_PATH}/daemon.pid"
export GOMAXPROCS=1
export IPFS_LOGGING="info"

if [[ "$1" == "stop" && -f "${PID_FILE}" ]]
then
    /bin/kill -s SIGINT `cat "${PID_FILE}"`
    sleep 5
    if grep -qs "${IPFS_PATH}/mount/ipfs" /proc/mounts
    then
	umount "${IPFS_PATH}/mount/ipfs"
    fi
    if grep -qs "${IPFS_PATH}/mount/ipns" /proc/mounts
    then
	umount "${IPFS_PATH}/mount/ipns"
    fi
    exit 0
fi
/util/bin/ipfs daemon --mount --enable-gc &
echo -e "$!" > ${PID_FILE}

systemd unit file for the daemon limits resource consumption with accounting directives:

[Unit]
Description=IPFS single node control service - P2P distributed content-based CDN with file frontend
After=syslog.target network.target remote-fs.target nss-lookup.target


[Service]
Type=forking
ExecStart=/util/ipfs/ipfs-service.daemon
ExecStop=/util/ipfs/ipfs-service.daemon stop
PIDFile=/util/ipfs/daemon.pid
TimeoutSec=60
User=ipfs
Group=ipfs
MemoryAccounting=true
MemoryHigh=134217728
MemoryMax=402653184
Restart=on-failure
RestartSec=10s
CPUAccounting=true
CPUQuota=30%


[Install]
WantedBy=multi-user.target

The daemons operate slow, but this kind of setup allows to prevent memory leaks and CPU hangups. The limitation for the number of processes is available through systemd but it can produce strange crashes of the daemon because of process management algorithm in Golang standard library.

I will be appreciated with any comments or reviews.

Note ipfs provides [quite advanced] systemd service files:

It’s important that the service is of type notify as this correctly lets systemd know that IPFS is up at the moment where it is actually up.

Thus, it would be best if your service file was based on the upstream.

Additionally, you can include env vars directly in the service file. You can also configure specific pre and post scripts to be called from it, rather than wrapping the binary on a script itself.

1 Like

Thanks for this review, @hector! I experienced some problems with the upstream service files (especially, deploying on OrangePI), that’s why I decided to write my own. For example, pre and post scripts weren’t running correctly, After section for my case with Pentium IV machine was unsuccessful.

I will try to customize the upstream files to avoid the problems. If I will be lucky, I will write a report here.

1 Like

I based on the upstream unit files but added mount possibility. Now the unit file looks as following:

[Unit]
Description=IPFS single node control service - P2P distributed content-based CDN with file frontend
Documentation=https://docs.ipfs.io/
After=syslog.target network.target remote-fs.target nss-lookup.target


[Service]
Type=notify

Environment=IPFS_PATH=/media/storage/system/ipfs
Environment=IPFS_LOGGING="info"
Environment=IPFS_CONFIG=/media/storage/system/ipfs/config

#Runtime
ExecStartPre=/media/storage/system/ipfs/ipfs-service.daemon umount
ExecStart=/util/bin/ipfs daemon --mount --migrate --enable-gc
TimeoutSec=60
User=ipfs
Group=ipfs
Restart=on-failure
RestartSec=10s
KillSignal=SIGINT

#Accounting
MemoryAccounting=true
MemoryHigh=134217728
MemoryMax=402653184
CPUAccounting=true
CPUQuota=40%
MemorySwapMax=0

[Install]
WantedBy=multi-user.target

The script now handles the issue when the daemon does not unmount the FUSE mount points when exiting with SIGTERM:

    export IPFS_PATH="/media/storage/system/ipfs"
    if grep -qs "${IPFS_PATH}/mount/ipfs" /proc/mounts
    then
	umount "${IPFS_PATH}/mount/ipfs"
    fi
    if grep -qs "${IPFS_PATH}/mount/ipns" /proc/mounts
    then
	umount "${IPFS_PATH}/mount/ipns"
    fi
    exit 0

The daemons are now working in test mode, I will wait for several days to obtain useful stats.