Part of collection: Hyper-converged Homelab with Proxmox
Update 09-10-2024: I have moved on to a setup with Docker LXC on Proxmox, with bind-mounts (without VirtioFS) as described in Gist Docker Swarm in Vm's with CephFS.
Update 07-03-2025: The Dockge LXC does this even better, eliminating most issues, with the Docker LXC](https://community-scripts.github.io/ProxmoxVE/scripts?id=docker)!
After struggling for some days, and since I really needed this to work (ignoring the it can't be done vibe everywhere), I managed to get Docker to work reliable in privileged Debian 12 LXC Containers on Proxmox 8
(Unfortunately, I couldn't get anything to work in unprivileged LXC Containers)
There are NO modifications required on the Proxmox host or the /etc/pve/lxc/xxx.conf
file; everything is done on the Docker Swarm host. So the only obvious candidate who could break this setup, are future Docker Engine updates!
My host are Debian 12 LXC containers, installed via tteck's Proxmox VE Helper Scripts
bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/debian.sh)"
Docker info shows i'm using overlay2, this is the recommended storage driver for Debian. This storage driver requires XFS or EXT4 as backing file system.
docker info | grep -A 7 "Storage Driver:"
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: systemd
As Neuer_User pointed out, running the Docker Containers unprivileged on a privileged
LXC seems the best compromise to run the containers in a relative secure way.
To do so, add a daemon.json on the Docker Servers that are part of the Swarm.
mkdir /etc/docker
nano /etc/docker/daemon.json
{
"userns-remap": "root"
}
And reboot reboot
the Docker Host.
(This moves everything below /var/lib/docker/ to the folder /var/lib/docker/0.0/ existing workload disappear, hence it's a step pre Docker installation!)
The get-docker.sh script is the most convenient way to quickly install the latest Docker-CE release!
curl -fsSL https://get.docker.com -o get-docker.sh
chmod +x get-docker.sh
./get-docker.sh
Without this step, the next step(s) fail!
# Manager Node
docker swarm init
# Add Node
docker swarm join --token <some-very-long-token>
# Display Join token again
docker swarm join-token worker
docker swarm join-token manager
For Docker in LXC to work, the only thing needed is to execute:
nsenter --net=/run/docker/netns/ingress_sbox sysctl -w net.ipv4.ip_forward=1
on the Docker Swarm Servers
This doesn't survive reboots, so I created an oneshot systemd service for it, to make sure that after each reboot the setting is applied.
First, we need a Bash script to be executed by the service.
nano /usr/local/bin/ipforward.sh
#!/bin/bash
nsenter --net=/run/docker/netns/ingress_sbox sysctl -w net.ipv4.ip_forward=1
chmod +x /usr/local/bin/ipforward.sh
This service is of the type oneshot
, during startup it waits for the docker.service
to be started, and then 10 seconds for run-docker-netns-ingress_sbox.mount
to be loaded. Only after that net.ipv4.ip_forward=1
can be applied.
nano /etc/systemd/system/ingress-sbox-ipforward.service
[Unit]
Description = Set net.ipv4.ip_forward for ingress_sbox namespace
After = docker.service
Wants = docker.service
[Service]
Type = oneshot
RemainAfterExit = yes
ExecStartPre = /bin/sleep 10
ExecStart = /usr/local/bin/ipforward.sh
[Install]
WantedBy = multi-user.target
systemctl daemon-reload
systemctl enable ingress-sbox-ipforward.service
systemctl start ingress-sbox-ipforward.service
systemctl status ingress-sbox-ipforward.service
Without ipv4.ip_forward set to 1, the Ingress Networking to the Docker Swarm is not active. So it's important to verify if the value is applied successfully.
systemctl status ingress-sbox-ipforward.service | grep ipforward.sh
# Or in a script via:
current_value=$(nsenter --net=/run/docker/netns/ingress_sbox sysctl -n net.ipv4.ip_forward)
echo $current_value
(Now, Docker in LXC seems to behave as Docker in a VM.)
To fix this, it’s needed to add a hostname entry for each swarm service, to make it more logical I also add a prefix service to the service names.
services:
service_nginx: # Prefix service_
image: nginx
hostname: nginx
- Proxmox Forum Topic about this subject.
Portainer & portainer agent were both installed using the same stack file you pointed to, just changed the /data volume to a bind mount aimed at the proper directory on the shared cephfs mount.
Frustrating thing is that I know this worked in the recent past. I've had this setup running for a while -- docker swarm in privileged lxc with a cephfs mount for persistent container data. Portainer was happily chugging along for the better part of a year, with dozens of host restarts and service relocations just working as expected. At some point in the last 6 weeks I noticed the portainer service failing (not 100% certain when it stopped working, as my attention has been elsewhere, and hadn't actually tried to log on to the portainer interface for a while). Seems entirely unrelated to the docker or portainer versions (I've tried multiple versions of docker and portainer recently, trying to get it to work as expected).
I also tried removing the mount point from the LXC and installing the ceph client inside the container and mounting via fstab. Same behavior.
Gave up hope this morning. Since I already have an NFS server exporting a couple of the cephfs directories, I just used that -- mounted the same directory via NFS on the docker hosts. Portainer now behaves as expected -- service is able to move to any host w/out complaint.
But yeah -- the added (admittedly minor) complexity of using NFS mounts inside the docker containers instead of a cephfs mount on the LXC makes my eye twitch a bit.