简体   繁体   中英

How to access network address from IFCONFIG from inside a Docker Container?

I am using a docker container for hyperledger aca-py agents, and for a project, I need the network address of the machine for the internet network, it is currently connected to. To access IFCONFIG in python, I am using the "netifaces" library in Python. The following lines of code work well outside the docker container of the agents, but on running it in the container, it shows an error. Why is this so ?

import netifaces as ni

...

net_add = ni.ifaddresses('wlp4s0')[2][0]['addr']
request_obj = requests.get('http://' + str(net_add) + ':8080/api/some_endpoint'))

Error message :

Shutting down agent ...
Faber      | 
Faber      | Shutting down
Faber      | Exited with return code 0
Traceback (most recent call last):
  File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/indy/demo/runners/university.py", line 803, in <module>
    asyncio.get_event_loop().run_until_complete(main(args))
  File "/home/indy/.pyenv/versions/3.6.13/lib/python3.6/asyncio/base_events.py", line 488, in run_until_complete
    return future.result()
  File "/home/indy/demo/runners/university.py", line 544, in main
    rll,
  File "/home/indy/demo/runners/university.py", line 82, in generate_credential_offer
    net_add = ni.ifaddresses('wlp4s0')[2][0]['addr']
ValueError: You must specify a valid interface name.

Docker containers can't see the host network interface or other setup. This is by design. A container can only see its Docker-private networking setup, and while Docker provides a NAT setup to make outbound connections, a container can't find out the host's IP address, or what interfaces it has, or look up a host interface by name.

As an operator you need to determine and inject this information yourself. Using the host ip in docker-compose suggests a recipe like:

# your_app.py
external_ip = os.environ['EXTERNAL_IP']
requests.get('http://' + external_ip + ':8080/api/some_endpoint')
# docker-compose.yml
services:
  your-app:
    environment:
      - EXTERNAL_IP # with no value, passed through from host
# at the shell prompt
export EXTERNAL_IP=$(hostname -I | awk '{print $1}')
docker-compose up -d

The hostname -I invocation may be wrong! But it's all but impossible to know this programatically.


Let's consider a container running on my current system. That container has an IP address; say it's 172.17.0.2/16. But that's not a routable address, it's inside the Docker-private IP space. If I could look at its host environment, I'd discover an IP address 192.168.65.3/24. But that's the Docker Desktop Linux VM, and that IP address isn't routable either. If I could step out of that, the real physical host has an IP address 192.168.149.120/24; but that's not routable either, it's on my home network. I'd need to talk to the router to find an actual routable Internet-visible IP address, nothing on my local system actually knows it at all.

+--------------------+          +-------------------------------+
|      192.168.149.1 |          | Host          192.168.149.120 |
|                    |          | +---------------------------+ |
|       Router       |          | | Docker VM    192.168.65.3 | |
|                    | <------- | | +-----------------------+ | |
|                    |          | | | Container  172.17.0.2 | | |
|                    |          | | +-----------^-----------+ | |
| 66.77.88.99        |          | +-------------|-------------+ |
+------^-------------+          +---------------|---------------+
       |                                        |
You need this address                  You are actually here

You can imagine other network environments where this is even more complicated. In Kubernetes, a Pod has an IP address but you don't usually use it; instead, clients send to a Service that forwards to the Pod. You might run an HTTP-based application through a content-delivery network, where the URL you want to publish is the CDN's DNS name and not something in your environment at all.


It might work to disable Docker networking, either running the container with docker run --net host or in Compose with network_mode: host . This disables some key Docker functionality, so you can't use other containers' names as host names and you can't hide or remap your application's ports. If you're in a Docker Desktop environment (not on native Linux) then you'll see the Linux VM's network environment, which still isn't the host environment. And again, even if you do get the physical host's network interfaces, there's no guarantee that it will actually have a routable IP address.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM