-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Advertise driver-specific addresses #2709
Conversation
6dfd590
to
43a326c
Compare
nomad/structs/structs.go
Outdated
@@ -2467,6 +2498,11 @@ func (s *Service) Copy() *Service { | |||
// Canonicalize interpolates values of Job, Task Group and Task in the Service | |||
// Name. This also generates check names, service id and check ids. | |||
func (s *Service) Canonicalize(job string, taskGroup string, task string) { | |||
// Default to AddressModeAuto | |||
if s.AddressMode == "" { |
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.
Can you actually move this to the api pkg. The defaulting should be happening there now.
Tags []string | ||
PortLabel string `mapstructure:"port"` | ||
AddressMode string `mapstructure:"address_mode"` | ||
Checks []ServiceCheck |
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.
Canonicalize below
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.
Added
client/driver/docker.go
Outdated
// This should only happen if there's been a coding error (such | ||
// as not calling InspetContainer after CreateContainer). Code | ||
// defensively in case the Docker API changes subtly. | ||
d.logger.Printf("[WARN] driver.docker: no network settings for container %s", c.ID) |
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.
May want to bump the log level
// Don't auto-advertise bridge IPs | ||
if name != "bridge" { | ||
auto = true | ||
} |
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.
Just break?
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.
Done
client/driver/qemu.go
Outdated
@@ -276,7 +276,7 @@ func (d *QemuDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, | |||
waitCh: make(chan *dstructs.WaitResult, 1), | |||
} | |||
go h.run() | |||
return h, nil | |||
return &StartResponse{Handle: h}, 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.
Does this not need to expose the port map?
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've only ever propagated the port map for the Docker driver despite rkt and qemu also having port maps. Should I go ahead and add that as part of this PR? Should Just Work but would be a new feature (or bugfix depending on perspective).
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.
From offline discussion: going to have rkt and qemu return their port maps.
nomad/structs/structs.go
Outdated
const ( | ||
AddressModeAuto = "auto" | ||
AddressModeHost = "host" | ||
AddressModeDriver = "driver" //FIXME plugin? I forget what we decided because like 1000 other things have gone wrong since then |
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.
Remove FIXME
client/driver/env/env.go
Outdated
// allocations to tasks with the driver's IP address if on exists. | ||
// Service's will advertise this address if address_mode=true or | ||
// address_mode=auto and the driver determines it should be used. | ||
DriverAddrPrefix = "NOMAD_DRIVER_ADDR_" |
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.
Remove
client/driver/env/env.go
Outdated
// Deprecated: Use NOMAD_HOST_ADDR_ or NOMAD_DRIVER_ADDR_ instead as | ||
// this environment variable will only ever use the host IP. If a port | ||
// map is used this variable will be set to the Host IP and Driver's | ||
// Port which likely won't work in either context. |
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.
Make it always be host_ip:host_port and don't say deprecated
client/driver/env/env.go
Outdated
AddrPrefix = "NOMAD_ADDR_" | ||
|
||
// IpPrefix is the prefix for passing the IP of a port allocation to a task. | ||
// IpPrefix is the prefix for passing the IP of a port allocation to a | ||
// task. This may not be the host's address depending on task |
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.
Always host IP
client/driver/env/env.go
Outdated
IpPrefix = "NOMAD_IP_" | ||
|
||
// PortPrefix is the prefix for passing the port allocation to a task. | ||
PortPrefix = "NOMAD_PORT_" | ||
|
||
// HostAddrPrefix is the prefix for passing both dynamic and static | ||
// port allocations to tasks with the host's IP address for cases where | ||
// the task advertises a different address. |
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.
Remove these
5a8964e
to
82c89f0
Compare
Ideally DriverNetwork would be fully populated in Driver.Prestart, but Docker doesn't assign the container's IP until you start the container. However, it's important to setup the port env vars before calling Driver.Start, so Prestart should populate that.
Also make NOMAD_ADDR_* use host ip:port for consistency. NOMAD_PORT_* varies based on port map and the driver IP isn't exposed as an env var as the only place it can be used is in script checks anyway.
82c89f0
to
fe3bb07
Compare
@dadgar Ready for round 2. |
client/driver/docker.go
Outdated
return resp, nil | ||
} | ||
|
||
func (d *DockerDriver) detectIP(c *docker.Container) (string, bool) { |
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.
Put a comment on what this does and the fields it returns
client/driver/docker.go
Outdated
d.logger.Printf("[ERROR] driver.docker: no network settings for container %s", c.ID) | ||
return "", false | ||
} | ||
ip, ipName := "", "" |
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.
Add blank spaces between blocks. Here and line 643
client/driver/env/env.go
Outdated
// buildNetworkEnv env vars in the given map. | ||
// | ||
// Auto: NOMAD_{IP,PORT,ADDR}_<label> | ||
// Host: NOMAD_HOST_{IP,PORT,ADDR}_<label> |
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.
Update comment
@@ -2430,6 +2450,12 @@ func (sc *ServiceCheck) Hash(serviceID string) string { | |||
return fmt.Sprintf("%x", h.Sum(nil)) | |||
} | |||
|
|||
const ( | |||
AddressModeAuto = "auto" |
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.
Comments
`NOMAD_DRIVER_IP_<label>` environment variable for use in script checks. | ||
|
||
The ports specified in the `port_map` are exposed via the | ||
`NOMAD_DRIVER_PORT_<label>` environment variables. Unlike the IP, ports are |
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.
Update
Looks like I accidently dropped them when combining env var listings in PR #2709
Looks like I accidently dropped them when combining env var listings in PR #2709
I'm going to lock this pull request because it has been closed for 120 days ⏳. This helps our maintainers find and focus on the active contributions. |
Summary
NOMAD_{HOST,DRIVER}_{ADDR,IP,PORT}_<label>
env varsservice.address_mode
to determine what IP to advertiseDriverNetwork
Ideally this would only need to be returned by Prestart, but Docker doesn't assign a container an IP until the container starts.
I could have implemented it such that Prestart returns PortMap and Start returns IP/AutoAdvertise, but here's why I didn't:
The last point raises an interesting question: Should I just create
Driver.Inspect
and have it return `DriverNetwork? TaskRunner would just call it as needed and we wouldn't need to persist DriverNetwork.Might make for a good followup PR.
NOMAD_{HOST,DRIVER}_{ADDR,IP,PORT}_<label>
env varsThis was the Cambrian explosion of networking env vars. My work revealed something interesting:
NOMAD_ADDR_<label>
isn't reliable. If aport_map
is set it concatenates the host IP with the driver port. This can only ever be right by pure happenstance.So I marked it as deprecated and introduced explicit env vars.
The big caveat here is that the DRIVER_IP (and therefore ADDR) env vars can't be populated until the driver returns them -- which right now only happens after Start. This makes it only really useful for script checks. Everything else happens before Start is called.
In theory if other drivers return an IP from Prestart then it would be available in Start (eg
args
interpolation).I tried to document this well, but it feels like a pretty big footgun.
service.address_mode
Turned out as we hoped!
auto
,host
, ordriver
whereauto
meanshost
unless you're using a Docker networking plugin.Checks always use host IP+Port as we discussed. A bit of a gotcha, but I think it's always the right choice. If it needs to be configurable for esoteric setups we can add that later.
Naming (Driver vs Plugin)
As always I'm willing to changes any names! That being said I went with driver everywhere as it just made sense. It's the network defined by the driver. I think using "plugin" right now would just leave people hunting around for what these "plugins" are -- or conflate it with Docker plugins which is kind of true now but would probably lead to confusion in the future?