I’d like to create a container via the docker rest api which will be accessible from the host but without external network access.
I’ve read the docs a couple times but still not able to get it to work.
When passing in the network name as the network to connect to when starting, there are no ports exposed.
If I connect at a later time, the container is connected to 2 networks – the default bridge, and my network. The exposed ports are working correctly in the latter case.
How do I configure this?
EDIT:
I did some more experiments – I was setting
Internal: true
Which according to the docs makes it so that only other containers connected will have access to the container.
I’d like to access the container from the host so the network cannot be internal.
Setting it to False allows me to access the container, but I can also connect to google from within the container.
Relevant reading:
https://docs.docker.com/engine/api/v1.43/#tag/Container/operation/ContainerCreate
The second link talks about creating a bridge network which by default shouldn’t have an external gateway.
Here is the network inspected as well as some other useful info
=> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cecb660da65c datumai/mh-mock-runtime:latest "uvicorn app.main:ap…" 5 minutes ago Up 5 minutes 0.0.0.0:55807->80/tcp datumai-model
=> docker inspect ID_CONTAINER
"NetworkSettings": {
"Bridge": "",
"SandboxID": "f5509cdf337b740ad50290766854aebddadd802366c780cf4d5e31a7050ffbd7",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"80/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "55807"
}
]
},
"SandboxKey": "/var/run/docker/netns/f5509cdf337b",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"datumai-model-network-offline": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"cecb660da65c"
],
"NetworkID": "59d034f30a97de377c6d3745b1b5764c487d58a5aa2e69dedd2dc7f4ece71e33",
"EndpointID": "f12b9a39c85ecda7f60edea34c09cc8773eb61be90dee281228b59d7bb6eba47",
"Gateway": "172.27.0.1",
"IPAddress": "172.27.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:1b:00:02",
"DriverOpts": null
}
}
}
}
=> docker inspect ID_OF_NETWORK
[
{
"Name": "datumai-model-network-offline",
"Id": "59d034f30a97de377c6d3745b1b5764c487d58a5aa2e69dedd2dc7f4ece71e33",
"Created": "2024-01-07T02:48:35.182210136Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.27.0.0/16",
"Gateway": "172.27.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"e42176ec9ae1b540a3703ccd6c09d44782dd17e5fba8bc7d4ff2a7403daf729a": {
"Name": "datumai-model",
"EndpointID": "e9ec6900d53c772a84f136d2599b1410aca0366518009a522a31b78de70a00d0",
"MacAddress": "02:42:ac:1b:00:02",
"IPv4Address": "172.27.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {
"com.datumai.model": "true"
}
}
]
EDIT 2:
The answer below mentions that an internal network should work just fine. Unfortunately, it seems that for my setup – which is Docker Desktop on a MacOSX M2, it doesn’t work that way.
Reproducing the issue:
docker network create --internal internal
docker run --net internal --rm --name web docker.io/alpinelinux/darkhttpd
in a new tab
=> docker container inspect web --format '{{.NetworkSettings.Networks.internal.IPAddress}}'
172.29.0.2:8080
The call to curl from host:
=> curl 172.29.0.2:8080
hangs, then shows
curl: (28) Failed to connect to 172.29.0.2 port 8080 after 75009 ms: Couldn't connect to server
2
Answers
I finally managed to get the behavior I want, but unfortunatelly that required a workaround by running an additional proxy. The approach isn't perfect but it might help someone down the line.
Here are the rough steps to follow
I've used https://hub.docker.com/r/jwilder/nginx-proxy.
The configuration requires the following:
The calls to the containers need to be routed through the proxy container, which needs the Host header set to the VIRTUAL_HOST above.
e.g.
Finally a call to the service succeeds, but any queries inside the container to e.g. google fail.
In fact, you can access a container from the host even when using the
internal
network as long as you access the container ip directly (rather than using port publishing). For example, if we start up a simple web server like this:We can get the container ip address like this:
And we can successfully connect to the web service in that container:
Because it’s on an
internal
network, the container doesn’t have outbound network connectivity:That is highly inaccurate. A bridge network is the most common type of Docker network, and of course it has a default gateway because most folks do want outbound network access: