Can't access jupyterhub in a docker container with netowrk_mode: host - docker

I have a jupyterhub running in a container with network_mode: host due to some requirement.
However after setting the network_mode to host in my docker-compose file, I can't access jupyterhub from an external host using the host ip:8000.
my understanding from this is
If you use the host network mode for a container, that container’s
network stack is not isolated from the Docker host (the container
shares the host’s networking namespace), and the container does not
get its own IP-address allocated. For instance, if you run a container
which binds to port 80 and you use host networking, the container’s
application is available on port 80 on the host’s IP address.
Is there anything i am missing?
EDIT:
To simplify i follow the instructions here
docker run --rm -d --network host --name my_nginx nginx
I can access the nginx welcome page doing
$ curl localhost:80
but if i try to curl from another host i get
$ curl 10.230.0.123:80
curl: (7) Failed connect to 10.230.0.123:80; No route to host

This issue can happen when on your system firewall is active and is blocking the port access. You can enable port access using below:
# in centos7, by updating iptables rules
iptables -I INPUT 5 -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
# in ubuntu
sudo ufw allow 80/tcp

Related

Unable to access jenkins on port 8080 when running docker network host

I have a Jenkins running in a docker container in Linux ec2 instance. I am running testcontainers within it and I want to expose all ports to the host. For that I am using network host.
When I run the jenkins container with -p 8080:8080 everything works fine and I am able to access jenkins on {ec2-ip}:8080
docker run id -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts
however, If I want to run the same image using --network=host as I want to expose all ports to the host
docker run id --network=host jenkins/jenkins:lts
{ec2-ip}:8080 becomes unreachable. I can curl to it locally within the container localhost:8080 but accessing jenkins from the browser doesn't work.
I am not sure how network host would change the way I access jenkins on port 8080. the application should be still available on port 8080 on the host IP address?
Check if you are enabling the port 8080 in the security group for the instance.
When a Docker container is running in the host network mode using the --network=host option, it shares the network stack with the Docker host. This means that the container is not isolated and uses the same network interface as the host.
In your case, you should be able to access the Jenkins from the browser with ec2-ip:8080
I tested it by running Jenkins with the following command:
docker run -id --name jenkins --network=host jenkins/jenkins:lts
if the issue still persists, you can check the following:
make sure the container is running
make sure that there is no other process is running on port 8080
make sure that you enabled the port 8080 for your ec2
AFAIU --network doesn't do what you expect it to do. --network flag allows you to connect the container to a network. For example, when you do --nerwork=host your container will be able to use the Docker host network stack. Not the other way around. Take a look at the official documentation.
Figured it out. needed to update iptables to allow port 8080 on network host.
sudo iptables -D INPUT -i eth0 -p tcp -m tcp --dport 8080 -m comment --comment "# jenkins #" -j ACCEPT

Docker containers in user defined docker network - access only from the host

I have an application that is creating a few containers in a user-defined docker network.
Currently I have forwarded (mapped) few ports from some of the containers in that network to the host machine so that I can access them from the host. The interaction between the containers (container to container) is happening via aliases that are defined in the network.
Unfortunately the map ports to the host are publicly exposed on my host machine. Is there a way that these mapped ports can be accessible only from the localhost of my host machine?
If you are using docker run -p [port-number]:[port-number] to forward your ports, you can use:
docker run -p 127.0.0.1:80:80 container
instead of:
docker run -p 80:80 container
By default, Docker exposes your ports on all available interfaces.
If you are on linux you can use iptables for that.
iptables -A INPUT -p tcp -s localhost --dport 8080 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROP
Just change 8080 for the port you want and run it multiple times for each port you are exposing.
First command is "anything coming from localhost to port 8080 allow it" and second is "drop anything coming into port 8080"
This change is not permanent it will reset after you reboot, but you can save it with:
iptables-save > /etc/iptables.conf
And restore it with:
iptables-restore < /etc/iptables.conf

How can I redirect a single port in a docker container to the container's host?

To make development easier for a project, I've put a couple of services it depends on in docker containers. This makes 'localhost' in the project's config mean something different when it is passed to one of the containers.
edit
To be clear, I'm trying to forward one of the container's ports to the host so when a process running in the container tries to access localhost:5432, it connects to the host's port 5432.
endedit
I'm currently using
HOST_IP=`ip route | grep default | awk '{ printf "%s",$3 }'`
cat /etc/hosts | sed "s/127.0.0.1/$HOST_IP/" > /tmp/etc_hosts
cp /tmp/etc_hosts /etc/hosts
to redirect anything targeting 'localhost' to the container's host. It works in this situation, but I'd prefer to find a way to do this only for the needed port as I expect it won't work in other situations.
Here's what I came up with to do that, but it's not working; when a connection in the container is to localhost:5432, it tries to connect to the container's 5432 instead of the host's:
# --- These are the things that should make redirecting port 5432 to the host machine
# work, provided the container is run in privileged mode.
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.route_localnet=1
iptables -t nat -A PREROUTING -p tcp --dport 5432 -j DNAT --to 172.19.0.1:5432
iptables -A FORWARD -d 172.19.0.1 -p tcp --dport 5432 -j ACCEPT
iptables -t nat -A POSTROUTING -j MASQUERADE
If I understand well, for development, you'd want localhost to resolve to a specific container, including when it's called from another container.
Host forwarding
Rewriting your hosts file is, as you mentioned it, not a good idea, since many services can experiment issues if you design localhost as being something different than, well... your local host.
But you can consider a few solutions.
Docker Toolbox
If running docker with Docker Toolbox, or by yourself on a virtual machine with Virtual Box, the intermediate virtual machine is visible, so localhost will represent it. You'll have to run the container, exposing this port, and then to set up a port forwarding in Virtualbox. If I use Wordpress as an example:
docker run -p 80:80 --name website -d wordpress
Virtual Box -> your docker VM (usually called default) -> Network -> Adapter 1 -> port forwarding -> create a mapping from host 8080 to guest 80
It will make Wordpress available at http://localhost:8080. Please note that under MacOS, the kernel restrains non-privileged port forwarding (ports under 1024).
This port forwarding can be created in command line, if you want to put it in a script:
VBoxManage modifyvm "default" --natpf1 "app,tcp,,8080,,80"
Docker for Windows/Docker for Mac
If running docker through Docker for Windows/Docker for Mac (or directly under Linux), rather than Docker Toolbox, you can run the container using the -p parameter, as specified by Scott's post, and your service will be available on localhost at this port (because the intermediate virtual machine is transparent, or no VM under Linux):
docker run -p 5432:5432 --name myapp -d myimage will make myapp available at localhost:5432.
socat (or iptables)
You can run socat on your host this way to forward communication on a specific port to your container:
socat TCP-LISTEN:5432,fork,reuseaddr,user=node,group=node,mode=777 TCP:172.19.0.1:5432 &
(where 172.19.0.1 is your container IP)
Container forwarding
--network
Your containers have their own hosts file, that you can see by issuing such a command:
docker run ubuntu cat /etc/hosts
You can add entries to hosts with the --add-host parameter:
docker run --add-host domain:1.2.3.4 --add-host domain2:5.6.7.8 ubuntu cat /etc/hosts
However this solution will be useless for localhost, because it won't remove the previous localhost associations. What you're looking for (and what is cleaner) is the parameter --network=host which allows the container to share the network interfaces of the host:
docker run --network=host ubuntu
This way, your container will be able to call the other containers services on localhost using their port.
The right way
Of course, the right way to achieve what you want would be to link your containers together and use their link names rather than localhost.
docker run -d --name mariadb -e MYSQL_ROOT_PASSWORD=password mariadb
docker run -d --name="wordpress" -p 8080:80 -e WORDPRESS_DB_PASSWORD=password --link mariadb:mysql wordpress
In this case, the Wordpress container will have a mysql entry in its hosts file, pointing to the mariadb container IP address. To see it, open a bash session in the Wordpress container and see by yourself.
docker exec -ti wordpress bash
#cat /etc/hosts
Show us how you are launching your container
port mapping can happen in your docker run command : -p hostport:containerport
as in
docker run -p 5432:5432 --name mycontainer -d myimage

docker networking direct access to container

I try to migrate from multiple VM with static ip to container based solution.
Now I'm using VM with static ip:
I can ping and telnet my VMs telnet 10.48.0.10 5432 and telnet 10.48.0.11 5432
I want to create a single docker host that allows me to do the same :
It would be great if I can telnet 172.17.0.2 5432 and telnet 172.17.0.3 5432
I try to do it via docker because I want to manage the configuration.
What would be the proper way to do this ?
Should I use a TCP Proxy inside a container to manage this ?
The solution is pretty simple.
create a network and bind it to the host
docker network create --subnet=10.0.0.0/24 -o "com.docker.network.bridge.host_binding_ipv4"="0.0.0.0" mynet
then run a container on mynet network
docker run -ti --net=mynet --ip=10.0.0.30 busybox
Now from another computer if you add route to your docker host (192.168.2.156) for this subnet :
sudo route add -net 10.0.0.0 netmask 255.255.255.0 gw 192.168.2.156
You can ping your container (ping 10.0.0.30)
If you want to access the containers from your host or from any other server that can get your host, you will need to map each container to a different port in the host server.
docker run -d -p 54321:5432 my_app
docker run -d -p 54322:5432 my_app
So you will can telnet 10.200.0.1 54321 and telnet 10.200.0.1 54322

Docker container port unreachable after Docker host static ip changed

Host uses CentOS static ip,
Container use Debian system bridge network and map with 80,9101 port to host.
After change host static ip with eth0, the container port cannot be reached remotely, even if recreated. Call from host is ok.
I have to reboot host machine.
Meanwhile, --net host mode container will not be affected.
First of all if you use --net=host your port mapping is with docker -p is not going to work any more. Because you're exposing your host network to your container.
You can't reach your container port any more because your container's application is actually bound to host IP address upon start up because of --net=host, so when the IP gets changed it's not going to work until you restart your application. Then it starts to work again.
If you want temporary solve this issue, either don't use --net=host or simply create a iptables rule your self to redirect traffic to your app.
If your app listening to port 8080 and you want to expose it as 80 for example, this should work I guess:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 127.0.0.1:8080
Given that your app is listening to localhost as well.

Resources