-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Add support for docker autodiscover to monitor containers on host network #6708
Conversation
Since this is a community submitted pull request, a Jenkins build has not been kicked off automatically. Can an Elastic organization member please verify the contents of this patch and then kick off a build manually? |
libbeat/common/docker/util.go
Outdated
|
||
// GetHostIp can look at the hostname and give the container gateway/host IP based on where the given | ||
// beat is running. | ||
func GetHostIp(watcher Watcher) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func GetHostIp should be GetHostIP
@@ -65,13 +66,16 @@ func AutodiscoverBuilder(bus bus.Bus, c *common.Config) (autodiscover.Provider, | |||
return nil, err | |||
} | |||
|
|||
hostIp := docker.GetHostIp(watcher) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var hostIp should be hostIP
@@ -24,6 +24,7 @@ type Provider struct { | |||
appenders autodiscover.Appenders | |||
watcher docker.Watcher | |||
templates *template.Mapper | |||
hostIp string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct field hostIp should be hostIP
53cb8cf
to
3c1afca
Compare
As we already had this feature in 6.2, could you add a CHANLOGE entry? As far as I understand the change, it's an addition / enhancement and will not break anything existant. For the |
jenkins, test it |
@ruflin i think it is necessary to break this PR into 2. Otherwise you wont be able to back port this fix to 6.2. Thoughts? |
I'm always up for 2 PR's if they can be separated, especially if one of them needs backport. |
a668182
to
9b02d7d
Compare
@ruflin this PR has to be back ported to 6.2 and I have pulled out the hints builder changes to a separate PR[https://github.com//pull/6727] to allow the same. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. @jsoriano would you mind having a look?
jenkins, test it |
libbeat/common/docker/util.go
Outdated
// Gateway address of a container is one of the interfaces on the host that can be used to connect to | ||
// containers that are being run on host network. | ||
for cid, container := range watcher.Containers() { | ||
if strings.Index(cid, hostname) == 0 && container != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In docker inspect
the hostname is available under Config
, I guess that it is also in the API, could we store it when requesting containers information so we don't need to assume anything? 🙂
libbeat/common/docker/util.go
Outdated
for _, address := range addrs { | ||
// Check the address type and if it is not a loop back then return it | ||
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { | ||
if ipnet.IP.To4() != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to limit to IPv4 only?
libbeat/common/docker/watcher.go
Outdated
|
||
if net.Gateway != "" { | ||
gateways = append(gateways, net.Gateway) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, when requesting information from the daemon we could also get the Hostname, at least if we use inspect, not sure with list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we wont get a hostname for a container running on host network.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A container running in host network gets the hostname of the host.
libbeat/common/docker/util.go
Outdated
return getLocalIP() | ||
} | ||
|
||
func getLocalIP() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is a bit tricky, are we sure that net.InterfaceAddrs()
always returns the addresses in the same order? what happens if an address is added or removed?
I think there is no safe method to guess the address of a host with multiple addresses 😐 maybe for that case we should allow to configure a host address in metricbeat (e.g. sensu has the address setting, and kubelet has the --node-ip
flag), and take it from there @ruflin wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of making it configurable. We can try to guess by default but we allow the user to overwrite it if the guessing is wrong. Normally I would suggest to go the other way and have the configuration by default and require the user to enable the magic part but as this is part of auto
discovery the user expects no configuration and magic I would say.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I talked with @vjsamuel offline and sory, I had misunderstood something, as the IP is only required to connect with the host namespace then yes, any IP of the host is equally valid :)
e9775f1
to
04bd3ed
Compare
jenkins, test it |
if len(ipaddresses) == 0 { | ||
info, err := w.client.ContainerInspect(w.ctx, c.ID) | ||
if err == nil { | ||
ipaddresses = append(ipaddresses, info.Config.Hostname) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
metricbeat
running in docker will only be able to resolve the hostname of the host if it is in the DNS or if the host exists in /etc/hosts
in the container, what is not always necessarily true.
I think we should check here if metricbeat
is running in docker (or in a network namespace).
If it is, then we use its gateway, that should be an IP in the host, as you proposed in a previous version, but now we are sure of knowing the hostname.
If it isn't running as docker it is also running in host mode and localhost or a local IP can be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i checked this behavior and it seems to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
neither approach work (using hostname and gateway ip) on mac however
I'm ok with this change if we don't find something more reliable. I was planning to do some research on this and try to come up with some alternative way to retrieve host IP, not sure it's possible though :) |
04bd3ed
to
5ee2645
Compare
I've been researching this with @vjsamuel, it seems we can get host IP by checking the default gateway:
It should be possible to read it from proc filesystem, I guess this will support more use cases, still to be tested |
5ee2645
to
e0556e8
Compare
@exekias i was revisiting the code today, i feel that this might be the cleanest solution code-wise. what do you think? if you are not convinced, i can make the above discussed change |
e0556e8
to
e31b456
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM @vjsamuel, this already improves the situation. I left some comments
CHANGELOG.asciidoc
Outdated
@@ -161,6 +161,9 @@ https://github.com/elastic/beats/compare/v6.2.3...master[Check the HEAD diff] | |||
- Add experimental Jolokia Discovery autodiscover provider. {pull}7141[7141] | |||
- Add owner object info to Kubernetes metadata. {pull}7231[7231] | |||
- Add beat export dashboard command. {pull}7239[7239] | |||
- Add a default seccomp (secure computing) filter on Linux that prohibits | |||
execve, execveat, fork, and vfork syscalls. A custom policy can be configured. {issue}5213[5213] | |||
- Add support for docker autodiscover to monitor containers on host network {pull}6708[6708] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some entries sneaked in here
libbeat/common/docker/watcher.go
Outdated
if err == nil { | ||
ipaddresses = append(ipaddresses, info.Config.Hostname) | ||
} else { | ||
logp.Debug("docker", "unable to inspect container %s due to error %v", c.ID, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably be a warning message? as it should not happen frequently, and can cause some debugging nightmares
e31b456
to
b182429
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WFG
jenkins, test this please |
In today's approach autodiscover docker provider can not monitor containers running on Host network. If a container runs on host network it would not have
.NetworkSettings.IPAddress
as seen below:To be able to monitor these containers we detect a host address that can be used be the docker auto discover as follows:
Gateway
of the network interface. That will be the host address that can be used.