How to connect to remote docker instance using virtual private network - docker

I have a docker instance on a host which has two network interfaces, one attached to the internet and one virtual private network.
The host is able to connect to the internet and the VPN.
The docker instance running on the host can connect to the internet, but cannot reach the VPN.
How can I assure my docker instance can connect to the VPN?
I have read explanation about using pipework (https://github.com/jpetazzo/pipework/) but don't see how I can get this to work for me.
I am using docker 0.8.0 on Ubuntu 13.10.
Thanks for the help.

I think that you do not need pipework. In default configuration, you should be able to reach both host interfaces from docker eth0 interface. Possible problems:
DNS: my default container resolv.conf is 8.8.8.8 and it may not know some VPN-specific domain names.
Filtering/firewall at host possibly drops/does not forward packets to VPN. (check firewall f.e ufw status, ...)
You can check IP ranges for possible conflicts in docker networking. In case of conflict, you can configure docker network interface docker0 manually to be ok with your VPN:
/etc/network/interfaces:
auto docker0
iface docker0 inet static
address 192.168.1.1 <--- configure this
netmask 255.255.255.0
bridge_stp off
bridge_fd 0

Related

docker macvlan outside subnet pfsense other subnet

I would like to know how can I make a docker container accessible outside its own network.
example : docker container have a dedicated ip 172.16.0.240 , the mac0 adress is 172.16.0.40 and the host address is 172.16.0.20
I can access 172.16.0.240 from all devices connected on 172.16.0.0/24
now i want to access it from 172.16.50.0/24.
Right now 172.16.50.0/24 has no issue accessing everything on 172.16.0.0/24 except those using the macvlan ip.
Thanks.
Mapping ports to the docker host is my recommendation. macvlan has not been very stable in our tests. There are even concerns in docker networking documentation about it https://docs.docker.com/network/macvlan/
If it is really necessary to use macvlan, then try an inbound NAT port forward on pfsense from the 50 LAN to the 0 LAN. Do this for all the ports you need access to.

Minikube - access host machine's ports

I'm using minikube with hyperkit driver, and I need to access a port opened on the host machine FROM a pod inside the minikube cluster.
There are 2 ways I can accomplish this:
Port forwarding
Port forward of my local port to the minikube ip:
ssh -i $(minikube ssh-key) docker#$(minikube ip) -R 8080:localhost:8080
And then from the pod I can curl 172.17.0.1:8080
source: https://medium.com/tarkalabs/proxying-services-into-minikube-8355db0065fd
Local machine's IP
From my host machine, I get the minikube's bridge IP: ifconfig bridge100
bridge100: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=3<RXCSUM,TXCSUM>
ether 8e:85:90:2d:d5:64
inet 192.168.64.1 netmask 0xffffff00 broadcast 192.168.64.255
And then from the pod I can curl 192.168.64.1:8080
However, I'm not sure both methods are the right way.
Is there a way to statically reference the host machine to be able to access open ports.
What's the solution here?
There are too many layers of indirection involved here and you’ll have to inject the physical host’s IP address into the container as an environment variable or ConfigMap setting. An ExternalName type Service could also work here.
The essential problem here is that each layer can find out about the layer immediately beyond it, but no further. You have a host running a VM running a Kubernetes Pod. The Pod can use the downward API to find its Node’s IP address, but in your case that will be the VM and not the host around it.
(As a parallel question: you have an ordinary home router that’s 192.168.1.1, and your local system is 192.168.1.2. You’re running some server on the router. Meanwhile, you have a VM running on your local system, which sees the host as 172.17.0.1 and believes it is 172.17.0.2. How does the VM reach the service on the router, if it doesn’t know about the 192.168.1.0/24 network in its local network environment?)
For others that also reach this question trying to make a pod running in minikube access a port running on the host, please refer to this reference.
In summary:
Make sure the service in the host is bound to 0.0.0.0 (all IPs). If it is only 127.0.0.1 (localhost) this will not work.
The pod inside minikube needs to connect to the host host.minikube.internal.

Network accessible IP for each docker container

I would like to deploy multiple applications via docker. Some of them are using the same port.
An alternative port mapping (Port 80->5080) is not an option, so my way to handle the problem is a network bridge which should allow me to assign an ip address from my internal network to each container.
The answer from this post does not work for me
Assign LAN IP address to Docker container different from host's IP address
i am able to assign an ip to the docker container, but it also gets the host ip address so i can not map ports.

How to delete interface docker0

I would like to remove the interface docker0. It would be better to avoid creating the interface docker0 when starting the service and using directly the eth0.
To delete the interface, use:
ip link delete docker0
You may require sudo privilege.
By default, the Docker server creates and configures the host system’s docker0 interface as an Ethernet bridge inside the Linux kernel that can pass packets back and forth between other physical or virtual network interfaces so that they behave as a single Ethernet network.
Look at Understand Docker container networks and Customize the docker0 bridge
When you install Docker, it creates three networks automatically. You can list these networks using the docker network ls command:
$ docker network ls
Historically, these three networks (bridge, none, host) are part of Docker’s implementation. When you run a container you can use the --network flag to specify which network you want to run a container on. These three networks are still available to you.
The bridge network represents the docker0 network present in all Docker installations. Unless you specify otherwise with the docker run --network= option, the Docker daemon connects containers to this network by default. You can see this bridge as part of a host’s network stack by using the ifconfig command on the host.
I support #gile's solution.
Be careful when removing interfaces. I do not recommend you to remove bridge docker0 (the default docker0 is as a bridge - in my case).
The documentation says:
Bridge networks are usually used when you are in standalone containers
that need to communicate.
https://docs.docker.com/network/#network-drivers
If you want to remove this interface, you can use the following tools in addition to the above solutions (for removing / adding interfaces I suggest you use the tools provided with the docker):
nmcli connection delete docker0
docker network rm docker0
brctl delbr docker0
If you don't want to create docker0 interface at all when docker starts then edit daemon.json(which is configuration file for docker) file to add line "bridge": "none" line to that json.
I have trouble with connecting to VPN after installing docker. The solution would be the following:
You can see the ip route table by executing ip route command in linux. Then delete any domains start with 172.16.x.x.
For example:
> ip route
default via 192.168.1.1 dev wlp2s0 proto dhcp metric 20600
169.254.0.0/16 dev wlp2s0 scope link metric 1000
172.16.14.0/24 dev vmnet8 proto kernel scope link src 172.16.14.1
172.16.57.0/24 dev vmnet1 proto kernel scope link src 172.16.57.1
192.168.1.0/24 dev wlp2s0 proto kernel scope link src 192.168.1.4 metric 600
Then delete them like the following:
sudo ip route del 172.16.14.0/24 dev vmnet8 proto kernel scope link src 172.16.14.1
sudo ip route del 172.16.57.0/24 dev vmnet1 proto kernel scope link src 172.16.57.1

How to access host port from docker container [duplicate]

This question already has answers here:
From inside of a Docker container, how do I connect to the localhost of the machine?
(41 answers)
Closed 12 months ago.
I have a docker container running jenkins. As part of the build process, I need to access a web server that is run locally on the host machine. Is there a way the host web server (which can be configured to run on a port) can be exposed to the jenkins container?
I'm running docker natively on a Linux machine.
UPDATE:
In addition to #larsks answer below, to get the IP address of the Host IP from the host machine, I do the following:
ip addr show docker0 | grep -Po 'inet \K[\d.]+'
For all platforms
Docker v 20.10 and above (since December 14th 2020)
On Linux, add --add-host=host.docker.internal:host-gateway to your Docker command to enable this feature. (See below for Docker Compose configuration.)
Use your internal IP address or connect to the special DNS name host.docker.internal which will resolve to the internal IP address used by the host.
To enable this in Docker Compose on Linux, add the following lines to the container definition:
extra_hosts:
- "host.docker.internal:host-gateway"
For macOS and Windows
Docker v 18.03 and above (since March 21st 2018)
Use your internal IP address or connect to the special DNS name host.docker.internal which will resolve to the internal IP address used by the host.
Linux support pending https://github.com/docker/for-linux/issues/264
MacOS with earlier versions of Docker
Docker for Mac v 17.12 to v 18.02
Same as above but use docker.for.mac.host.internal instead.
Docker for Mac v 17.06 to v 17.11
Same as above but use docker.for.mac.localhost instead.
Docker for Mac 17.05 and below
To access host machine from the docker container you must attach an IP alias to your network interface. You can bind whichever IP you want, just make sure you're not using it to anything else.
sudo ifconfig lo0 alias 123.123.123.123/24
Then make sure that you server is listening to the IP mentioned above or 0.0.0.0. If it's listening on localhost 127.0.0.1 it will not accept the connection.
Then just point your docker container to this IP and you can access the host machine!
To test you can run something like curl -X GET 123.123.123.123:3000 inside the container.
The alias will reset on every reboot so create a start-up script if necessary.
Solution and more documentation here: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds
When running Docker natively on Linux, you can access host services using the IP address of the docker0 interface. From inside the container, this will be your default route.
For example, on my system:
$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link
valid_lft forever preferred_lft forever
And inside a container:
# ip route show
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 src 172.17.0.4
It's fairly easy to extract this IP address using a simple shell
script:
#!/bin/sh
hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip
You may need to modify the iptables rules on your host to permit
connections from Docker containers. Something like this will do the
trick:
# iptables -A INPUT -i docker0 -j ACCEPT
This would permit access to any ports on the host from Docker
containers. Note that:
iptables rules are ordered, and this rule may or may not do the
right thing depending on what other rules come before it.
you will only be able to access host services that are either (a)
listening on INADDR_ANY (aka 0.0.0.0) or that are explicitly
listening on the docker0 interface.
If you are using Docker on MacOS or Windows 18.03+, you can connect to the magic hostname host.docker.internal.
Lastly, under Linux you can run your container in the host network namespace by setting --net=host; in this case localhost on your host is the same as localhost inside the container, so containerized service will act like non-containerized services and will be accessible without any additional configuration.
Use --net="host" in your docker run command, then localhost in your docker container will point to your docker host.
The answer is...
Replace http://127.0.0.1 or http://localhost with http://host.docker.internal.
Why?
Source in the docs of Docker.
My google search brought me to here, and after digging in the comments I found it's a duplicate of From inside of a Docker container, how do I connect to the localhost of the machine?. I voted for closing this one as a duplicate, but since people (including myself!) often scroll down on the answers rather than reading the comments carefully, here is a short answer.
For linux systems, you can – starting from major version 20.04 of the docker engine – now also communicate with the host via host.docker.internal. This won't work automatically, but you need to provide the following run flag:
--add-host=host.docker.internal:host-gateway
See
https://github.com/moby/moby/pull/40007#issuecomment-578729356
https://github.com/docker/for-linux/issues/264#issuecomment-598864064
Solution with docker-compose:
For accessing to host-based service, you can use network_mode parameter
https://docs.docker.com/compose/compose-file/#network_mode
version: '3'
services:
jenkins:
network_mode: host
EDIT 2020-04-27: recommended for use only in local development environment.
EDIT 2021-09-21: IHaveHandedInMyResignation wrote it does not work for Mac and Windows. Option is supported only for Linux
I created a docker container for doing exactly that https://github.com/qoomon/docker-host
You can then simply use container name dns to access host system e.g.
curl http://dockerhost:9200
Currently the easiest way to do this on Mac and Windows is using host host.docker.internal, that resolves to host machine's IP address. Unfortunately it does not work on linux yet (as of April 2018).
We found that a simpler solution to all this networking junk is to just use the domain socket for the service. If you're trying to connect to the host anyway, just mount the socket as a volume, and you're on your way. For postgresql, this was as simple as:
docker run -v /var/run/postgresql:/var/run/postgresql
Then we just set up our database connection to use the socket instead of network. Literally that easy.
I've explored the various solution and I find this the least hacky solution:
Define a static IP address for the bridge gateway IP.
Add the gateway IP as an extra entry in the extra_hosts directive.
The only downside is if you have multiple networks or projects doing this, you have to ensure that their IP address range do not conflict.
Here is a Docker Compose example:
version: '2.3'
services:
redis:
image: "redis"
extra_hosts:
- "dockerhost:172.20.0.1"
networks:
default:
ipam:
driver: default
config:
- subnet: 172.20.0.0/16
gateway: 172.20.0.1
You can then access ports on the host from inside the container using the hostname "dockerhost".
For docker-compose using bridge networking to create a private network between containers, the accepted solution using docker0 doesn't work because the egress interface from the containers is not docker0, but instead, it's a randomly generated interface id, such as:
$ ifconfig
br-02d7f5ba5a51: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.32.1 netmask 255.255.240.0 broadcast 192.168.47.255
Unfortunately that random id is not predictable and will change each time compose has to recreate the network (e.g. on a host reboot). My solution to this is to create the private network in a known subnet and configure iptables to accept that range:
Compose file snippet:
version: "3.7"
services:
mongodb:
image: mongo:4.2.2
networks:
- mynet
# rest of service config and other services removed for clarity
networks:
mynet:
name: mynet
ipam:
driver: default
config:
- subnet: "192.168.32.0/20"
You can change the subnet if your environment requires it. I arbitrarily selected 192.168.32.0/20 by using docker network inspect to see what was being created by default.
Configure iptables on the host to permit the private subnet as a source:
$ iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT
This is the simplest possible iptables rule. You may wish to add other restrictions, for example by destination port. Don't forget to persist your iptables rules when you're happy they're working.
This approach has the advantage of being repeatable and therefore automatable. I use ansible's template module to deploy my compose file with variable substitution and then use the iptables and shell modules to configure and persist the firewall rules, respectively.
This is an old question and had many answers, but none of those fit well enough to my context. In my case, the containers are very lean and do not contain any of the networking tools necessary to extract the host's ip address from within the container.
Also, usin the --net="host" approach is a very rough approach that is not applicable when one wants to have well isolated network configuration with several containers.
So, my approach is to extract the hosts' address at the host's side, and then pass it to the container with --add-host parameter:
$ docker run --add-host=docker-host:`ip addr show docker0 | grep -Po 'inet \K[\d.]+'` image_name
or, save the host's IP address in an environment variable and use the variable later:
$ DOCKERIP=`ip addr show docker0 | grep -Po 'inet \K[\d.]+'`
$ docker run --add-host=docker-host:$DOCKERIP image_name
And then the docker-host is added to the container's hosts file, and you can use it in your database connection strings or API URLs.
For me (Windows 10, Docker Engine v19.03.8) it was a mix of https://stackoverflow.com/a/43541732/7924573 and https://stackoverflow.com/a/50866007/7924573 .
change the host/ip to host.docker.internal
e.g.: LOGGER_URL = "http://host.docker.internal:8085/log"
set the network_mode to bridge (if you want to maintain the port forwarding; if not use host):
version: '3.7'
services:
server:
build: .
ports:
- "5000:5000"
network_mode: bridge
or alternatively: Use --net="bridge" if you are not using docker-compose (similar to https://stackoverflow.com/a/48806927/7924573)
As pointed out in previous answers: This should only be used in a local development environment.
For more information read: https://docs.docker.com/compose/compose-file/#network_mode and https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds
You can access the local webserver which is running in your host machine in two ways.
Approach 1 with public IP
Use host machine public IP address to access webserver in Jenkins docker container.
Approach 2 with the host network
Use "--net host" to add the Jenkins docker container on the host's network stack. Containers which are deployed on host's stack have entire access to the host interface. You can access local webserver in docker container with a private IP address of the host machine.
NETWORK ID NAME DRIVER SCOPE
b3554ea51ca3 bridge bridge local
2f0d6d6fdd88 host host local
b9c2a4bc23b2 none null local
Start a container with the host network
Eg: docker run --net host -it ubuntu and run ifconfig to list all available network IP addresses which are reachable from docker container.
Eg: I started a nginx server in my local host machine and I am able to access the nginx website URLs from Ubuntu docker container.
docker run --net host -it ubuntu
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a604f7af5e36 ubuntu "/bin/bash" 22 seconds ago Up 20 seconds ubuntu_server
Accessing the Nginx web server (running in local host machine) from Ubuntu docker container with private network IP address.
root#linuxkit-025000000001:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes
In almost 7 years the question was asked, it is either docker has changed, or no one tried this way. So I will include my own answer.
I have found all answers use complex methods. Today, I have needed this, and found 2 very simple ways:
use ipconfig or ifconfig on your host and make note of all IP addresses. At least two of them can be used by the container.
I have a fixed local network address on WiFi LAN Adapter: 192.168.1.101. This could be 10.0.1.101. the result will change depending on your router
I use WSL on windows, and it has its own vEthernet address: 172.19.192.1
use host.docker.internal. Most answers have this or another form of it depending on OS. The name suggests it is now globally used by docker.
A third option is to use WAN address of the machine, or in other words IP given by the service provider. However, this may not work if IP is not static, and requires routing and firewall settings.
PS: Although pretty identical to this question here, and I posted this answer there, I first found this post, so I post it here too as may forget my own answer.
The simplest option that worked for me was,
I used the IP address of my machine on the local network(assigned by the router)
You can find this using the ifconfig command
e.g
ifconfig
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=400<CHANNEL_IO>
ether f0:18:98:08:74:d4
inet 192.168.178.63 netmask 0xffffff00 broadcast 192.168.178.255
media: autoselect
status: active
and then used the inet address. This worked for me to connect any ports on my machine.
When you have two docker images "already" created and you want to put two containers to communicate with one-another.
For that, you can conveniently run each container with its own --name and use the --link flag to enable communication between them. You do not get this during docker build though.
When you are in a scenario like myself, and it is your
docker build -t "centos7/someApp" someApp/
That breaks when you try to
curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz
and you get stuck on "curl/wget" returning no "route to host".
The reason is security that is set in place by docker that by default is banning communication from a container towards the host or other containers running on your host.
This was quite surprising to me, I must say, you would expect the echosystem of docker machines running on a local machine just flawlessly can access each other without too much hurdle.
The explanation for this is described in detail in the following documentation.
http://www.dedoimedo.com/computers/docker-networking.html
Two quick workarounds are given that help you get moving by lowering down the network security.
The simplest alternative is just to turn the firewall off - or allow all. This means running the necessary command, which could be systemctl stop firewalld, iptables -F or equivalent.

Resources