Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hostname for container gateway #5651

Closed
kermorgant opened this issue Mar 29, 2020 · 27 comments · Fixed by #9972
Closed

hostname for container gateway #5651

kermorgant opened this issue Mar 29, 2020 · 27 comments · Fixed by #9972
Assignees
Labels
Good First Issue This issue would be a good issue for a first time contributor to undertake. kind/feature Categorizes issue or PR as related to a new feature. locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments.

Comments

@kermorgant
Copy link

/kind feature

Description

Provide a dns entry to containers pointing to their gateway.

Context : as a developer, one of my setup involves a service running on the host machine, that should be proxied by nginx running in a container.

Describe the results you received:

I could make it work by writing the container's static gateway ip in nginx's config.

Describe the results you expected:

It would have been nice to have a standard hostname for the gateway (I believe docker has host.docker.internal for that). Or did I miss some easy alternative ?

Output of podman version:

Version:            1.8.2
RemoteAPI Version:  1
Go Version:         go1.14
Git Commit:         028e3317eb1494b9b2acba4a0a295df80fae66cc
Built:              Sat Mar 21 15:30:34 2020
OS/Arch:            linux/amd64```

@openshift-ci-robot openshift-ci-robot added the kind/feature Categorizes issue or PR as related to a new feature. label Mar 29, 2020
@mheon
Copy link
Member

mheon commented Mar 29, 2020 via email

@github-actions
Copy link

A friendly reminder that this issue had no activity for 30 days.

@rhatdan rhatdan added the Good First Issue This issue would be a good issue for a first time contributor to undertake. label Apr 29, 2020
@rhatdan
Copy link
Member

rhatdan commented Jun 9, 2020

@ParkerVR PTAL

@baude
Copy link
Member

baude commented Jun 22, 2020

I think this is actually already available when using the dnsname plugin. One point, this is NOT purposely enabled on the default network (same with docker). But I think, if i understand your want, it can be done on any network that has the dnsname plugin enabled.

  1. Create a new network
/etc/cni/net.d/homer.conflist
  1. Run a container on that new network.
ed449cbae687479ed354c8f66c8b0db4636a74d57578662ae614e195e804c229
  1. Check the IP of the container
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
3: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 6e:6f:62:c2:35:8b brd ff:ff:ff:ff:ff:ff
    inet 10.89.3.5/24 brd 10.89.3.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::6c6f:62ff:fec2:358b/64 scope link 
       valid_lft forever preferred_lft forever
  1. Check the route of the container
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.89.3.1       0.0.0.0         UG    0      0        0 eth0
10.89.3.0       0.0.0.0         255.255.255.0   U     0      0        0 eth0
  1. Check the /etc/resolv.conf inside the container
search redhat.com localdomain DESKTOP-SH5EG3J.localdomain
nameserver 10.89.3.1

@rhatdan
Copy link
Member

rhatdan commented Sep 10, 2020

Since this is already available, closing.

@rhatdan rhatdan closed this as completed Sep 10, 2020
@outergod
Copy link

outergod commented Jan 4, 2021

I tried to read @baude's answer multiple times to understand how the dnsname plugin solves this problem as I also happen to be in need of this feature, but I'm either failing to understand the answer or there is a misunderstanding.

The plugin provides internal hostname resolution for each container on the same network via dnsmasq, which is also visible in /run/containers/cni/dnsname/$NETWORK/addnhosts, however it does not provide a hostname for the gateway IP, which is what the ticket author has been asking for.

In the given example, 10.89.3.1 should e.g. be resolvable through gateway (or a similar name), which is currently not the case.

@baude baude reopened this Jan 4, 2021
@bblenard
Copy link

@rhatdan If this needs someone to work on it I'll take a swing at it.

@rhatdan
Copy link
Member

rhatdan commented Jan 22, 2021

Go for it.

@bblenard
Copy link

Just to make sure I have the details down correctly, when we spin up a container we have the following options for its network configuration

Slirp: Gateway address is CIDR + 2 REF although this is inaccessible without allow_host_loopback=true
Bridge: Rootless mode will not have an interface other than loopback, "root" mode will connect to cni network and the gateway address will be in NetworkSettings block
FromPod/FromContainer: depends on the specific pod / container but should be something we can inspect at runtime
Default/Private (which ends up being bridge or slirp): Depends on if it is rootless or not
None: No network so no gateway, not sure on this one.
Host: Not sure on this one other than runtime inspection
Existing NS: Not sure on this one
List of CNI Networks: Not sure on this one

Overall I'm not sure on the technical details required to determine the containers gateway especially in a portable way that will work on windows/mac. Is there anything I should read up on while trying to tackle this ticket / suggestions? Also if any of my assumptions above are wrong please let me know.

@mheon
Copy link
Member

mheon commented Jan 26, 2021

Corrections:

  • Rootless (with the new rootless CNI feature from 2.1) does support connecting to CNI networks, so your bridge assumption is incorrect. For both root and rootless, the gateway is contained in NetworkSettings. If the container joins multiple CNI networks (List of CNI Netwoirks). Generally speaking, NetworkSettings is not nil, we should source gateway from there.
  • If we are joining the network NS of another pod/container, we should get that container's gateway (in the pod case, the infra container's) and use that.
  • None does not have a gateway and should not set one. Existing NS (specifying an NS by path) has insufficient information to determine so we can't determine one.

Generally speaking: If ctr.config.NetNSCtr is set (we are sharing a network namespace), we need to get that container's gateway. If ctr.state.NetworkSettings is not nil, we should grab gateways from any results returned by CNI and use those. If ctr.state.NetworkSettings is nil, and network mode is slirp4netns, we use the slirp gateway. If the container is in the host network, we can try and handle that by grabbing the host's gateway, but I'd just as soon take no action in that case. If none of the above are true, we can't determine gateway, do nothing.

@bblenard
Copy link

@mheon Thanks for the insight. I think I have enough to go on now! (hopefully lol)

@bblenard
Copy link

Got something working(ish). I am still ironing out the implementation but this might hit the points Matthew outlined

bblenard@dc5bcc8

That being said according to the CNI spec the ctr.state.NetworkStatus block could potentially have multiple IP entries with different gateways or none at all. I'll keep digging into this but at the moment I'm not sure if this could pose an issue (or I just am not getting something yet).

I also need to fix the assumed 10.0.2.100 / 10.0.2.3 / 10.0.2.2 values for slirp4netns stuff. If I am understanding correctly those are just the default values and instead we should inspect the networks configured cidr to determine the address (cidr + 100), dns (cidr + 3), and gateway (cidr + 2).

All stuff I still need to figure out 🤷

@bblenard
Copy link

Okay so I think I have an implementation that works but I'm not quite ready for a PR because I'm worried I have some technical details wrong. If someone from Redhat / someone more knowledgeable than me wants to take a look at my changes I would greatly appreciate it.

master...bblenard:issue-5651-hostname-for-container-gateway

@mheon
Copy link
Member

mheon commented Jan 29, 2021

I think we'll need @AkihiroSuda or @giuseppe to validate the slirp bits. The CNI bits look fine, though the Slirp and CNI bits should probably be mutually exclusive (I imagine we'll want to use the CNI provided gateway, even in rootless CNI scenarios).

@AkihiroSuda
Copy link
Collaborator

I imagine we'll want to use the CNI provided gateway, even in rootless CNI scenarios

Yes 👍

@bblenard
Copy link

bblenard commented Feb 3, 2021

Currently trying to write some tests for these changes before I open a PR.

While messing with tests I had an issue that lead me to an additional potential issue. Currently the code that handles determining the gateway is as follows (getHosts in container_linux_internal.go):

	var depCtr *Container
	if c.config.NetNsCtr != "" {
		// ignoring the error because there isn't anything to do
		depCtr, _ = c.getRootNetNsDepCtr()
	} else if len(c.state.NetworkStatus) != 0 {
		depCtr = c
	} else {
		depCtr = nil
	}

	if depCtr != nil {
		for _, pluginResultsRaw := range depCtr.state.NetworkStatus {
			pluginResult, _ := cnitypes.GetResult(pluginResultsRaw)
			for _, ip := range pluginResult.IPs {
				hosts += fmt.Sprintf("%s host.gateway.internal\n", ip.Gateway)
			}
		}
	} else if c.config.NetMode.IsSlirp4netns() {
		hosts += fmt.Sprintf("%s host.gateway.internal\n", slirp4netnsGateway)
	} else {
		logrus.Debug("unexpected network configuration while determining host.gateway.internal address")
	}

An issue I am worried about is the check that determines if c.state.NetworkStatus has entries. If it has entries those are supposed to be:

NetworkStatus contains the configuration results for all networks the pod is attached to. Only populated if we created a network namespace for the container, and the network namespace is currently active REF

I don't know if this is possible but if the network status object has multiple results ie len(c.state.NetworkStatus) > 1 , we could end up with multiple host.gateway.internal addresses in /etc/hosts. I don't know if this is a possibility or not 🤷

Finally @mheon's comment:

I imagine we'll want to use the CNI provided gateway, even in rootless CNI scenarios

I also am not sure how to create this situation to test my implementation.

Sorry to ramble here but I am worried my implementation doesn't consider all use cases / my understanding of podman's networking is lacking...

@github-actions
Copy link

github-actions bot commented Mar 6, 2021

A friendly reminder that this issue had no activity for 30 days.

@rhatdan
Copy link
Member

rhatdan commented Mar 7, 2021

@bblenard @AkihiroSuda @mheon What is going on with this issue? Anything?

@bblenard
Copy link

I pushed up some code that might take care of this but when I went to write some unit tests I felt that there could be some issues with my implementation which I mentioned above. I haven't messed with this since though.

@mheon
Copy link
Member

mheon commented Mar 10, 2021

Sorry, didn't see that response. We can potentially end up with multiple CNI results (will happen in any case where a container joins multiple networks), but this is probably OK - we can generate a hosts entry with multiple IP addresses, one for each gateway.

@bblenard
Copy link

bblenard commented Mar 12, 2021

Okay I can look at picking this backup and try to get a PR opened soon (hopefully within a week or so)

Edit:

So I double checked man 5 hosts and that says the format should be

IP_address canonical_hostname [aliases...]

So @mheon can you explain more what you mean when you say

we can generate a hosts entry with multiple IP addresses

Because I'm interpreting that to mean:

1.1.1.1 1.1.1.2 1.1.1.3 host.gateway.internal

Which seems wrong, but I could be misinterpreting you, the man page, or both

@bblenard
Copy link

@mheon bump ^ just in case you didn't see my sneaky edit

@mheon
Copy link
Member

mheon commented Mar 29, 2021

@bblenard No - I believe it is valid to do:

1.1.1.1 host.gateway.internal
2.2.2.2 host.gateway.internal

@bblenard
Copy link

bblenard commented Apr 8, 2021

Finally got around to opening a PR, its been a while so hopefully I didn't make a silly mistake. I would love some suggestions on how to make sure I test this properly. I did basic sanity checks on my machine

➜  podman git:(issue-5651-hostname-for-container-gateway) bin/podman run --network slirp4netns:cidr=192.168.0.0/24,allow_host_loopback=true centos sh -c 'cat /etc/hosts && ping -c 1 host.gateway.internal'
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# used by slirp4netns
192.168.0.100	237a017ac22c vigilant_bouman
192.168.0.2 host.gateway.internal
PING host.gateway.internal (192.168.0.2) 56(84) bytes of data.
64 bytes from host.gateway.internal (192.168.0.2): icmp_seq=1 ttl=255 time=0.071 ms

--- host.gateway.internal ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.071/0.071/0.071/0.000 ms
➜  podman git:(issue-5651-hostname-for-container-gateway) bin/podman run --network slirp4netns:allow_host_loopback=true centos sh -c 'cat /etc/hosts && ping -c 1 host.gateway.internal' 
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# used by slirp4netns
10.0.2.100	93f8233fd52c vigorous_keldysh
10.0.2.2 host.gateway.internal
PING host.gateway.internal (10.0.2.2) 56(84) bytes of data.
64 bytes from host.gateway.internal (10.0.2.2): icmp_seq=1 ttl=255 time=0.078 ms

--- host.gateway.internal ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.078/0.078/0.078/0.000 ms

@github-actions
Copy link

github-actions bot commented May 9, 2021

A friendly reminder that this issue had no activity for 30 days.

@bblenard
Copy link

This issue isn't stale :) still working out the details for the implementation here: #9972

bblenard pushed a commit to bblenard/podman that referenced this issue May 17, 2021
This change adds the entry `host.containers.internal` to the `/etc/hosts`
file within a new containers filesystem. The ip address is determined by
the containers networking configuration and points to the gateway address
for the containers networking namespace.

Closes containers#5651

Signed-off-by: Baron Lenardson <[email protected]>
@outergod
Copy link

Thanks @bblenard for your work on this!

@github-actions github-actions bot added the locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. label Sep 21, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Good First Issue This issue would be a good issue for a first time contributor to undertake. kind/feature Categorizes issue or PR as related to a new feature. locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants