TrueNAS Scale Native Docker & VM access to host [Guide]

You’re welcome to do as you please, just wanted to alert others attention to the video tutorial.

Since this is a less brittle long term solution, I would imagine any additional upfront effort is worth it. This new methodology shouldnt arbitrarily break on an update.

1 Like

This was discussed multiple times already, and it’s not the same in terms of performance.

I would not call this method brittle, it has survived multiple major updates with minor changes that were made before the final release of that update.

And now, with the “install-dev-tools” option, they have solved 2 problems, they have kept TrueNAS as they say “an appliance” to maintain support.

And whoever doesn’t want to use it like this, activates this option, and TrueNAS becomes a true Linux/Debian, but without any support.

I myself have already updated the script and removed the checks from the beginning that became obsolete and some others.

I also added the optional installation for Portainer and for those who use/need Nvidia VGA.

There are 4 new variables that need to be changed, 3 for the portainer and 1 to activate Nvidia support, they are self-explanatory, but if you have any doubts I can explain:

Enable Docker Script - Version: Dragonfish-24.04.0 + Portainer + Nvidia runtime
#!/usr/bin/env bash

# Enable docker and docker-compose on TrueNAS SCALE (no Kubernetes)
# Follow the guide in this post before using this script:
# https://forum.level1techs.com/t/truenas-scale-native-docker-vm-access-to-host-guide/190882
# This script is a hack! Use it at your own risk!!
# Edit all the vars under:
# Vars you need to change
# to point to your storage
#
# Schedule this script to run via System Settings -> Advanced -> Init/Shutdown Scripts
# Click Add -> Type: Script and choose this script -> When: choose to run as Post Init
exec >/mnt/ssd/Tools/enable-docker.log

# Vars you need to change:
# set a path to your docker dataset
docker_dataset="/you/docker/dataset"
# set the docker_daemon path on your storage for it to survive upgrades
new_docker_daemon="/you/new/docker/daemon.json"
# apt sources persist
new_apt_sources="/you/new/aptsources.list"
# Options: ON/OFF
# Install the Portainer container:
portainer_on="ON"
portainer_data="/you/data/portainer"
portainer_port=9443
# If you use an Nvidia VGA for transcoding in docker, enable this:
nvidia_on="OFF"

echo "§§ Starting script! §§"

echo "§§ Activating Developer Mode... §§"
install-dev-tools > /dev/null
echo "§§ Developer Mode Enabled. §§"

if [[ "$nvidia_on" == "ON" ]]; then
  echo "§§ Enabling Nvidia VGA for transcoding in docker... §§"

  KERNER=$(uname -r)
  DUNAME=/lib/modules/"$KERNER"/
  DIDKMS=/lib/modules/"$KERNER"/updates/dkms/

  echo "§§ Checking if nvidia modules are started... §§"
  if [[ ! -f "$DUNAME"nvidia-uvm.ko ]]; then
    echo "§§ nvidia-uvm.ko does not exist, creating module with symbolic link... §§"
    ln -s "$DIDKMS"nvidia-current-uvm.ko "$DUNAME"nvidia-uvm.ko
    echo "§§ Updating the module list... §§"
    depmod -a
    echo "§§ Starting Nvidia modules... §§"
    nvidia-container-cli -k -d /dev/tty info
  else
    echo "§§ nvidia-uvm.ko exists, checking if it is started... §§"
    if [[ ! -f /dev/nvidia-uvm ]]; then
      echo "§§ nvidia-uvm not started, starting... §§"
      nvidia-container-cli -k -d /dev/tty info
    else
      echo "§§ nvidia-uvm is already started. §§"
    fi
  fi
fi

echo "§§ apt update §§"
apt update > /dev/null

echo "§§ Linking apt sources to your storage for persistance §§"
echo "§§ Please note that with this you'll have to update the links manually on your storage when there's an update §§"
aptsources="/etc/apt/sources.list"
if [[ -f "$aptsources" ]] && [[ ! -L "$aptsources" ]]; then
  cp "$aptsources" "$new_apt_sources"
  mv "$aptsources" "$aptsources".old
fi
if [[ ! -f "$new_apt_sources" ]]; then
  touch "$new_apt_sources"
fi
if [[ ! -f "$aptsources" ]]; then
  ln -s "$new_apt_sources" "$aptsources"
fi
echo "§§ Fix the trust.gpg warnings §§"
# Create a directory for the new keyrings if it doesn't exist
mkdir -p /etc/apt/trusted.gpg.d

# Find all keys in the old keyring
for key in $(gpg --no-default-keyring --keyring /etc/apt/trusted.gpg --list-keys --with-colons | awk -F: '/^pub:/ { print $5 }'); do
  echo "Processing key: $key"
  # Export each key to a new keyring file in the trusted.gpg.d directory
  gpg --no-default-keyring --keyring /etc/apt/trusted.gpg --export --armor "$key" >/etc/apt/trusted.gpg.d/"$key".asc
done

# Backup the old keyring
mv /etc/apt/trusted.gpg /etc/apt/trusted.gpg.backup

#Docker Checks
echo "§§ Docker Checks §§"

if [[ ! -f /etc/apt/keyrings/docker.asc ]]; then
  echo "§§ Missing Keyrings §§"
  install -m 0755 -d /etc/apt/keyrings
  curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
  chmod a+r /etc/apt/keyrings/docker.asc
else
  echo "§§ Keyrings Exist §§"
fi
if ! grep -q "https://download.docker.com/linux/debian" /etc/apt/sources.list; then
  echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(lsb_release -cs) stable" >> /etc/apt/sources.list
  apt update
else
  echo "§§ Docker List: §§"
  cat /etc/apt/sources.list
fi

Docker=$(which docker)
DCRCHK=$(apt list --installed | grep docker)
if [[ -z "$Docker" ]] || [[ -z "$DCRCHK" ]]; then
  echo "Docker executable not found"
  apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
fi
echo "§§ Which Docker: $Docker §§"

## HEREDOC: docker/daemon.json
echo "§§ Docker daemon.json §§"
read -r -d '' JSON <<END_JSON
{
  "data-root": "${docker_dataset}",
  "storage-driver": "overlay2",
  "exec-opts": [
    "native.cgroupdriver=cgroupfs"
  ]
}
END_JSON

## path to docker daemon file
docker_daemon="/etc/docker/daemon.json"

if [[ ${EUID} -ne 0 ]]; then
  echo "§§ Please run this script as root or using sudo §§"
elif [[ "$(systemctl is-enabled k3s)" == "enabled" ]] || [[ "$(systemctl is-active k3s)" == "active" ]]; then
  echo "§§ You can not use this script while k3s is enabled or active §§"
elif ! zfs list "$docker_dataset" &>/dev/null; then
  echo "§§ Dataset not found: $docker_dataset §§"
else
  echo "§§ Checking file: ${docker_daemon} §§"
  if [[ -f "$docker_daemon" ]] && [[ ! -L "$docker_daemon" ]]; then
    rm -rf "$docker_daemon"
  fi
  if [[ ! -f "$new_docker_daemon" ]]; then
    touch "$new_docker_daemon"
  fi
  if [[ ! -f "$docker_daemon" ]]; then
    ln -s "$new_docker_daemon" "$docker_daemon"
  fi

  # Read the current JSON from the file
  current_json=$(cat $docker_daemon 2>/dev/null)
  echo -e "§§ current_json:\n$current_json\n§§"

  # Check if current_json is empty and if so, set it to an empty JSON object
  if [[ -z "$current_json" ]]; then
    current_json="{}"
  fi

  # Merge the current JSON with the new JSON
  merged_json=$(echo "$current_json" | jq --argjson add "$JSON" '. * $add')
  echo -e "§§ merged_json:\n$merged_json\n§§"
  # Check if the merged JSON is different from the current JSON
  if [[ "$merged_json" != "$current_json" ]] || [[ -z "$current_json" ]]; then
    echo "§§ Updating file: $docker_daemon §§"
    echo "$merged_json" | tee "$docker_daemon" >/dev/null
    if [[ "$(systemctl is-active docker)" == "active" ]]; then
      echo "§§ Restarting Docker §§"
      systemctl restart docker
    elif [[ "$(systemctl is-enabled docker)" != "enabled" ]]; then
      echo "§§ Enable and starting Docker §§"
      systemctl enable --now docker
    fi
  fi
fi

if [[ "$nvidia_on" == "ON" ]]; then
  ## Configure NVIDIA runtime in docker
  echo "§§ Configuring Nvidia runtime in docker... §§"
  RUNCHK=$(grep "nvidia-container-runtime" /etc/docker/daemon.json)

  if [ -z "$RUNCHK" ]; then
    nvidia-ctk runtime configure --runtime=docker
    echo "§§ Nvidia runtime configured. §§"
    echo "§§ Restarting Docker §§"
    systemctl restart docker
  else
    echo "§§ NVIDIA runtime is already configured. §§"
  fi
fi

if [[ "$portainer_on" == "ON" ]]; then
  echo "§§ Checking if Portainer is installed... §§"
  PORCHK=$(docker ps | grep portainer)
  if [ -z "$NVDCHK" ]; then
    echo "§§ Installing Portainer... §§"
    docker run -d -p $portainer_port:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v $portainer_data:/data portainer/portainer-ce:latest > /dev/null
    echo "§§ Portainer installed. §§"
  else
    echo "§§ Portainer is already installed. §§"
  fi
fi

Docker=$(which docker)
DockerV=$(docker --version)
echo "§§ Which Docker: $Docker §§"
echo "§§ Docker Version: $DockerV §§"

echo "§§ Script Finished! §§"

@Scepterus It clears me some doubts, the first, why do you use it:

#!/usr/bin/env bash
rather than:
#!/bin/bash

Another thing, I believe we no longer need to check the storage-driver, because apparently, now it will always be overlay2, correct?

And also, what this option does exactly:
. ~/.bashrc

And if you can take a look at the script I updated based on yours, any tips to improve it are always welcome :smiley:

1 Like

I tried to remove the NVIDIA kernel and reinstall it, but the NVIDIA container is tied to TrueNAS, at least in 23, so that’s not possible.

I just finished the Apps script, and upgraded to Dragonfish, I will update the first post with the relevant codes.

Because it is a better standard, if someone decided they wanted to install another version of bash, for example, I would always use the one that the user has defined.

Yes, but I would keep it as legacy for at least 2 more major versions, for backwards compatibility.

It sources the file bashrc after we make changes to it, or if we want to reload everything in the path and aliases.

  PORCHK=$(docker ps | grep portainer)
  if [ -z "$NVDCHK" ]; then

Two issues there, you used two names for the var, and also you only used one , it’s better to use 2 like [].

Aside from that, do you set the Nvidia on manually? You could just check if an NVIDIA card is present and switch it based on that.

Upgrade conclusions:
Just found out the upgrade overwrote the apt sources list in the link, I will need to figure out how to account for that, but thankfully I have a snapshot to restore from.

Another thing, I got this error when trying to update:

rm: cannot remove '/lib32': Read-only file system
dpkg: error processing package usrmerge (--configure):
 installed usrmerge package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
 usrmerge
E: Sub-process /usr/bin/dpkg returned an error code (1)

Using apt update. Still more fixing and adapting needed.
Ok, for some reason / was mounted as read-only. Adding a remount to the script.

Now everything works again.

I encountered the same issue with / being mounted read only. If you wait some time after booting, it would eventually get mounted read/write. Adding a remount very early in your script fixes this, as you found out.

1 Like

Yep, hopefully someone will now test these scripts together on a regular system upgrading from 23 to 24, and let us know how the upgrade went.

But so far, it seems to be fine.

1 Like

also:

if [[ ! -f "$DUNAME"nvidia-uvm.ko ]]; then
    echo "§§ nvidia-uvm.ko does not exist, creating module with symbolic link... §§"
    ln -s "$DIDKMS"nvidia-current-uvm.ko "$DUNAME"nvidia-uvm.ko
    echo "§§ Updating the module list... §§"
    depmod -a
    echo "§§ Starting Nvidia modules... §§"
    nvidia-container-cli -k -d /dev/tty info
else
    echo "§§ nvidia-uvm.ko exists, checking if it is started... §§"
    if [[ ! -e /dev/nvidia-uvm ]]; then
        echo "§§ nvidia-uvm not started, starting... §§"
        modprobe nvidia-uvm
        echo "§§ Updating the module list... §§"
        depmod -a
        nvidia-container-cli -k -d /dev/tty info
    else
        echo "§§ nvidia-uvm is already started. §§"
    fi
fi

Because your code was always looping the same results.

Hi Scepterus, thank you for the original post and your effort to answer all people’s questions from 2022!I actually had used WenDell’s method to migrate my apps (nextcloud, immich etc.) from Truecharts docker to VM. It seems that everything works well. However I feel that the performance of apps under VM is a bit below the Truecharts apps. Maybe it is because of the overhead in VM? By the way I am using DragonFish which is the latest version of TrueNAS Scale.

Now I saw your solution and feel that I may give it a try. I have some questions before trying:

  1. Apologise I haven’t gone through all your replies and posts. I would like to know if the original script in the 1st post (2022) still works under DragonFish. From a few latest posts it seems yes but I would just like to double check. Do I need to refer to a later post to make some changes?
  2. Would running docker natively break the TrueNAS system in some way? Is there any potential risk I need to be aware of?
  3. What is the best way to back up all the dockers/containers, configration, dataset if I take your approach? I would like to be able to restore all of them if something goes wrong.

Thanks again!

You’re welcome

yes still does.

not if you follow the guide correctly.

Just snapshots and an rsync of the docker dataset to another drive if you really want a backup.

Looks like IX-System is listening to the community – Native Docker / Docker Compose support is (officially) coming to SCALE this fall!

1 Like

Amazing, our hard work here paid off. However, the script for apps restore, and the other parts of the guide will still be relevant as each update will still remove the apps you install with apt.

1 Like

So just upgraded, needed to touch @Finallf script by a bit (thanks for sharing it btw!) and ensure it matches up with your latest script. I’m now running Dragonfish and it was mostly painless (needed to mkdir those directories to persist the daemon and apt source, woops).

Glad to see the next version is finally adding docker natively and properly! Like about time but hopefully this enforces running docker containers natively won’t be considered “breaking” the appliance that is truenas.

1 Like

Did anynone’s script stopped working after the update to 24.04.2?

I am getting this error when running the script.

E: Package 'docker-ce' has no installation candidate
E: Package 'docker-ce-cli' has no installation candidate
E: Unable to locate package containerd.io
E: Couldn't find any package by glob 'containerd.io'
E: Unable to locate package docker-buildx-plugin
E: Unable to locate package docker-compose-plugin

Hi, thanks so much for the guide! I’d like to run plex as a docker container accessible from my local network. Any hints as to how I can do this would be appreciated! I’m using this image plexinc/pms-docker:latest it seems to come up fine but nothing can connect to plex. I’m assuming some sort of network/firewall change is needed

cheers

Hey, did you use the latest version of the script? If so, we’ll debug further.

You’ll need to set up ports that are accessible in your compose file, any guide online on how to set up plex in docker compose should be fine, TrueNAS really does not play a part here.

@Scepterus thanks, will look this up.

@mforce the script works fine for me under Dragonfish-24.04.2

It still not working for me on 24.04.2, looks like an issue with pkg sources. I get this error when doing apt update.

sudo apt update
Hit:1 https://apt.sys.truenas.net/dragonfish/nightlies/debian bookworm InRelease
Hit:2 https://apt.sys.truenas.net/dragonfish/nightlies/libnvidia bookworm InRelease
Hit:3 https://apt.sys.truenas.net/dragonfish/nightlies/helm all InRelease
Hit:4 https://apt.sys.truenas.net/dragonfish/nightlies/debian-security bookworm-security InRelease
Hit:5 https://apt.sys.truenas.net/dragonfish/nightlies/debian-backports bookworm-backports InRelease
Hit:6 https://apt.sys.truenas.net/dragonfish/nightlies/debian-debug bookworm-debug InRelease
Hit:7 https://apt.sys.truenas.net/dragonfish/nightlies/yarn stable InRelease
Hit:8 https://apt.sys.truenas.net/dragonfish/nightlies/nvidia bookworm InRelease
Hit:9 https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
3 packages can be upgraded. Run 'apt list --upgradable' to see them.
W: Skipping acquire of configured file 'contrib/binary-amd64/Packages' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/debian-backports bookworm-backports InRelease' doesn't have the component 'contrib' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'contrib/i18n/Translation-en' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/debian-backports bookworm-backports InRelease' doesn't have the component 'contrib' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'non-free/binary-amd64/Packages' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/debian-backports bookworm-backports InRelease' doesn't have the component 'non-free' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'non-free/i18n/Translation-en' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/debian-backports bookworm-backports InRelease' doesn't have the component 'non-free' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'maindeb/binary-amd64/Packages' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'maindeb' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'maindeb/i18n/Translation-en' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'maindeb' (component misspelt in sources.list?)
W: Skipping acquire of configured file '[arch=amd64 signed-by=/etc/apt/keyrings/docker.asc]/binary-amd64/Packages' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component '[arch=amd64 signed-by=/etc/apt/keyrings/docker.asc]' (component misspelt in sources.list?)
W: Skipping acquire of configured file '[arch=amd64 signed-by=/etc/apt/keyrings/docker.asc]/i18n/Translation-en' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component '[arch=amd64 signed-by=/etc/apt/keyrings/docker.asc]' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'https://download.docker.com/linux/debian/binary-amd64/Packages' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'https://download.docker.com/linux/debian' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'https://download.docker.com/linux/debian/i18n/Translation-en' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'https://download.docker.com/linux/debian' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'bookworm/binary-amd64/Packages' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'bookworm' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'bookworm/i18n/Translation-en' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'bookworm' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'stable/binary-amd64/Packages' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'stable' (component misspelt in sources.list?)
W: Skipping acquire of configured file 'stable/i18n/Translation-en' as repository 'https://apt.sys.truenas.net/dragonfish/nightlies/pcm bookworm InRelease' doesn't have the component 'stable' (component misspelt in sources.list?)

that’s because you have nightlies in your apt list.
try these:

deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable
deb http://deb.debian.org/debian/ bookworm main non-free non-free-firmware
#deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/debian/ bookworm main
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/libnvidia/ bookworm main
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/helm/ all main
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/debian-security/ bookworm-security main
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/debian-backports/ bookworm-backports main contrib non-free
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/debian-debug/ bookworm-debug main
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/yarn/ stable main
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/nvidia/ bookworm main
deb http://apt.tn.ixsystems.com/apt-direct/dragonfish/24.04.0/pcm/ bookworm main

Thanks that was the issue, your list did not work though I had to use my list with the updated version 24.04.1 instead of nightlies and that did it.

1 Like

Glad that solved your issue.

1 Like