mviereck / x11docker

Run GUI applications and desktops in docker and podman containers. Focus on security.
MIT License
5.62k stars 378 forks source link

Issue when getting Hostip on Linux #182

Closed ko-pp closed 5 years ago

ko-pp commented 5 years ago

Running last version from master on Funtoo GNU/Linux with sway.

(TL;DR: see proposed patch at the end)

When trying to run jess/spotify with pulseaudio, I could not launch it twice without a reboot (as in, launch, quit, re-launch). x11docker simply stopped without any error and without opening any window. The problem was the same with other images using pulseaudio. The order did not matter: once one was launched, no other would work (either at the time or after stopping the first).

After taking a look at the logs in --verbose, I found variations of:

/x11docker/container.CMD.sh: 115: export: 169.254.207.216:33615: bad variable name

Looking at container.CMD.sh, we can see

   114  export 'PULSE_SERVER=tcp:172.17.0.1'
   115  export '169.254.207.216:33615'

It seems that store_runoption dump env (L4541-4548) gives some bad variable… Let’s see how PULSE_SERVER is set then: the function setup_sound_pulseaudio (L1511); we are in the tcp case so we want to check what is used on L1570.

Using a warning (let us remove --verbose), I could see that Hostip contained two lines with an IP on each (172.17.0.1 and 169.254.207.216, see above), definitely not what we want. How is it set?

Being on Linux, it’s either on L5808 or 5809; the first command, run directly in a term, does return 172.17.0.1… and only 172.17.0.1 (the second returns my ip on the LAN but is not executed by the script since we don’t enter the OR clause)

So… I "fixed" my issue by appending | head -n1 to the command on L5808 (as is done on the next line) but I don’t know why there are more IPs when running x11docker nor if it is the best way to fix it (although it does work: I have been listening to music from jess/spotify the whole time I have been writing here)

Here is the diff:

diff --git a/x11docker b/x11docker
index d21bfcd..b0b6270 100755
--- a/x11docker
+++ b/x11docker
@@ -5805,7 +5805,7 @@ check_host() {                  # check host environment

   # Check host IP. Needed for --pulseaudio=tcp and --xwin
   case $Winsubsystem in
-    "") Hostip="$(ip -4 -o a | grep 'docker0' | awk '{print $4}' | cut -d/ -f1)"
+    "") Hostip="$(ip -4 -o a | grep 'docker0' | awk '{print $4}' | cut -d/ -f1 | head -n1)"
       [ "$Hostip" ] || Hostip="$(ip -4 -o a | awk '{print $4}' | cut -d/ -f1 | grep -v 127.0.0.1 | head -n1)" ;;
     *) Hostip="$(ipconfig.exe | rmcr | grep -A6 'DockerNAT' | grep 'IPv4' | rev | cut -d' ' -f1 | rev)"
       [ "$Hostip" ] || Hostip="$(ipconfig.exe | rmcr | grep 'IPv4' | grep -o '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | grep "^10\.0\.*" )"

If you want, I can make a PR (or you can apply the patch yourself, as you prefer). But if you think this need more work, I can try to figure out why I have a different result in the script and in a term and how to select the correct IP (but it’s getting late here so it will wait a bit)

Also, on L5812, you have two pipes without anything in-between (head -n1 | | rev), it does not work on bash on my (Linux) computer and I assume it should not work on a windows’ version of bash either.

In any case, thank you for this nice piece of software :smile_cat:

mviereck commented 5 years ago

Thank you for the report and this detailed track-down to the underlying issue!

I've applied your suggestion with | head -n1. However, I am still curious why you get a 2-line-result in x11docker, but not in terminal with ip -4 -o a | grep 'docker0' | awk '{print $4}' | cut -d/ -f1. It would be quite interesting to know why there is a difference. Unless we know the reason, | head -n1 is just a hotfix without knowing what is going on.

Could you compare the output of ip -4 -o a | grep docker0 in terminal with the output of the same command in a short script?

#! /bin/bash
ip -4 -o a | grep docker0

Also, on L5812, you have two pipes without anything in-between (head -n1 | | rev), it does not work on bash on my (Linux) computer and I assume it should not work on a windows’ version of bash either.

Good catch! Is fixed, too.

ko-pp commented 5 years ago

However, I am still curious why you get a 2-line-result in x11docker, but not in terminal

Me too and, strangely, I do see two IPs know… maybe I tried, yesterday, while docker was doing something with the network (I was doing my tests while waiting for docker-compose up --build to finish in another term)

What I am seeing know is

4: docker0    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0\       valid_lft forever preferred_lft forever
4: docker0    inet 169.254.174.153/16 brd 169.254.255.255 scope global noprefixroute docker0\       valid_lft forever preferred_lft forever

I tried replacing head with tail and I still have working sound, so the selected IP doesn’t seem to matter that much with my set-up. I haven’t played that much with Docker yet, I do not know if there are cases where IPs from docker0 will not be accessible from the container.

Perhaps, the full list of IPs could be sent to container.CMD.sh and the first to answer to a ping -c 1 selected from inside the container? Although that would probably complicate the debug a bit since the selected IP would not be displayed when printing container.CMD.sh. (Maybe use another script that select the IP then update container.CMD.sh before it is displayed? Not sure it would be trivial, I haven’t read all of x11docker, only used a lot of ^F)

mviereck commented 5 years ago

Thanks for the test! Good to know that there can be more than one docker0 IP.

I've always seen 172.17.0.1 on Linux. That seems to be stable for the docker daemon. The additional IP address you get along with docker-compose might disappear if you stop the docker-compose setup. I am not sure. If an IP gets invalid while x11docker uses it, the setup would fail. In your case the pulseaudio sound would stop.

I slightly changed the IP check to prefer 172.17.0.1 if available:


                       Hostip="$(ip -4 -o a | grep 'docker0' | awk '{print $4}' | cut -d/ -f1 | grep 172.17.0.1)"
      [ "$Hostip" ] || Hostip="$(ip -4 -o a | grep 'docker0' | awk '{print $4}' | cut -d/ -f1 | head -n1)"
      [ "$Hostip" ] || Hostip="$(ip -4 -o a |                  awk '{print $4}' | cut -d/ -f1 | grep -v 127.0.0.1 | head -n1)" 

Perhaps, the full list of IPs could be sent to container.CMD.sh and the first to answer to a ping -c 1 selected from inside the container?

Some sort of additional check might make sense. Basically x11docker just needs one reliable IP from host; it doesn't matter which one, it should just not disappear while in use. So far x11docker relied on docker0. A possible check could somehow use the container IP after startup. I'll think about it. However, for some other setups, e.g. X over IP, x11docker needs a reliable host IP since startup.

ko-pp commented 5 years ago

The additional IP address you get along with docker-compose might disappear if you stop the docker-compose setup. I am not sure.

It does not seem to be the case. Oddly, I only have 172.17.0.1 for docker0 on my server (also a Funtoo and also using docker-compose), I have no idea why I have a second one on this computer…

172.17.0.1 does seem to be the normal value when not customized in daemon.json (I do not have one so 169.254.174.153 does not come from there) so it’s probably a safe bet to use it whenever possible.

You could also use something like docker network inspect bridge | grep -i "gateway" | awk '{print $2}' | tr -d \" (172.17.0.1 here) and even replace bridge by a variable to allow the user to specify which docker network to use

mviereck commented 5 years ago

You could also use something like docker network inspect bridge | grep -i "gateway" | awk '{print $2}' | tr -d \" (172.17.0.1 here) and even replace bridge by a variable to allow the user to specify which docker network to use

That is a good idea in general. But docker inspect needs root permissions or membership of group docker. x11docker asks for a possibly needed password after all other setup is done to avoid a dependency of group docker. Checking late for the IP and adjusting the setup at this point needs more code change than I believe to make sense yet.

I think the current solution will almost always work; after all, the IP is needed for some special setups and fallbacks only. If over time it turns out that the current solution is not enough, I'll think again about this.

Thank you!