Dockerfile services question?

Does anyone know what the following output means?

saneuser@e3d5c83d3c5d:/xsane$ systemctl list-unit-files --type service -all
UNIT FILE                              STATE   
apt-daily-upgrade.service              static 
........
saned.service                          masked  
saned@.service                         indirect
.........

I am inside a docker container, running Debian buster
I want to know is saned running, or what do I need to do to get it running.

It would seem it is not running from this

saneuser@e3d5c83d3c5d:/xsane$ ps ax | grep saned
   12 pts/0    S+     0:00 grep saned

I have the following installed

saneuser@e3d5c83d3c5d:/xsane$ dpkg -l | grep sane
ii  libsane:amd64                 1.0.27-3.2                   amd64        API library for scanners
ii  libsane-common                1.0.27-3.2                   all          API library for scanners -- documentation and support files
ii  libsane-dev:amd64             1.0.27-3.2                   amd64        API development library for scanners [development files]
ii  libsane-hpaio:amd64           3.18.12+dfsg0-2              amd64        HP SANE backend for multi-function peripherals
ii  sane-utils                    1.0.27-3.2                   amd64        API library for scanners -- utilities
ii  xsane                         0.999-6+b1                   amd64        featureful graphical frontend for SANE (Scanner Access Now Easy)
ii  xsane-common                  0.999-6                      all          xsane architecture independent files

Normally in Debian, if I install xsane the daemon would be started?
Why not in the container?

I feel that maybe saned is still under sysVinit rather than systemd.
In /etc/init.d there is

saneuser@e3d5c83d3c5d:/etc/init.d$ ls
avahi-daemon  cups-browsed  hwclock.sh  saned  x11-common
cups          dbus          procps      udev

and there is a link in /etc/rc6.d

saneuser@e3d5c83d3c5d:/etc$ ls -l rc6.d
total 0
lrwxrwxrwx 1 root root 22 Jan  8 16:01 K01avahi-daemon -> ../init.d/avahi-daemon
lrwxrwxrwx 1 root root 22 Jan  8 16:01 K01cups-browsed -> ../init.d/cups-browsed
lrwxrwxrwx 1 root root 20 Dec 18 11:00 K01hwclock.sh -> ../init.d/hwclock.sh
lrwxrwxrwx 1 root root 15 Jan  8 15:59 K01saned -> ../init.d/saned
lrwxrwxrwx 1 root root 14 Jan  8 15:59 K01udev -> ../init.d/udev

So does that mean saned is being started by sysVinit?
If so, why is it not running?

I think it is sysVinit , because I get this

saneuser@e3d5c83d3c5d:~$ systemctl start saned
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

OK so lets try and start it with sysVinit

saneuser@e3d5c83d3c5d:~$ service saned start
[....] Starting SANE network scanner server: sanedsaned[38]: saned (AF-indep+IPv6) from sane-backends 1.0.27 starting up

saned[38]: do_bindings: [0] bind failed: Address already in use

saned[39]: Now daemonized

saned[39]: Could not write PID file: Permission denied

saned[40]: saned_avahi: failed to create client: Daemon not running

. ok 

There are some problems because I am not root in the container, but it seemed to something

saneuser@e3d5c83d3c5d:~$ ps ax | grep sane
   39 ?        Ss     0:00 /usr/sbin/saned -a saned
   59 pts/0    S+     0:00 grep sane
``

Lets see if it helps.... I am trying to drive the scanner

saneuser@e3d5c83d3c5d:~$ scanimage -L
dbus[60]: arguments to dbus_connection_send() were incorrect, assertion “connection != NULL” failed in file …/…/…/dbus/dbus-connection.c line 3316.
This is normally a bug in some application using the D-Bus library.

D-Bus not built with -rdynamic so unable to print a backtrace
Aborted

That is more than scanimage normally says 
Here is the normal response when it cant connect

$ scanimage -L

No scanners were identified. If you were expecting something different,
check that the scanner is plugged in, turned on and detected by the
sane-find-scanner tool (if appropriate). Please read the documentation
which came with this software (README, FAQ, manpages).

So there is progress,  but I think startind saned as a normal user only did half a job. 

So why would Debian in a docker container not use systemd?
The Debian base image I am using is
`FROM debian:buster-slim`
so it is a cut down Debian. 
Maybe they removed systemd?

It would seem there are no daemons at all running

saneuser@e3d5c83d3c5d:/etc$ ps ax
PID TTY STAT TIME COMMAND
1 pts/0 Ss 0:00 /bin/bash
39 ? Ss 0:00 /usr/sbin/saned -a saned
109 pts/0 R+ 0:00 ps ax

Only the saned that I started by hand.

So maybe I learnt something..... docker base images do 
not start any services.
1 Like

I found this

"This is by design. Docker should be running a process in the foreground in your container and it will be spawned as PID 1 within the container’s pid namespace. Docker is designed for process isolation, not for OS virtualization, so there are no other OS processes and daemons running inside the container (like systemd, cron, syslog, etc), only your entrypoint or command you run.

If they included systemd commands, you’d find a lot of things not working since your entrypoint replaces init. Systemd also makes use to cgroups which docker restricts inside of containers since the ability to change cgroups could allow a process to escape the container’s isolation. "

If the entrypoint in a container replaces init, how does one
start a daemon?

It would seem that running the sysV script does not work.
Do I have to do everything as an ENTRYPOINT?

The answer is here

Yes everything you want to stay running has to be in CMD or ENTRYPOINT…

Sorry for the confusion, I am learning on the job.

2 Likes

I was going to suggest that xsane is more of a GUI type of app and there is no GUI in your container. Something along those lines anyway.

I work on Kubernetes clusters all day and am no container expert. We’re all learning as we go.

That part is Ok. I can start the container with gui support.
I had some previous experience with waterfox in a container, so I knew how to do the gui bit.
At the moment xsane starts, and then brings up a popup saying it can not find a device.
I think the issue is, saned is not running… so I got into a tangle trying to start services in a container.

I learnt something important… a container normally only
runs one process, and it is PID#1 so it takes the place of init in a normal linux.

If I need to run more than one process (ie xsane plus some daemons) i read that the easiest way to do it is to put
the service starts and xsane into a shell script, load the script
into the container at build time, then use
CMD /initscript.sh
in the dockerfile.
The the script becomes PID#1 and it will run the service starts and xsane as child processes.
About to try that… untested at moment

You can enjoy your clusters. I like the low level stuff, so I get to know how it works.

1 Like

I forgot about that. Should come in handy.

1 Like

I tried it.
Here is the script

$ cat scaninit.sh
#!/bin/sh
# CMD for xsane Dockerfile
/etc/init.d/saned start
/usr/bin/xsane

and the end of the Dockerfile

....
ENV TZ=Australia/Sydney
# exec scaninit.sh
CMD sh -ex /xsane/scaninit.sh

I build the container, then run it,
Get an error

$ docker run -i -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -h $HOSTNAME -v $HOME/.Xauthority:/home/nevj/.Xauthority --device=/dev/dri/card0 myxsane:v2
+ /etc/init.d/saned start
Starting SANE network scanner server: saned.
+ /usr/bin/xsane
dbus[14]: arguments to dbus_connection_send() were incorrect, assertion "connection != NULL" failed in file ../../../dbus/dbus-connection.c line 3316.
This is normally a bug in some application using the D-Bus library.

  D-Bus not built with -rdynamic so unable to print a backtrace
Aborted

So I assume that means saned is trying to talk to dbus , and it fails to talk.

Maybe dbus is not even running in the container? I cant see it when I go into the container interactively and do ps ax ??

If you don’t see it using ps then I guess it’s not running.

Did you start with a different base than when you were playing with waterfox? Was dbus running there?

1 Like

Same base. Waterfox did not need any services. It needed lots of libraries.

I guess I will try starting dbus. That requires root permission… how do I get root permission inside a container?

If you don’t see it using ps then I guess it’s not running.

How can I get a message from dbus[14]: if it is not running?

I think saned must be trying to communicate with another daemon ( maybe avahi), and is using dbus to do it.

Best practice is to not have root permissions inside a container. Many times, with Docker you do. I usually use Podman. It’s daemonless and non-root by default.

In your Dockerfile I think the default is to run as root unless you say otherwise, but I could be wrong. You can specifically run as root in the Dockerfile and then it should stay running as root unless you switch to another user.

The Bingbot says:

To run a Dockerfile as root, you can use the USER instruction in your Dockerfile to specify the user inside the container that will start the process inside the container. By default, the USER instruction is set to root. Here is an example of how to use the USER instruction in a Dockerfile:

FROM debian:stretch
USER root
CMD ["echo", "hello"]

This Dockerfile will run the echo command as the root user inside the container. If you want to execute a command using the root user inside the Docker container, you can use the -u option with the docker exec command. For example, to execute a command using the root user inside the Docker container, you can use the following command:

$ docker exec -it -u 0 <container_name> bash

Here, the -u option is used to define the ID of the root user inside the container ¹²³⁴.

Source: Conversation with Bing, 1/9/2024
(1) dockerfile - Run docker as root verus non-root - Stack Overflow. dockerfile - Run docker as root verus non-root - Stack Overflow.
(2) Root User and Password Inside a Docker Container - Baeldung. https://www.baeldung.com/ops/root-user-password-docker-container.
(3) Docker Tip #91: Exec into a Container as Root without Sudo or a … Docker Tip #91: Exec into a Container as Root without Sudo or a Password — Nick Janetakis.
(4) Running Docker Containers as ROOT: | dockerlabs. Running Docker Containers as ROOT: | dockerlabs.
(5) Dockerfile reference | Docker Docs. Dockerfile reference | Docker Docs.

That is right. You have to be root to build a container.
but
when you run the container, the user is whoever USER is set to.
That is usually fine, but to start some daemons you need to be root or at least have root permissions.
Maybe I can get away with putting the USER in the root group?
Not good security, but it may at least work.
What I really need is something like sudo, but without a password, just to start a service, then revert to normal user.

This quest has taken a new turn.
I have discovered that saned does not need to be running to access a networked scanner.
In both my distros in which xsane can access my scanner, I can stop saned and xsane still finds the scanner.
It would seem saned is only needed if one has a usb or sata scanner attached directly to a computer, and one wishes to access the scanner from another computer… a bit like a shared printer.

Now, apart from admitting my stupid mistake, what do I need to do to make xsane work in a docker container?
My next best guess is , there are some missing dynamic
libraries ( .so files).
I can get a list of all the .so files used by xsane as follows

ldd /pathto/xsane

It lists more than 100 .so files.
Wow… so I have to cross check that against a list of all the
lib*.so files present in my container.
That should keep me out of trouble for a few days.
Will report progress.

1 Like

Hi Neville,
I don’t have the knowledge to help you and I don’t understand the problem you’re trying to solve, so don’t reply to my post if what I write doesn’t make sense.

As I understand it, you have xsane inside a container and you want to access the scanner.
The container is isolated and the scanner must be on another IP, which must be that of your external network.
Don’t you have to create any rules in the docker or firewall to give the external network access to the container?

Jorge

2 Likes

Hi Jorge,
The network part of it seems OK.
Setting the container up to drive the hosts gui seems to make it communicate properly with the host.
From inside the container I can ping the scanner because it is on a local network accessible to the Void host system . I have previously run the waterfox browser in a container, and it was able to communicate in both directions.

What I am trying to do is build a container environment in which xsane will work with my scanner.
I am doing this because xsane does not seem to work with my scanner in Debian 12 or any of its derivatives like MX23. It does work with Debian 11 ( or MX21) so I am trying to provide a Debian 11 environment for xsane that I can move around into any distro.

The alternative is to solve the issues xsane has in Debian12 and MX23. @JoelA is helping with that.

Regards
Neville

I found this
" Containers have networking enabled by default, and they can make outgoing connections. A container has no information about what kind of network it’s attached to, or whether their peers are also Docker workloads or not. A container only sees a network interface with an IP address, a gateway, a routing table, DNS services, and other networking details. "

2 Likes

On second thought, that is unlikely… Xsane was installed from a package so it should have all its dependencies installed.

So what else could be wrong?
Maybe xsane needs some other daemon… maybe I still need dbus?
How does one check what services a process requires?

The problem seems to be, I can not run the dbus service inside
a Docker container.

My Dockerfile executes a script

#!/bin/sh
# CMD for xsane Dockerfile
service dbus start
/usr/bin/xsane

ie just 2 lines, start dbus and then run xsane.

I get the following

xhost +
$ docker run -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -h $HOSTNAME -v $HOME/.Xauthority:/home/nevj/.Xauthority --device=/dev/dri/card0 myxsane:v2

+ /usr/bin/xsane
dbus[8]: arguments to dbus_connection_send() were incorrect, assertion "connection != NULL" failed in file ../../../dbus/dbus-connection.c line 3316.
This is normally a bug in some application using the D-Bus library.

  D-Bus not built with -rdynamic so unable to print a backtrace
Aborted

So dbus seems to be present in the container, but not able to communicate properly.

Given that I have now solved my xsane scanner issue another way
Xsane, network scanner, and MX23.1 - #27 by nevj
I think we might put the Xsane-docker-container issue on the shelf.
It is an interesting challenge, but rather time consuming.

Thank you all for responses.

4 Likes

There is PROGRESS !!

After a couple of sessions with ChatGPT, I learnt how to make a container share dbus files and sockets with the host.

That helped , but it was not the full answer.
There was a flaw in my approach… I thought I would have to run dbus inside my container… It is more appropriate to set up the container so that any dbus calls are passed to the host’s dbus.

I made the following Dockerfile

FROM debian:buster-slim
#set working dir inside container
WORKDIR /xsane
# setup scaninit.sh script
COPY ./scaninit.sh /xsane
#
RUN cd /etc/apt && \
# apt debian setup
  cp sources.list sources.list.orig && \
  sed 's/main/main contrib non-free/' sources.list.orig >sources.list && \
  cd /xsane && \
  apt-get update && \
  apt-get upgrade -y && \
  apt-get install -y apt-utils && \
#  apt-get install -y sudo && \
#
# apt install packages for xsane
  apt-get install -y  xsane && \
# apt install packages for xsane libraries
  apt-get install -y libsane-hpaio  && \
  apt-get install -y dbus  && \
  apt-get install -y libusb-0.1-4  && \
#
# apt install brother drivers
  apt-get install -y wget && \
  wget https://github.com/nevillejackson/Unix/blob/main/Brother/\
debbrother/brscan2-0.2.5-1.amd64.deb?raw=true && \
  apt-get install -y dpkg && \
  apt-get install -y  csh && \
  dpkg -i --force-all 'brscan2-0.2.5-1.amd64.deb?raw=true' && \
  brsaneconfig2 -a name=brscan2 model="MFC-640CW" ip=192.168.32.98 && \
  cd /usr/lib64 && \
  cp -r sane /usr/lib && \
  cp libbrcolm* /usr/lib && \
  cp libbrscandec* /usr/lib && \
  ln -sfr /usr/lib64/libscandec* /usr/lib/x86_64-linux-gnu && \
  ln -sfr /usr/lib64/libcolm* /usr/lib/x86_64-linux-gnu && \
  mkdir -p /usr/lib/x86_64-linux-gnu/sane && \
  ln -sfr /usr/lib64/sane/libsane-brother* /usr/lib/x86_64-linux-gnu/sane && \
#
# locale
  apt-get install -y locales locales-all  && \
  rm -rf /var/lib/apt/lists/*
#
# setup environment
RUN useradd --create-home saneuser 
RUN usermod -a -G scanner saneuser
RUN rm -fr /tmp/* /var/tmp/* /var/cache/*/*
RUN mkdir -p /var/run/dbus
USER saneuser
ENV DBUS_SESSION_BUS_ADDRESS="unix:path=/var/run/dbus/system_bus_socket"
# /var/run points to /run in Debian and Void
ENV HOME /home/saneuser
ENV LC_ALL en_AU.UTF-8
ENV LANG en_AU.UTF-8
ENV LANGUAGE en_AU.UTF-8
ENV TZ=Australia/Sydney

CMD /usr/bin/xsane

I used that to build the container, then ran it with

xhost +
docker run --privileged  --net=host -e DBUS_SYSTEM_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket -v /var/run/dbus:/var/run/dbus -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -h $HOSTNAME -v $HOME/.Xauthority:/home/nevj/.Xauthority --device=/dev/dri/card0 myxsane:v2

Yes, that is a mouthful , but what it is doing is telling the container where the dbus socket and files are , in the host, and setting up networking of dbus calls.

When it runs I get the following

So it brings up the xsane menu .
I tried to do scan and it did not work … a popup message about
inappropriate command.
So I tried ‘preview’… and that worked.
Then I tried scan again, and it worked.
Then I quit everything, started the container again… and this time
scan worked first try.

So I can drive the scanner from inside a docker container.
Now all I have to do is work out how to make it save the scanned image back to the host.
Currently if I press save, it attempts to save it inside the container
in /home/saneuser but that fails with a message

(xsane:7): Gtk-WARNING **: 21:25:10.611: Attempting to store changes into `/home/saneuser/.local/share/recently-used.xbel', but failed: Failed to create file “/home/saneuser/.local/share/recently-used.xbel.SS1YH2”: No such file or directory

(xsane:7): Gtk-WARNING **: 21:25:10.611: Attempting to set the permissions of `/home/saneuser/.local/share/recently-used.xbel', but failed: No such file or directory

I think it a missing directory or a permissions issue… but I dont want it saved there anyway.

Who knows how to write from a container, to the host’s filesystem?

2 Likes

I would think you’d just map another volume from local storage to the container storage.

-v /home/nev/scans:/home/saneuser/scans

Or whatever directory you’re talking about. You may have to grant permissions to that local directory for whatever user the container is running as. If it’s you then it should work I’d think.

1 Like

You are right.
I mapped my home directory in the host to the home directory in the container
and
I made the user in the container nevj to avoid any permission issues.
Then when I tell xscan to save the image, it brings up a window showing my host home directory, and I can click save and it saves the image in the host.

Along the way I discovered that defining the dbus socket is unnecessary and installing dbus in the container is unnecessary.
All that is needed is a volume mapping /run/dbus in the container to /run/dbus in the host.

So here is my final, pruned , Dockerfile

 FROM debian:buster-slim
#set working dir inside container
WORKDIR /xsane
#
RUN cd /etc/apt && \
# apt debian setup
  cp sources.list sources.list.orig && \
  sed 's/main/main contrib non-free/' sources.list.orig >sources.list && \
  cd /xsane && \
  apt-get update && \
  apt-get upgrade -y && \
  apt-get install -y apt-utils && \
#  apt-get install -y sudo && \
#
# apt install packages for xsane
  apt-get install -y  xsane && \
# apt install packages for xsane libraries
  apt-get install -y libsane-hpaio  && \
  apt-get install -y libusb-0.1-4  && \
#
# apt install brother drivers
  apt-get install -y wget && \
  wget https://github.com/nevillejackson/Unix/blob/main/Brother/\
debbrother/brscan2-0.2.5-1.amd64.deb?raw=true && \
  apt-get install -y dpkg && \
  apt-get install -y  csh && \
  dpkg -i --force-all 'brscan2-0.2.5-1.amd64.deb?raw=true' && \
  brsaneconfig2 -a name=brscan2 model="MFC-640CW" ip=192.168.32.98 && \
  cd /usr/lib64 && \
  cp -r sane /usr/lib && \
  cp libbrcolm* /usr/lib && \
  cp libbrscandec* /usr/lib && \
  ln -sfr /usr/lib64/libscandec* /usr/lib/x86_64-linux-gnu && \
  ln -sfr /usr/lib64/libcolm* /usr/lib/x86_64-linux-gnu && \
  mkdir -p /usr/lib/x86_64-linux-gnu/sane && \
  ln -sfr /usr/lib64/sane/libsane-brother* /usr/lib/x86_64-linux-gnu/sane && \
#
# locale
  apt-get install -y locales locales-all  && \
  rm -rf /var/lib/apt/lists/*
#
# setup environment
RUN useradd --create-home nevj 
RUN usermod -a -G scanner nevj
RUN rm -fr /tmp/* /var/tmp/* /var/cache/*/*
# /var/run points to /run in Debian and Void
RUN mkdir -p /var/run/dbus
USER nevj
ENV HOME /home/nevj
ENV LC_ALL en_AU.UTF-8
ENV LANG en_AU.UTF-8
ENV LANGUAGE en_AU.UTF-8
ENV TZ=Australia/Sydney
CMD /usr/bin/xsane

and the docker command to run it

docker run  -v /home/nevj:/home/nevj -v /var/run/dbus:/var/run/dbus -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -h $HOSTNAME -v $HOME/.Xauthority:/home/nevj/.Xauthority --device=/dev/dri/card0 myxsane:v2

Not quite mind as boggling as my first successful version.
It has 4 volumes

  • one for dbus
  • one for writing the image
  • two for X11

The final ultimate test will be to move the container to another
OS which does not have xsane working, and test it there.
I dont need to move the container, I can move the Dockerfile, but the host OS will have to have docker and dbus… most have.

2 Likes

That Dockerfile was developed with Void as a host.
I went to my new MX23 install
disabled xsane by removing libusb-0.1.so.4.4.4
Copied the Dockerfile from Void
installed docker.io in MX23
added nevj to docker group
built the container again in MX23

docker build -t myxsane:v2 .

and ran it

docker run  -v /home/nevj:/home/nevj -v /var/run/dbus:/var/run/dbus -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY -h $HOSTNAME -v $HOME/.Xauthority:/home/nevj/.Xauthority --device=/dev/dri/card0 myxsane:v2

It worked.
Xsane will not run in the MX23 host, but it will run in the container.

So I put libusb-0.1.so.4.4.4 back into MX23… it is a lot easier to use xsane natively, than in a container.
I just wanted to prove that the container solution would work, even though it eventually proved to be unnecessary.

Conclusion:
If something will only work in an older version of Linux, you can still run it in a container inside your newer version of Linux.
and
Dont try to run services in a container… just run the app. Use the host’s
services via volume sharing.

4 Likes