Give a container the names, rather than a resolver to ask
The commit before this said "told where to resolve names" and passed --dns, which is not what it ended up doing. This is that correction: a container is given the names themselves, written into its own hosts file by the runtime. The reason for the change is the decision the mesh already made about names — a file rather than a resolver, because it works on every runtime, needs no package and has no failure mode of its own. Passing a resolver address would have required a resolver to exist, which at that point none did. A resolver is coming, for the case a file genuinely cannot express: a service named under a machine, postgres.novox.internal, where the wildcard cannot be enumerated in advance. When it arrives it will need this field back under its own name. It is not being kept in the meantime — a field nothing fills is a field nobody can trust, and the vocabulary is asserted by a count for exactly that reason.
This commit is contained in:
@@ -812,12 +812,12 @@ func applyContainer(ctx context.Context, r *declaration.Container, run Runner) (
|
|||||||
for _, v := range r.Volumes {
|
for _, v := range r.Volumes {
|
||||||
args = append(args, "--volume", v)
|
args = append(args, "--volume", v)
|
||||||
}
|
}
|
||||||
for _, n := range r.Nameservers {
|
for _, h := range r.Hosts {
|
||||||
// Per container rather than by changing the machine's resolver configuration. That file
|
// Written into the container's own hosts file by the runtime. Per container rather than
|
||||||
// belongs to something else on most machines, and a host that edited it would be fighting
|
// by editing the machine's resolver configuration: that file belongs to something else on
|
||||||
// whatever owns it on every boot — the fault this host exists to avoid, in the one place
|
// most machines, and a host that edited it would be fighting whatever owns it on every
|
||||||
// it would be hardest to see.
|
// boot — the fault this host exists to avoid, in the place it would be hardest to see.
|
||||||
args = append(args, "--dns", n)
|
args = append(args, "--add-host", h)
|
||||||
}
|
}
|
||||||
args = append(args, r.Image)
|
args = append(args, r.Image)
|
||||||
args = append(args, r.Args...)
|
args = append(args, r.Args...)
|
||||||
|
|||||||
@@ -1231,7 +1231,7 @@ func TestAFailedActionStopsWhatFollows(t *testing.T) {
|
|||||||
// `resolv.conf` — so every internal name the mesh wrote for the machine is invisible to what the
|
// `resolv.conf` — so every internal name the mesh wrote for the machine is invisible to what the
|
||||||
// machine is running. That was hit for real: a database client on one node could not resolve
|
// machine is running. That was hit for real: a database client on one node could not resolve
|
||||||
// another node, on a mesh where both names were correct and present on both machines.
|
// another node, on a mesh where both names were correct and present on both machines.
|
||||||
func TestAContainerIsToldWhichResolverToUse(t *testing.T) {
|
func TestAContainerIsGivenTheMeshsNames(t *testing.T) {
|
||||||
var ran []string
|
var ran []string
|
||||||
run := func(_ context.Context, name string, args ...string) (string, error) {
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
||||||
if name != "docker" {
|
if name != "docker" {
|
||||||
@@ -1250,25 +1250,23 @@ func TestAContainerIsToldWhichResolverToUse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
d := parseTrusted(t, `{"declaration":1,"resources":[
|
d := parseTrusted(t, `{"declaration":1,"resources":[
|
||||||
{"id":"app","type":"container","name":"app","image":"`+pinned+`",
|
{"id":"app","type":"container","name":"app","image":"`+pinned+`",
|
||||||
"nameservers":["10.42.0.1"]}
|
"hosts":["anchor.internal:10.42.0.1"]}
|
||||||
]}`)
|
]}`)
|
||||||
_, _, _ = Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil)
|
_, _, _ = Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil)
|
||||||
|
|
||||||
var told bool
|
var told bool
|
||||||
for i, a := range ran {
|
for i, a := range ran {
|
||||||
if a == "--dns" && i+1 < len(ran) && ran[i+1] == "10.42.0.1" {
|
if a == "--add-host" && i+1 < len(ran) && ran[i+1] == "anchor.internal:10.42.0.1" {
|
||||||
told = true
|
told = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !told {
|
if !told {
|
||||||
t.Fatalf("the container was not told where to resolve names: %v", ran)
|
t.Fatalf("the container cannot reach another machine by name: %v", ran)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// And a container that was told nothing is run exactly as before: most containers resolve
|
// And a container given no names is run exactly as before.
|
||||||
// whatever the machine resolves, and passing an empty flag would be a change of behaviour
|
func TestAContainerGivenNoNamesIsRunAsBefore(t *testing.T) {
|
||||||
// dressed as a default.
|
|
||||||
func TestAContainerToldNothingIsRunAsBefore(t *testing.T) {
|
|
||||||
var ran []string
|
var ran []string
|
||||||
run := func(_ context.Context, name string, args ...string) (string, error) {
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
||||||
if name != "docker" {
|
if name != "docker" {
|
||||||
@@ -1291,8 +1289,8 @@ func TestAContainerToldNothingIsRunAsBefore(t *testing.T) {
|
|||||||
_, _, _ = Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil)
|
_, _, _ = Apply(context.Background(), archHost(t), d, store.State{}, store.OriginCarried, run, nil, nil)
|
||||||
|
|
||||||
for _, a := range ran {
|
for _, a := range ran {
|
||||||
if a == "--dns" {
|
if a == "--add-host" {
|
||||||
t.Fatalf("a container that was told nothing was given a resolver anyway: %v", ran)
|
t.Fatalf("a container given no names was given some anyway: %v", ran)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -328,18 +328,22 @@ type Container struct {
|
|||||||
Ports []string `json:"ports,omitempty"`
|
Ports []string `json:"ports,omitempty"`
|
||||||
Volumes []string `json:"volumes,omitempty"`
|
Volumes []string `json:"volumes,omitempty"`
|
||||||
Args []string `json:"args,omitempty"`
|
Args []string `json:"args,omitempty"`
|
||||||
// Nameservers this container resolves through.
|
// Names this container can reach, as `name:address`.
|
||||||
//
|
//
|
||||||
// **Because a container does not inherit the machine's names.** It gets its own `/etc/hosts`
|
// **Because a container does not inherit the machine's names.** It gets its own `/etc/hosts`
|
||||||
// holding its own hostname, and a runtime rewrites `resolv.conf` — so every internal name the
|
// holding only its own hostname, so every internal name the mesh wrote for this machine is
|
||||||
// mesh wrote for this machine is invisible to the thing the machine is running. That was hit
|
// invisible to the thing the machine is running. That was hit for real: a database client on
|
||||||
// for real: a database client on one node could not resolve another node, on a mesh where
|
// one node could not resolve another node, on a mesh where both names were correct and
|
||||||
// both names were correct and present.
|
// present on both machines.
|
||||||
//
|
//
|
||||||
// Set by the mesh rather than by a module: which resolver a machine has is a fact about the
|
// **A file rather than a resolver, which is the decision the mesh already made about names**
|
||||||
// machine, and a module that named one would be a module that only runs where somebody put
|
// and this extends rather than overturns: it works on every runtime, needs no package, and
|
||||||
// that resolver.
|
// has no failure mode of its own. A resolver becomes necessary when names are wanted that are
|
||||||
Nameservers []string `json:"nameservers,omitempty"`
|
// not one-per-node — service names, wildcards — and that is still not true.
|
||||||
|
//
|
||||||
|
// Set by the mesh, not by a module: which machines exist is a fact about the mesh, and a
|
||||||
|
// module that listed them would be a module that goes stale when one joins.
|
||||||
|
Hosts []string `json:"hosts,omitempty"`
|
||||||
|
|
||||||
// Network is the container's network, passed to the runtime unchanged.
|
// Network is the container's network, passed to the runtime unchanged.
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user