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
To make a port available to services outside of Docker, or to Docker containers which are not connected to the container's network, use the --publish or -p flag. This creates a firewall rule which maps a container port to a port on the Docker host to the outside world.
To publish a port for our container, we'll use the --publish flag ( -p for short) on the docker run command. The format of the --publish command is [host port]:[container port] . So, if we wanted to expose port 8000 inside the container to port 8080 outside the container, we would pass 8080:8000 to the --publish flag.
If I understand well, for development, you'd want localhost to resolve to a specific container, including when it's called from another container.
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.
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
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"
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
.
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)
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With