I am running a basic web application (PHP) inside Docker on a Debian VM, using Docker Compose.
When preforming sudo docker-compose up -d all containers start running just fine.
I have my ports setup as follows: 8007 for the application itself, 8008 for PHPMyAdmin, 9009 for Portainer.
The IP of the Debian VM is 192.168.56.102
When browsing using curl inside the VM to http://192.168.56.102:8007 the page loads without issues.
However, when browsing to the same URL on my Windows 10 host (Chrome) I get a connection timeout.
Pinging to 192.168.56.102 from host to VM and viceversa works fine, and so does SSH.
Does anyone know why I can't browse to these pages, eventhough everything works fine within the VM and the host and VM are clearly able to communicate?
Thanks.
I managed to fix the problem.
As suggested by #larsks some firewall rule inside Debian was blocking the connection. I had already tried /sbin/iptables -F which flushes the firewall rules, which I thought was enough, but it turns out that's not the case.
After running all these commands, the Debian firewall was completly reset and the issue was fixed:
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
Related
When creating docker containers with a docker-compose file which specifies hostname (hostname:) and ip addresses (ipv4_address:), I would like the local computer (the computer that runs the docker daemon service, aka my laptop) to be able to resolve those hostnames, without the need of (too much) manual intervention. I.e. if the container is a webserver service with hostname my_webserver, I would like that my_werbserver resolve to the IP address I assigned to that container.
What's the best way to achieve that? Anything better than maintaining /etc/hosts on my laptop manually?
As #Kārlis Ābele mentioned, I don't think you can do what you need without additional services. One solution would be to run dnsmasq in a docker container in the same network as the other docker containers. See Make the internal DNS server available from the host
docker run -d --name dns -p 53:53 -p 53:53/udp --network docker_network andyshinn/dnsmasq:2.76 -k -d
Check that it works using localhost as DNS
nslookup bar localhost
Optionally setup localhost as DNS server. On Ubutu 18.04 for example, edit /etc/resolvconf/resolv.conf.d/head.
nameserver localhost
Restart the resolvconf service.
sudo service resolvconf restart
Now you should be able to ping the containers by name.
EDITED:
An alternative solution (based on #Kārlis Ābele answer) is to listen to docker events and update /etc/hosts. A barebones implementation:
#!/usr/bin/env bash
while IFS= read -r line; do
container_id=$(echo ${line}| sed -En 's/.*create (.*) \(.*$/\1 /p')
container_name=$(echo ${line}| sed -En 's/.*name=(.*)\)$/\1 /p')
ip_addr=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${container_id})
echo ${ip_addr} ${container_name} >> /etc/hosts
done < <(docker events --filter 'event=create')
Well it seems like something that won't be possible without some custom service that is listening for events on Docker daemon...
How I would do this, is write a simple service that is listening for Docker events (https://docs.docker.com/engine/reference/commandline/events/) and updates /etc/hosts file accordingly.
Other than that, without manually updating hosts file I don't think there are other options though.
Hey i'm quite new to these docker stuff. I tried to start an docker container with bitbucket, but i get this output.
root#rv1175:~# docker run -v bitbucketVolume:/var/atlassian/application-data/bitbucket --name="bitbucket" -d -p 7990:7990 -p 7999:7999 atlassian/bitbucket-server
6da32052deeba204d5d08518c93e887ac9cc27ac10ffca60fa20581ff45f9959
docker: Error response from daemon: driver failed programming external connectivity on endpoint bitbucket (55d12e0e4d76ad7b7e8ae59d5275f6ee85c8690d9f803ec65fdc77a935a25110): (iptables failed: iptables --wait -t filter -A DOCKER ! -i docker0 -o docker0 -p tcp -d 172.17.0.2 --dport 7999 -j ACCEPT: iptables: No chain/target/match by that name.
(exit status 1)).
root#rv1175:~#
I got the same output every time i tried to activate any docker
container. Can someone help me?
P.S. one more question.
What does 172.1.0.2 mean? I can only say, that this is not my ip.
172.17.0.2 would be the IP assigned to the container within the default Docker bridge network (docker0 virtual interface). These are not reachable from the outside, though you are instructing the Docker engine to "publish" (in Docker terminology) two ports.
To do so, the engine creates port forwarding rules with iptables, which forward (in your case) all incoming traffic to ports tcp/7990 and tcp/7999 on all interfaces of the host to the same ports at 172.17.0.2 on the docker0 interface (where the process in the container is hopefully listening).
It looks like the DOCKER iptables chain where this happens is not present. Maybe you have other tools manipulating iptables that might be erasing what the Docker engine is doing. Try to identify them and restart the Docker engine (it should re-create everything on startup).
You can also instruct the engine not to manipulate iptables by configuring the Docker daemon appropriately. You would then need to set things up yourself if you want to use the network bridge driver (though you could also use the host driver). Here is a good example of doing so.
The main goal is to do a real NAT instead of NAPT. Note normal docker run -p ip:port2:port1 command actally is doing NAPT (address+port translation) instead of NAT(address translation). Is it possible to map address only, but keep all exposed ports the same as the container, like docker run -p=ip1:*:* ... , instead of one by one or a range?
ps.1. My port range is rather big (22-50070, ssh-hdfs) so port range approach won't work.
ps.2. Maybe I need a swarm of virtual machines and join the host into the swarm.
ps.3 I raised an feature request on github. Not sure if they will accept it but currently there are 2000+ open issues (it's so popular).
Solution
On linux, you can access any container by ip and port without any binding (no -p) ootb. Docker version: CE 17+
If your host is windows, and docker is running on a linux VM like me, to access the containers, the only thing need to do is adding the route on windows route add -p 172.16.0.0 mask 255.240.0.0 ip_of_your_vm. Now you can access all containers by IP:port without any port mapping from both windows host and linux VM.
There are few options you have. One is to decide which PORT range you want to map then use that in your docker run
docker run -p 192.168.33.101:80-200:80-200 <your image>
Above will map all ports from 80 to 200 on your container. Assuming your idle IP is 192.168.33.100. But unfortunately it is not possible to map a larger port range as docker creates multiple iptables forks to setup the tables and bombs the memory. It would raise an error like below
docker: Error response from daemon: driver failed programming external connectivity on endpoint zen_goodall (0ae6cec360831b46fe3668d6aad9f5f72b6dac5d26cc6c817452d1402d12f02c): (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8513 -j DNAT --to-destination 172.17.0.3:8513 ! -i docker0: (fork/exec /sbin/iptables: resource temporarily unavailable)).
This is not right way of docker mapping it. But this is not a use case that they would agree to, so may not fix the above issue. Next option is to run your docker container without any port publishing and use below iptables rules
DOCKER_IP=172.17.0.2
ACTION=A
IP=192.168.33.101
sudo iptables -t nat -$ACTION DOCKER -d $IP -j DNAT --to-destination $DOCKER_IP ! -i docker0
sudo iptables -t filter -$ACTION DOCKER ! -i docker0 -o docker0 -p tcp -d $DOCKER_IP -j ACCEPT
sudo iptables -t nat -$ACTION POSTROUTING -p tcp -s $DOCKER_IP -d $DOCKER_IP -j MASQUERADE
ACTION=A will add the rules and ACTION=D will delete the rules. This would setup complete traffic from your IP to the DOCKER_IP. This only good if you are doing it on a testing server. Not recommended on staging or production. Docker adds a lot more rules to prevent other containers poking into your container but this offers no protection whatsoever
I dont think there is a direct way to do what you are asking.
If you use "-P" option with "docker run", all ports that are exposed using "EXPOSE" in Dockerfile will automatically get exposed with random ports in the host. With "-p" option, the only way is to specify the option multiple times for multiple ports.
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
I am running into an issue with Google Container Engine where I am unable to add capabilities to the running of my Docker container.
I need to be able to alter the iptables so that I can forward traffic through my Docker VPN container.
The docker container runs fine when I am able to pass --cap-add=NET_ADMIN into the run command, but since GCE is (seemingly) only able to run images this does not seem possible. I get an insufficient permissions error when running my docker image and so it fails to deploy.
Is there anyway around this so I can alter theiptables? Or does GCE just not have this ability?
I have checked out this issue. Which references building an image with privileges but it doesn't seem to be close to resolved.
My iptables commands for reference:
iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE
There was a pull request filed yesterday to add this feature to Kubernetes. Once it has been added to Kubernetes you should be able to test it by building from head and deploying your cluster to GCE.
This feature will show up in Google Container Engine shortly after the next release of Kubernetes.