Public IP mapping to internal shared virtual ip address in Docker - docker

I am using Docker on OSX and have created a host with a bridged network and a couple of containers that share a virtual IP (so 172.19.0.50 points to 172.19.0.1 and if that container goes down, 172.19.0.50 is pointed at 172.19.0.2 and so on). Other containers within this network can access 172.19.0.50 and see either of the boxes as planned, so great so far.
Where I am confused is quite how to point my public 192.168.99.100 IP such that it goes to 172.19.0.50 rather than a specific container IP.
This is an area I'm not too familiar with so any advice much appreciated.

After some research, it seems to me that there's no "docker solution", for the moment. I have the exact same problem : I have a galera cluster on 3 containers on 1 docker host. Let's say you need to access the port 3306 on your containers, like me.
I manage a virtual IP on those galera nodes, and it works great. But I can't tell Docker to match the port's host (3306 in my case for mysql) to the virtual_ip:3306. The port from your host has to be mapped to a container and port. Not an IP address.
If you run the container that have the virtual ip, with port mapping like this :
docker run -d -p 3306:3306 docker_image /bin/bash
The requests to the public host IP address on 3306 will be redirected to the port 3306 of your container network interface (which have in theory 2 addresses, one static and the virtual one). But if your virtual ip moves to another docker, it won't change anything to your port mapping. The requests from the outside will be redirected to the first container anyway. (and, by the way, you can't map multiple containers to the same docker host's port. Actually, it wouldn't help)
In my opinion, you could use a HAProxy or Nginx reverse proxy in a container : so you can map the 3306's host port to the HAProxy's 3306 port, and HAProxy can redirect your requests to the cluster (with or without loadbalancing). So now you don't even need virtual IP.
BUT, now you have a nice single point of failure. It would be nice to add another reverse proxy as a backup, but then you would need a virtual IP for the failover, and you would be stuck with the problem of the beginning.
If somebody has a better solution to this...

Related

docker swarm causing problems with iptables

I'm having an issue with docker swarm with it modifying iptables when i need control over the ports. I am trying to use UFW to make my own rules.
My setup has an nginx proxy that routes all traffic on designated ports to containers on different nodes to specific ports on a local network interface. So all of the node servers i want to block every single port on the public interface so all traffic has to come via the proxy server.
The problem is docker opens the ports on the public interface, let's say i have a container on 80:80 it opens port 80 on the public interface, when i don't want that server to be directly accessed, it needs to come in via the reverse proxy and down through the private network interface only.
I read with docker compose you can bind the port to the 127.0.0.1 ip address instead of letting docker bind to 0.0.0.0 like this:
"127.0.0.1:80:80"
However this doesn't work with docker swarm yaml config, when i try it gives this error:
error decoding 'Ports': Invalid hostPort: 127.0.0.1
This is causing me a headache, i don't want docker touching my iptables rules at all but i can't find a solid answer on how to stop it.
At the moment i am using OVH firewall directly on the ip addresses, however this isn't an ideal solution as OVH is basic and doesn't allow me to set port ranges which i need to do;

Nginx proxy manager is not being able to serve the page from another docker container

I am trying for nginx proxy manager (running in a docker container) to connect to another docker container that has port 8080 open on it. When I setup the proxy to connect to 192.168.0.29:8080 the ip address of the host, but it doesn't work, the browser just says that the site didn't send any data.
I tried setting up the reverse proxy with other services (that weren't running inside a docker container), and they worked flawlessly. So, I've concluded, the problem is something with the docker containers.
First, I tried replacing the ip address with the address of the container (shown in portainer) which showed to be 172.17.0.2. But, that didn't work. I can confirm that both containers are in the same network, bridge.
I could not find any solutions for this problem either here, at Stack Overflow, or anywhere else. Hope there's enough data to solve this problem. Thanks ahead of time!
Edit:
running arp -na from within the container gives this output:
[root#docker-00244f7ab2cc:/app]# arp -na
? (172.17.0.1) at 02:42:d1:fc:fc:6b [ether] on eth0
I found the solution to my question after lots of searching and testing and it's quite simple. The solution is to start the nginx proxy manager docker container on the host network instead of the bridge network. Then, you can use localhost and then the port to refer to which service you want to redirect to.

Dockerized Telnet over SSH Reverse Tunnel

I know that the title might be confusing so let me explain.
The is my current situation:
Server A - 127.0.0.1
Server B - 1.2.3.4.5
Server B opens a reverse tunnel to Server A. This gives me a random port on Server A to communicate with the Server B. Let's assume the port is 1337.
As I mentioned to access Server B I am sending packets to 127.0.0.1:1337.
Our client needs a Telnet connection. Since Telnet is insecure but a requirement, we decided to use telnet OVER the ssh reverse tunnel.
Moreover, we created an alpine container with busybox inside of it to eliminate any access to the host. And here is our problem.
The tunnel is created on the host, yet the telnet client is inside a docker container. Those are two separate systems.
I can share my host network with the docker with -network=host but it eliminates the encapsulation idea of the docker container.
Also binding the docker to host like that -p 127.0.0.1:1337:1337 screams that the port is already in use and it can't bind to that (duh ssh is using it)
Mapping ports from host to the container are also not working since the telnet client isn't forwarding the traffic to a specific port so we can't just "sniff" it out.
Does anyone have an idea how to overcome this?
I thought about sharing my host network and trying to configure iptables rules to limit the docker functionality over the network but my iptables skills aren't really great.
The port forward does not work, because that is basically the wrong direction. -p 127.0.0.1:1337:1337 means "take everything thats coming in on that host-port, and forward it into the container". But you want to connect from the container to that port on the host.
Thats basically three steps:
The following steps require atleast Docker v20.04
On the host: Bind your tunnel to the docker0 interface on the host (might require that you figure out the ip of that interface first). In other words, referring to your example, ensure that the local side of the tunnel does not end at 127.0.0.1:1337 but <ip of host interface docker0>:1337
On the host: Add --add-host host.docker.internal:host-gateway to your docker run command
Inside your container: telnet to host.docker.internal (magic DNS name) on the port you bound in step 2 (i.e. 1337)

Docker Compose with static public IP over LAN but different with Host IP

I have the requirement where I need to expose all my containers through a static public IP.
However, the static public IP cannot be host IP because host IP must be dynamic.
The 2 solutions I found is macvlan and linux secondary IP, but base on my understanding, they cannot fulfil my need.
with macvlan, each container will get individual IP. I need to access all container through the same IP.
with linux secondary IP, I can assign a single static IP which exclusive for my docker container. However, I didn't found a way to manage the /etc/network/interface inside a docker container.
My question is:
Is it possible to set all container using same ip using macvlan?
Is there any way to manage/etc/network/interface, include ifup and ifdown inside a docker container?
Is there any alternative method
Edit:
the image is the system design for what I wish to achieve:
Assign the static IP to your host and use the ordinary docker run -p option. The host is allowed to have multiple IP addresses (it presumably already has its dynamic IP address and the Docker-internal 172.17.0.1 address) and you can use an additional parameter to docker run -p 10.10.10.10:80:8888 to bind to a specific host address (that specific address and no other, port 80, forwards to port 8888 in the container).
Another good setup is to provision a load balancer of some sort, assign the static IP address to it, and have it forward to the host. This is also helpful if you want to put some level of rate-limiting or basic HTTP filtering at this layer.
There's no specific technical barrier to running ifconfig by hand inside a container, but no off-the-shelf images expects to need to do it, which means you'll need to write all of your own images that won't really be reusable outside this specific environment. A developer might have trouble running the identical image locally, for instance.

Make docker machine available under host name in Windows

I'm trying to make a docker machine available to my Windows by a host name. After creating it like
docker-machine create -d virtualbox mymachine
and setting up a docker container that exposes the port 80, how can I give that docker machine a host name such that I can enter "http://mymachine/" into my browser to load the website? When I change "mymachine" to the actual IP address then it works.
There is an answer to this question but I would like to achieve it without an entry in the hosts file. Is that possible?
You might want to refer to docker documentaion:
https://docs.docker.com/engine/userguide/networking/#exposing-and-publishing-ports
You expose ports using the EXPOSE keyword in the Dockerfile or the
--expose flag to docker run. Exposing ports is a way of documenting which ports are used, but does not actually map or open any ports.
Exposing ports is optional.
You publish ports using the --publish or --publish-all flag to docker
run. This tells Docker which ports to open on the container’s network
interface. When a port is published, it is mapped to an available
high-order port (higher than 30000) on the host machine, unless you
specify the port to map to on the host machine at runtime. You cannot
specify the port to map to on the host machine when you build the
image (in the Dockerfile), because there is no way to guarantee that
the port will be available on the host machine where you run the
image.
I also suggest reviewing the -P flag as it differs from the -p one.
Also i suggest you try "Kitematic" for Windows or Mac, https://kitematic.com/ . It's much simpler (but dont forget to commit after any changes!)
Now concerning the network in your company, it has nothing to do with docker, as long as you're using docker locally on your computer it wont matter what configuration your company set. Even you dont have to change any VM network config in order to expose things to your local host, all comes by default if you're using Vbox ( adapter 1 ==> NAT & adapter 2 ==> host only )
hope this is what you're looking for
If the goal is to keep it as simple as possible for multiple developers, localhost will be your best bet. As long as the ports you're exposing and publishing are available on host, you can just use http://localhost in the browser. If it's a port other than 80/443, just append it like http://localhost:8080.
If you really don't want to go the /etc/hosts or localhost route, you could also purchase a domain and have it route to 127.0.0.1. This article lays out the details a little bit more.
Example:
dave-mbp:~ dave$ traceroute yoogle.com
traceroute to yoogle.com (127.0.0.1), 64 hops max, 52 byte packets
1 localhost (127.0.0.1) 0.742 ms 0.056 ms 0.046 ms
Alternatively, if you don't want to purchase your own domain and all developers are on the same network and you are able to control DHCP/DNS, you can setup your own DNS server to include a private route back to 127.0.0.1. Similar concept to the Public DNS option, but a little more brittle since you might allow your devs to work remote, outside of a controlled network.
Connecting by hostname requires that you go through hostname to IP resolution. That's handled by the hosts file and falls back to DNS. This all happens before you ever touch the docker container, and docker machine itself does not have any external hooks to go out and configure your hosts file or DNS servers.
With newer versions of Docker on windows, you run containers with HyperV and networking automatically maps ports to localhost so you can connect to http://localhost. This won't work with docker-machine since it's spinning up virtualbox VM's without the localhost mapping.
If you don't want to configure your hosts file, DNS, and can't use a newer version of docker, you're left with connecting by IP. What you can do is use a free wildcard DNS service like http://xip.io/ that maps any name you want, along with your IP address, back to that same IP address. This lets you use things like a hostname based reverse proxy to connect to multiple containers inside of docker behind the same port.
One last option is to run your docker host VM with a static IP. Docker-machine doesn't support this directly yet, so you can either rely on luck to keep the same IP from a given range, or use another tool like Vagrant to spin up the docker host VM with a static IP on the laptop. Once you have a static IP, you can modify the host file once, create a DNS entry for every dev, or use the same xip.io URL, to access the containers each time.
If you're on a machine with Multicasting DNS (that's Bonjour on a Mac), then the approach that's worked for me is to fire up an Avahi container in the Docker Machine vbox. This lets me refer to VM services at <docker-machine-vm-name>.local. No editing /etc/hosts, no crazy networking settings.
I use different Virtualbox VMs for different projects for my work, which keeps a nice separation of concerns (prevents port collisions, lets me blow away all the containers and images without affecting my other projects, etc.)
Using docker-compose, I just put an Avahi instance at the top of each project:
version: '2'
services:
avahi:
image: 'enernoclabs/avahi:latest'
network_mode: 'host'
Then if I run a webserver in the VM with a docker container forwarding to port 80, it's just http://machine-name.local in the browser.
You can add a domain name entry in your hosts file :
X.X.X.X mymachine # Replace X.X.X.X by the IP of your docker machine
You could also set up a DNS server on your local network if your app is meant to be reachable from your coworkers at your workplace and if your windows machine is meant to remain up as a server.
that would require to make your VM accessible from local network though, but port forwarding could then be a simple solution if your app is the only webservice running on your windows host. (Note that you could as well set up a linux server to avoid using docker-machine on windows, but you would still have to set up a static IP for this server to ensure that your domain name resolution works).
You could also buy your own domain name (or get a free one) and assign it your docker-machine's IP if you don't have rights to write in your hosts file.
But these solution may not work anymore after some time if app host doesn't have a static IP and if your docker-machine IP changes). Not setting up a static IP doesn't imply it will automatically change though, there should be some persistence if you don't erase the machine to create a new one, but that wouldn't be guaranteed either.
Also note that if you set up a DNS server, you'd have to host it on a device with a static IP as well. Your coworkers would then have to configure their machine to use this one.
I suggest nginx-proxy. This is what I use all the time. It comes in especially handy when you are running different containers that are all supposed to answer to the same port (e.g. multiple web-services).
nginx-proxy runs seperately from your service and listens to docker-events to update it's own configuration. After you spun up your service and query the port nginx-proxy is listening to, you will be redirected to your service. Therefore you either need to start nginx-proxy with the DEFAULT_HOST flag or send the desired host as header param with the request.
As I am running this only with plain docker, I don't know if it works with docker-machine, though.
If you go for this option, you can decide for a certain domain (e.g. .docker) to be completely resolved to localhost. This can be either done company-wide by DNS, locally with hosts file or an intermediate resolver (the specific solution depends on your OS, of course). If you then try to reach http://service1.docker nginx-proxy will route to the container that has then ENV VIRTUAL_HOST=service1.docker. This is really convenient, because it only needs one-time setup and is from then on dynamic.

Resources