Synology: Run the latest Docker daemon without patching DSM6.x

Kristofer Lundgren
4 min readMar 20, 2021

Updated 2021–06–17.

If you have a Synology with an Intel CPU. Docker is available as a package in Package Center. Although, the Docker daemon installed is quite old.

The problem

The default Docker daemon has severe issues if you try using it to deploy services in a Docker Swarm. For instance, if you try to pass environment variables to a container through a docker-compose.yml file, and start services as part of a Docker Stack, the environment variables cannot be passed to the containers.

Also, many features have been added since the release of the old Docker version.

The “other” hacks

There are instructions available on the Internet how to hack the installed Docker daemon and install a later version in the Synology Linux distribution itself. Such solutions are rarely good in the long run, as modifying the Synology installation is not supported, and may(will) break in bad ways when Synology updates the Linux configuration in the future.

The alternative

The existing Docker daemon can run single containers just fine.
What if we run another Docker daemon in a Container? This in generally known as Docker in Docker, i.e. DinD.
In this article we will call the original Docker daemon the “L1 Docker daemon”. And our newly installed daemon the “L2 Docker daemon” (Layer 1 and 2).

Tasks

  • Start the L2 Docker daemon on a supported filesystem.
  • Connect the L2 Docker daemon to the host network
  • Expose the management interface (Docker socket) from L2 Docker Daemon on the host securely.
  • The Synology docker command should control the L2 Docker daemon by default.

Hurdle no.1 , the filesystem

For unknown reasons, Docker in Docker on Synology cannot run on the BTRFS filesystem. Technically it ought to be possible. The solution is to run the L2 Docker daemon on a EXT4 filesystem instead.

If your /volume1 filesystem is BTRFS, create a second volume using the Synology “Storage Manager”, Choose EXT4 as the filesystem and give it a size of 10GB to start with. you can grow the volume later when needed.

Connect to the Synology server using SSH

Enable SSH on the Synology server:

  • Control Panel -> Terminal & SNMP -> Enable SSH Service
  • Login using ssh and your administrative username and password.
    ssh <admin-account>@<ip-of-synology>
  • Change to the root account. Use your administrative password when asked.
    sudo -i

L1 Docker daemon configuration

We will change the L1 Docker daemon to expose the management docker-socket in a new location. And then, configure the L2 Docker socket to listen on the location of the original L1 Docker daemon location. This enables the docker CLI tool to manage the L2 Docker daemon by default.

We also configure the use of the Google Docker registry, to avoid the Docker Hub registry pull restrictions ¹. Additionally, we also disable the userland-proxy, which is known to slow down packet forwarding ².

  • As root, run this command, and add the content below between the curly braces. And make sure you get the commas in the right place:
    nano /var/packages/Docker/etc/dockerd.json
   "hosts": ["unix:///var/run/docker-L1.sock"],
"registry-mirrors": [
"https://mirror.gcr.io"
],
"userland-proxy": false,

You can verify the json document here: https://jsonlint.com/

  • Restart the L1 Docker daemon, and it will automatically restart with the new settings. Run command as root:
    killall dockerd

Start the L2 Docker daemon

As root, run this command to create the L2 Docker configuration, and copy the content below:
nano /etc/docker/docker-L2-compose.yml

version: "3.7"
# Docker in Docker for Synology servers.
# See docs at: https://kristoferlundgren.medium.com/synology-run-the-latest-docker-daemon-without-patching-dsm6-x-7bb4834d87bc
#
# Commands:
# docker-compose \
# --file /etc/docker/docker-L2-compose.yml \
# --host unix:///var/run/docker-L1.sock up -d
# docker-compose \
# --file /etc/docker/docker-L2-compose.yml \
# --host unix:///var/run/docker-L1.sock down
services:
docker-L2:
image: docker:dind
restart: unless-stopped
container_name: docker-L2
volumes:
- /var/run:/var/run
- /etc/group:/etc/group
- /volume1:/volume1
- /volume2:/volume2
network_mode: "host"
privileged: true
entrypoint: /usr/local/bin/dockerd
command:
- --userland-proxy=false
- --registry-mirror=https://mirror.gcr.io
- --exec-root
- /tmp/var-run-docker
- --data-root
- /volume2/docker-L2/var-lib-docker
- --pidfile
- /dev/null
- --host
- "unix:///var/run/docker.sock"
- --host
- "unix:///var/run/docker-L2.sock"

The above configuration assumes the EXT4 partition is located at /volume2 . Change the file if that is not the case.

Finally, start the L2 Docker daemon with this command:

docker-compose --file /etc/docker/docker-L2-compose.yml --host unix:///var/run/docker-L1.sock up -d

The L2 Docker daemon will now start and be available with the usual docker CLI tool. The L2 Docker daemon will also start automatically when the Synology starts/restarts.

Verify the L2 Docker daemon installation

To verify you can access the L2 Docker daemon, issue this command:

docker info --format '{{.ServerVersion}}'

The version returned is the version of the L2 Docker daemon, and should now be a version above 20.

Verify port forwarding using the L2 Docker daemon

Start a small web server using this command:

docker run --rm -ti -p 8080:80 caddy
# Stop the web server with Ctrl-C.

Open a web browser and access http://<synology-host-ip>:8080.

Enjoy!

In case of failure

To stop the L2 docker daemon, use this command:

docker-compose --file /etc/docker/docker-L2-compose.yml --host unix:///var/run/docker-L1.sock down

To delete the L2 Docker daemon runtime environment, and start over. Issue this command:

rm -rf /volume2/docker-L2

You can also uninstall/install the Docker Synology package to start over completely.

Updates

  • 2021–04–17
    Changed --pidfile option to /dev/null. The pid file must not be kept between reboots, and this update achieves this very effectively.
  • 2021–04–17
    Added In case of failure paragraph.
  • 2021-06–17
    Changed --exec-root directory for L2 Docker daemon to /tmp/var-run-docker. The L2 Docker daemon would not start if the directory was retained between reboot of the Synology server. This is solved by putting the directory in docker container’s /tmp.

--

--

Kristofer Lundgren

A systems engineer using DevOps principles on a daily basis.