mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add custom DNS settings to service definition
This fix tries to fix the issue raised in 24391 about allowing custom DNS settings to service definition. This fix adds `DNSConfig` (`Nameservers`, `Options`, `Search`) to service definition, as well as `--dns`, `--dns-opt`, and `dns-search` to `service create`. An integration test has been added to cover the changes in this fix. This fix fixes 24391. A PR in swarmkit will be created separately. Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
parent
703dcbe579
commit
9e8adbecf5
7 changed files with 95 additions and 11 deletions
|
@ -7,6 +7,20 @@ import (
|
||||||
"github.com/docker/docker/api/types/mount"
|
"github.com/docker/docker/api/types/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf)
|
||||||
|
// Detailed documentation is available in:
|
||||||
|
// http://man7.org/linux/man-pages/man5/resolv.conf.5.html
|
||||||
|
// `nameserver`, `search`, `options` have been supported.
|
||||||
|
// TODO: `domain` is not supported yet.
|
||||||
|
type DNSConfig struct {
|
||||||
|
// Nameservers specifies the IP addresses of the name servers
|
||||||
|
Nameservers []string `json:",omitempty"`
|
||||||
|
// Search specifies the search list for host-name lookup
|
||||||
|
Search []string `json:",omitempty"`
|
||||||
|
// Options allows certain internal resolver variables to be modified
|
||||||
|
Options []string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// ContainerSpec represents the spec of a container.
|
// ContainerSpec represents the spec of a container.
|
||||||
type ContainerSpec struct {
|
type ContainerSpec struct {
|
||||||
Image string `json:",omitempty"`
|
Image string `json:",omitempty"`
|
||||||
|
@ -22,4 +36,5 @@ type ContainerSpec struct {
|
||||||
Mounts []mount.Mount `json:",omitempty"`
|
Mounts []mount.Mount `json:",omitempty"`
|
||||||
StopGracePeriod *time.Duration `json:",omitempty"`
|
StopGracePeriod *time.Duration `json:",omitempty"`
|
||||||
Healthcheck *container.HealthConfig `json:",omitempty"`
|
Healthcheck *container.HealthConfig `json:",omitempty"`
|
||||||
|
DNSConfig *DNSConfig `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,9 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
||||||
flags.StringSliceVar(&opts.networks, flagNetwork, []string{}, "Network attachments")
|
flags.StringSliceVar(&opts.networks, flagNetwork, []string{}, "Network attachments")
|
||||||
flags.VarP(&opts.endpoint.ports, flagPublish, "p", "Publish a port as a node port")
|
flags.VarP(&opts.endpoint.ports, flagPublish, "p", "Publish a port as a node port")
|
||||||
flags.StringSliceVar(&opts.groups, flagGroup, []string{}, "Set one or more supplementary user groups for the container")
|
flags.StringSliceVar(&opts.groups, flagGroup, []string{}, "Set one or more supplementary user groups for the container")
|
||||||
|
flags.Var(&opts.dns, flagDNS, "Set custom DNS servers")
|
||||||
|
flags.Var(&opts.dnsOptions, flagDNSOptions, "Set DNS options")
|
||||||
|
flags.Var(&opts.dnsSearch, flagDNSSearch, "Set custom DNS search domains")
|
||||||
|
|
||||||
flags.SetInterspersed(false)
|
flags.SetInterspersed(false)
|
||||||
return cmd
|
return cmd
|
||||||
|
|
|
@ -296,6 +296,9 @@ type serviceOptions struct {
|
||||||
groups []string
|
groups []string
|
||||||
tty bool
|
tty bool
|
||||||
mounts opts.MountOpt
|
mounts opts.MountOpt
|
||||||
|
dns opts.ListOpts
|
||||||
|
dnsSearch opts.ListOpts
|
||||||
|
dnsOptions opts.ListOpts
|
||||||
|
|
||||||
resources resourceOptions
|
resources resourceOptions
|
||||||
stopGrace DurationOpt
|
stopGrace DurationOpt
|
||||||
|
@ -325,7 +328,10 @@ func newServiceOptions() *serviceOptions {
|
||||||
endpoint: endpointOptions{
|
endpoint: endpointOptions{
|
||||||
ports: opts.NewListOpts(ValidatePort),
|
ports: opts.NewListOpts(ValidatePort),
|
||||||
},
|
},
|
||||||
logDriver: newLogDriverOptions(),
|
logDriver: newLogDriverOptions(),
|
||||||
|
dns: opts.NewListOpts(opts.ValidateIPAddress),
|
||||||
|
dnsOptions: opts.NewListOpts(nil),
|
||||||
|
dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,16 +364,21 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
||||||
},
|
},
|
||||||
TaskTemplate: swarm.TaskSpec{
|
TaskTemplate: swarm.TaskSpec{
|
||||||
ContainerSpec: swarm.ContainerSpec{
|
ContainerSpec: swarm.ContainerSpec{
|
||||||
Image: opts.image,
|
Image: opts.image,
|
||||||
Args: opts.args,
|
Args: opts.args,
|
||||||
Env: currentEnv,
|
Env: currentEnv,
|
||||||
Hostname: opts.hostname,
|
Hostname: opts.hostname,
|
||||||
Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()),
|
Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()),
|
||||||
Dir: opts.workdir,
|
Dir: opts.workdir,
|
||||||
User: opts.user,
|
User: opts.user,
|
||||||
Groups: opts.groups,
|
Groups: opts.groups,
|
||||||
TTY: opts.tty,
|
TTY: opts.tty,
|
||||||
Mounts: opts.mounts.Value(),
|
Mounts: opts.mounts.Value(),
|
||||||
|
DNSConfig: &swarm.DNSConfig{
|
||||||
|
Nameservers: opts.dns.GetAll(),
|
||||||
|
Search: opts.dnsSearch.GetAll(),
|
||||||
|
Options: opts.dnsOptions.GetAll(),
|
||||||
|
},
|
||||||
StopGracePeriod: opts.stopGrace.Value(),
|
StopGracePeriod: opts.stopGrace.Value(),
|
||||||
},
|
},
|
||||||
Networks: convertNetworks(opts.networks),
|
Networks: convertNetworks(opts.networks),
|
||||||
|
@ -463,6 +474,9 @@ const (
|
||||||
flagContainerLabel = "container-label"
|
flagContainerLabel = "container-label"
|
||||||
flagContainerLabelRemove = "container-label-rm"
|
flagContainerLabelRemove = "container-label-rm"
|
||||||
flagContainerLabelAdd = "container-label-add"
|
flagContainerLabelAdd = "container-label-add"
|
||||||
|
flagDNS = "dns"
|
||||||
|
flagDNSOptions = "dns-opt"
|
||||||
|
flagDNSSearch = "dns-search"
|
||||||
flagEndpointMode = "endpoint-mode"
|
flagEndpointMode = "endpoint-mode"
|
||||||
flagHostname = "hostname"
|
flagHostname = "hostname"
|
||||||
flagEnv = "env"
|
flagEnv = "env"
|
||||||
|
|
|
@ -25,6 +25,14 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
|
||||||
TTY: c.TTY,
|
TTY: c.TTY,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.DNSConfig != nil {
|
||||||
|
containerSpec.DNSConfig = &types.DNSConfig{
|
||||||
|
Nameservers: c.DNSConfig.Nameservers,
|
||||||
|
Search: c.DNSConfig.Search,
|
||||||
|
Options: c.DNSConfig.Options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Mounts
|
// Mounts
|
||||||
for _, m := range c.Mounts {
|
for _, m := range c.Mounts {
|
||||||
mount := mounttypes.Mount{
|
mount := mounttypes.Mount{
|
||||||
|
@ -81,6 +89,14 @@ func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
|
||||||
TTY: c.TTY,
|
TTY: c.TTY,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.DNSConfig != nil {
|
||||||
|
containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{
|
||||||
|
Nameservers: c.DNSConfig.Nameservers,
|
||||||
|
Search: c.DNSConfig.Search,
|
||||||
|
Options: c.DNSConfig.Options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.StopGracePeriod != nil {
|
if c.StopGracePeriod != nil {
|
||||||
containerSpec.StopGracePeriod = ptypes.DurationProto(*c.StopGracePeriod)
|
containerSpec.StopGracePeriod = ptypes.DurationProto(*c.StopGracePeriod)
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,6 +327,12 @@ func (c *containerConfig) hostConfig() *enginecontainer.HostConfig {
|
||||||
GroupAdd: c.spec().Groups,
|
GroupAdd: c.spec().Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.spec().DNSConfig != nil {
|
||||||
|
hc.DNS = c.spec().DNSConfig.Nameservers
|
||||||
|
hc.DNSSearch = c.spec().DNSConfig.Search
|
||||||
|
hc.DNSOptions = c.spec().DNSConfig.Options
|
||||||
|
}
|
||||||
|
|
||||||
if c.task.LogDriver != nil {
|
if c.task.LogDriver != nil {
|
||||||
hc.LogConfig = enginecontainer.LogConfig{
|
hc.LogConfig = enginecontainer.LogConfig{
|
||||||
Type: c.task.LogDriver.Name,
|
Type: c.task.LogDriver.Name,
|
||||||
|
|
|
@ -23,6 +23,9 @@ Create a new service
|
||||||
Options:
|
Options:
|
||||||
--constraint value Placement constraints (default [])
|
--constraint value Placement constraints (default [])
|
||||||
--container-label value Service container labels (default [])
|
--container-label value Service container labels (default [])
|
||||||
|
--dns list Set custom DNS servers (default [])
|
||||||
|
--dns-opt list Set DNS options (default [])
|
||||||
|
--dns-search list Set custom DNS search domains (default [])
|
||||||
--endpoint-mode string Endpoint mode (vip or dnsrr)
|
--endpoint-mode string Endpoint mode (vip or dnsrr)
|
||||||
-e, --env value Set environment variables (default [])
|
-e, --env value Set environment variables (default [])
|
||||||
--env-file value Read in a file of environment variables (default [])
|
--env-file value Read in a file of environment variables (default [])
|
||||||
|
|
|
@ -789,3 +789,30 @@ func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
c.Assert(strings.TrimSpace(out), checker.Equals, "true")
|
c.Assert(strings.TrimSpace(out), checker.Equals, "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) {
|
||||||
|
d := s.AddDaemon(c, true, true)
|
||||||
|
|
||||||
|
// Create a service
|
||||||
|
name := "top"
|
||||||
|
_, err := d.Cmd("service", "create", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-opt=timeout:3", "busybox", "top")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
// Make sure task has been deployed.
|
||||||
|
waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
|
||||||
|
|
||||||
|
// We need to get the container id.
|
||||||
|
out, err := d.Cmd("ps", "-a", "-q", "--no-trunc")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
id := strings.TrimSpace(out)
|
||||||
|
|
||||||
|
// Compare against expected output.
|
||||||
|
expectedOutput1 := "nameserver 1.2.3.4"
|
||||||
|
expectedOutput2 := "search example.com"
|
||||||
|
expectedOutput3 := "options timeout:3"
|
||||||
|
out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out))
|
||||||
|
c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out))
|
||||||
|
c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out))
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue