Add custom DNS settings to service definition
| ... | ... |
@@ -7,6 +7,20 @@ import ( |
| 7 | 7 |
"github.com/docker/docker/api/types/mount" |
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 |
+// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) |
|
| 11 |
+// Detailed documentation is available in: |
|
| 12 |
+// http://man7.org/linux/man-pages/man5/resolv.conf.5.html |
|
| 13 |
+// `nameserver`, `search`, `options` have been supported. |
|
| 14 |
+// TODO: `domain` is not supported yet. |
|
| 15 |
+type DNSConfig struct {
|
|
| 16 |
+ // Nameservers specifies the IP addresses of the name servers |
|
| 17 |
+ Nameservers []string `json:",omitempty"` |
|
| 18 |
+ // Search specifies the search list for host-name lookup |
|
| 19 |
+ Search []string `json:",omitempty"` |
|
| 20 |
+ // Options allows certain internal resolver variables to be modified |
|
| 21 |
+ Options []string `json:",omitempty"` |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 10 | 24 |
// ContainerSpec represents the spec of a container. |
| 11 | 25 |
type ContainerSpec struct {
|
| 12 | 26 |
Image string `json:",omitempty"` |
| ... | ... |
@@ -22,4 +36,5 @@ type ContainerSpec struct {
|
| 22 | 22 |
Mounts []mount.Mount `json:",omitempty"` |
| 23 | 23 |
StopGracePeriod *time.Duration `json:",omitempty"` |
| 24 | 24 |
Healthcheck *container.HealthConfig `json:",omitempty"` |
| 25 |
+ DNSConfig *DNSConfig `json:",omitempty"` |
|
| 25 | 26 |
} |
| ... | ... |
@@ -41,6 +41,9 @@ func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 41 | 41 |
flags.StringSliceVar(&opts.networks, flagNetwork, []string{}, "Network attachments")
|
| 42 | 42 |
flags.VarP(&opts.endpoint.ports, flagPublish, "p", "Publish a port as a node port") |
| 43 | 43 |
flags.StringSliceVar(&opts.groups, flagGroup, []string{}, "Set one or more supplementary user groups for the container")
|
| 44 |
+ flags.Var(&opts.dns, flagDNS, "Set custom DNS servers") |
|
| 45 |
+ flags.Var(&opts.dnsOptions, flagDNSOptions, "Set DNS options") |
|
| 46 |
+ flags.Var(&opts.dnsSearch, flagDNSSearch, "Set custom DNS search domains") |
|
| 44 | 47 |
|
| 45 | 48 |
flags.SetInterspersed(false) |
| 46 | 49 |
return cmd |
| ... | ... |
@@ -296,6 +296,9 @@ type serviceOptions struct {
|
| 296 | 296 |
groups []string |
| 297 | 297 |
tty bool |
| 298 | 298 |
mounts opts.MountOpt |
| 299 |
+ dns opts.ListOpts |
|
| 300 |
+ dnsSearch opts.ListOpts |
|
| 301 |
+ dnsOptions opts.ListOpts |
|
| 299 | 302 |
|
| 300 | 303 |
resources resourceOptions |
| 301 | 304 |
stopGrace DurationOpt |
| ... | ... |
@@ -325,7 +328,10 @@ func newServiceOptions() *serviceOptions {
|
| 325 | 325 |
endpoint: endpointOptions{
|
| 326 | 326 |
ports: opts.NewListOpts(ValidatePort), |
| 327 | 327 |
}, |
| 328 |
- logDriver: newLogDriverOptions(), |
|
| 328 |
+ logDriver: newLogDriverOptions(), |
|
| 329 |
+ dns: opts.NewListOpts(opts.ValidateIPAddress), |
|
| 330 |
+ dnsOptions: opts.NewListOpts(nil), |
|
| 331 |
+ dnsSearch: opts.NewListOpts(opts.ValidateDNSSearch), |
|
| 329 | 332 |
} |
| 330 | 333 |
} |
| 331 | 334 |
|
| ... | ... |
@@ -358,16 +364,21 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
| 358 | 358 |
}, |
| 359 | 359 |
TaskTemplate: swarm.TaskSpec{
|
| 360 | 360 |
ContainerSpec: swarm.ContainerSpec{
|
| 361 |
- Image: opts.image, |
|
| 362 |
- Args: opts.args, |
|
| 363 |
- Env: currentEnv, |
|
| 364 |
- Hostname: opts.hostname, |
|
| 365 |
- Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()), |
|
| 366 |
- Dir: opts.workdir, |
|
| 367 |
- User: opts.user, |
|
| 368 |
- Groups: opts.groups, |
|
| 369 |
- TTY: opts.tty, |
|
| 370 |
- Mounts: opts.mounts.Value(), |
|
| 361 |
+ Image: opts.image, |
|
| 362 |
+ Args: opts.args, |
|
| 363 |
+ Env: currentEnv, |
|
| 364 |
+ Hostname: opts.hostname, |
|
| 365 |
+ Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()), |
|
| 366 |
+ Dir: opts.workdir, |
|
| 367 |
+ User: opts.user, |
|
| 368 |
+ Groups: opts.groups, |
|
| 369 |
+ TTY: opts.tty, |
|
| 370 |
+ Mounts: opts.mounts.Value(), |
|
| 371 |
+ DNSConfig: &swarm.DNSConfig{
|
|
| 372 |
+ Nameservers: opts.dns.GetAll(), |
|
| 373 |
+ Search: opts.dnsSearch.GetAll(), |
|
| 374 |
+ Options: opts.dnsOptions.GetAll(), |
|
| 375 |
+ }, |
|
| 371 | 376 |
StopGracePeriod: opts.stopGrace.Value(), |
| 372 | 377 |
}, |
| 373 | 378 |
Networks: convertNetworks(opts.networks), |
| ... | ... |
@@ -463,6 +474,15 @@ const ( |
| 463 | 463 |
flagContainerLabel = "container-label" |
| 464 | 464 |
flagContainerLabelRemove = "container-label-rm" |
| 465 | 465 |
flagContainerLabelAdd = "container-label-add" |
| 466 |
+ flagDNS = "dns" |
|
| 467 |
+ flagDNSRemove = "dns-rm" |
|
| 468 |
+ flagDNSAdd = "dns-add" |
|
| 469 |
+ flagDNSOptions = "dns-options" |
|
| 470 |
+ flagDNSOptionsRemove = "dns-options-rm" |
|
| 471 |
+ flagDNSOptionsAdd = "dns-options-add" |
|
| 472 |
+ flagDNSSearch = "dns-search" |
|
| 473 |
+ flagDNSSearchRemove = "dns-search-rm" |
|
| 474 |
+ flagDNSSearchAdd = "dns-search-add" |
|
| 466 | 475 |
flagEndpointMode = "endpoint-mode" |
| 467 | 476 |
flagHostname = "hostname" |
| 468 | 477 |
flagEnv = "env" |
| ... | ... |
@@ -48,6 +48,9 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 48 | 48 |
flags.Var(newListOptsVar(), flagMountRemove, "Remove a mount by its target path") |
| 49 | 49 |
flags.Var(newListOptsVar(), flagPublishRemove, "Remove a published port by its target port") |
| 50 | 50 |
flags.Var(newListOptsVar(), flagConstraintRemove, "Remove a constraint") |
| 51 |
+ flags.Var(newListOptsVar(), flagDNSRemove, "Remove custom DNS servers") |
|
| 52 |
+ flags.Var(newListOptsVar(), flagDNSOptionsRemove, "Remove DNS options") |
|
| 53 |
+ flags.Var(newListOptsVar(), flagDNSSearchRemove, "Remove DNS search domains") |
|
| 51 | 54 |
flags.Var(&opts.labels, flagLabelAdd, "Add or update a service label") |
| 52 | 55 |
flags.Var(&opts.containerLabels, flagContainerLabelAdd, "Add or update a container label") |
| 53 | 56 |
flags.Var(&opts.env, flagEnvAdd, "Add or update an environment variable") |
| ... | ... |
@@ -55,6 +58,10 @@ func newUpdateCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 55 | 55 |
flags.StringSliceVar(&opts.constraints, flagConstraintAdd, []string{}, "Add or update a placement constraint")
|
| 56 | 56 |
flags.Var(&opts.endpoint.ports, flagPublishAdd, "Add or update a published port") |
| 57 | 57 |
flags.StringSliceVar(&opts.groups, flagGroupAdd, []string{}, "Add an additional supplementary user group to the container")
|
| 58 |
+ flags.Var(&opts.dns, flagDNSAdd, "Add or update custom DNS servers") |
|
| 59 |
+ flags.Var(&opts.dnsOptions, flagDNSOptionsAdd, "Add or update DNS options") |
|
| 60 |
+ flags.Var(&opts.dnsSearch, flagDNSSearchAdd, "Add or update custom DNS search domains") |
|
| 61 |
+ |
|
| 58 | 62 |
return cmd |
| 59 | 63 |
} |
| 60 | 64 |
|
| ... | ... |
@@ -257,6 +264,15 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
|
| 257 | 257 |
} |
| 258 | 258 |
} |
| 259 | 259 |
|
| 260 |
+ if anyChanged(flags, flagDNSAdd, flagDNSRemove, flagDNSOptionsAdd, flagDNSOptionsRemove, flagDNSSearchAdd, flagDNSSearchRemove) {
|
|
| 261 |
+ if cspec.DNSConfig == nil {
|
|
| 262 |
+ cspec.DNSConfig = &swarm.DNSConfig{}
|
|
| 263 |
+ } |
|
| 264 |
+ if err := updateDNSConfig(flags, &cspec.DNSConfig); err != nil {
|
|
| 265 |
+ return err |
|
| 266 |
+ } |
|
| 267 |
+ } |
|
| 268 |
+ |
|
| 260 | 269 |
if err := updateLogDriver(flags, &spec.TaskTemplate); err != nil {
|
| 261 | 270 |
return err |
| 262 | 271 |
} |
| ... | ... |
@@ -484,6 +500,71 @@ func updateGroups(flags *pflag.FlagSet, groups *[]string) error {
|
| 484 | 484 |
return nil |
| 485 | 485 |
} |
| 486 | 486 |
|
| 487 |
+func removeDuplicates(entries []string) []string {
|
|
| 488 |
+ hit := map[string]bool{}
|
|
| 489 |
+ newEntries := []string{}
|
|
| 490 |
+ for _, v := range entries {
|
|
| 491 |
+ if !hit[v] {
|
|
| 492 |
+ newEntries = append(newEntries, v) |
|
| 493 |
+ hit[v] = true |
|
| 494 |
+ } |
|
| 495 |
+ } |
|
| 496 |
+ return newEntries |
|
| 497 |
+} |
|
| 498 |
+ |
|
| 499 |
+func updateDNSConfig(flags *pflag.FlagSet, config **swarm.DNSConfig) error {
|
|
| 500 |
+ newConfig := &swarm.DNSConfig{}
|
|
| 501 |
+ |
|
| 502 |
+ nameservers := (*config).Nameservers |
|
| 503 |
+ if flags.Changed(flagDNSAdd) {
|
|
| 504 |
+ values := flags.Lookup(flagDNSAdd).Value.(*opts.ListOpts).GetAll() |
|
| 505 |
+ nameservers = append(nameservers, values...) |
|
| 506 |
+ } |
|
| 507 |
+ nameservers = removeDuplicates(nameservers) |
|
| 508 |
+ toRemove := buildToRemoveSet(flags, flagDNSRemove) |
|
| 509 |
+ for _, nameserver := range nameservers {
|
|
| 510 |
+ if _, exists := toRemove[nameserver]; !exists {
|
|
| 511 |
+ newConfig.Nameservers = append(newConfig.Nameservers, nameserver) |
|
| 512 |
+ |
|
| 513 |
+ } |
|
| 514 |
+ } |
|
| 515 |
+ // Sort so that result is predictable. |
|
| 516 |
+ sort.Strings(newConfig.Nameservers) |
|
| 517 |
+ |
|
| 518 |
+ search := (*config).Search |
|
| 519 |
+ if flags.Changed(flagDNSSearchAdd) {
|
|
| 520 |
+ values := flags.Lookup(flagDNSSearchAdd).Value.(*opts.ListOpts).GetAll() |
|
| 521 |
+ search = append(search, values...) |
|
| 522 |
+ } |
|
| 523 |
+ search = removeDuplicates(search) |
|
| 524 |
+ toRemove = buildToRemoveSet(flags, flagDNSSearchRemove) |
|
| 525 |
+ for _, entry := range search {
|
|
| 526 |
+ if _, exists := toRemove[entry]; !exists {
|
|
| 527 |
+ newConfig.Search = append(newConfig.Search, entry) |
|
| 528 |
+ } |
|
| 529 |
+ } |
|
| 530 |
+ // Sort so that result is predictable. |
|
| 531 |
+ sort.Strings(newConfig.Search) |
|
| 532 |
+ |
|
| 533 |
+ options := (*config).Options |
|
| 534 |
+ if flags.Changed(flagDNSOptionsAdd) {
|
|
| 535 |
+ values := flags.Lookup(flagDNSOptionsAdd).Value.(*opts.ListOpts).GetAll() |
|
| 536 |
+ options = append(options, values...) |
|
| 537 |
+ } |
|
| 538 |
+ options = removeDuplicates(options) |
|
| 539 |
+ toRemove = buildToRemoveSet(flags, flagDNSOptionsRemove) |
|
| 540 |
+ for _, option := range options {
|
|
| 541 |
+ if _, exists := toRemove[option]; !exists {
|
|
| 542 |
+ newConfig.Options = append(newConfig.Options, option) |
|
| 543 |
+ } |
|
| 544 |
+ } |
|
| 545 |
+ // Sort so that result is predictable. |
|
| 546 |
+ sort.Strings(newConfig.Options) |
|
| 547 |
+ |
|
| 548 |
+ *config = newConfig |
|
| 549 |
+ return nil |
|
| 550 |
+} |
|
| 551 |
+ |
|
| 487 | 552 |
type byPortConfig []swarm.PortConfig |
| 488 | 553 |
|
| 489 | 554 |
func (r byPortConfig) Len() int { return len(r) }
|
| ... | ... |
@@ -120,6 +120,52 @@ func TestUpdateGroups(t *testing.T) {
|
| 120 | 120 |
assert.Equal(t, groups[2], "wheel") |
| 121 | 121 |
} |
| 122 | 122 |
|
| 123 |
+func TestUpdateDNSConfig(t *testing.T) {
|
|
| 124 |
+ flags := newUpdateCommand(nil).Flags() |
|
| 125 |
+ |
|
| 126 |
+ // IPv4, with duplicates |
|
| 127 |
+ flags.Set("dns-add", "1.1.1.1")
|
|
| 128 |
+ flags.Set("dns-add", "1.1.1.1")
|
|
| 129 |
+ flags.Set("dns-add", "2.2.2.2")
|
|
| 130 |
+ flags.Set("dns-rm", "3.3.3.3")
|
|
| 131 |
+ flags.Set("dns-rm", "2.2.2.2")
|
|
| 132 |
+ // IPv6 |
|
| 133 |
+ flags.Set("dns-add", "2001:db8:abc8::1")
|
|
| 134 |
+ // Invalid dns record |
|
| 135 |
+ assert.Error(t, flags.Set("dns-add", "x.y.z.w"), "x.y.z.w is not an ip address")
|
|
| 136 |
+ |
|
| 137 |
+ // domains with duplicates |
|
| 138 |
+ flags.Set("dns-search-add", "example.com")
|
|
| 139 |
+ flags.Set("dns-search-add", "example.com")
|
|
| 140 |
+ flags.Set("dns-search-add", "example.org")
|
|
| 141 |
+ flags.Set("dns-search-rm", "example.org")
|
|
| 142 |
+ // Invalid dns search domain |
|
| 143 |
+ assert.Error(t, flags.Set("dns-search-add", "example$com"), "example$com is not a valid domain")
|
|
| 144 |
+ |
|
| 145 |
+ flags.Set("dns-options-add", "ndots:9")
|
|
| 146 |
+ flags.Set("dns-options-rm", "timeout:3")
|
|
| 147 |
+ |
|
| 148 |
+ config := &swarm.DNSConfig{
|
|
| 149 |
+ Nameservers: []string{"3.3.3.3", "5.5.5.5"},
|
|
| 150 |
+ Search: []string{"localdomain"},
|
|
| 151 |
+ Options: []string{"timeout:3"},
|
|
| 152 |
+ } |
|
| 153 |
+ |
|
| 154 |
+ updateDNSConfig(flags, &config) |
|
| 155 |
+ |
|
| 156 |
+ assert.Equal(t, len(config.Nameservers), 3) |
|
| 157 |
+ assert.Equal(t, config.Nameservers[0], "1.1.1.1") |
|
| 158 |
+ assert.Equal(t, config.Nameservers[1], "2001:db8:abc8::1") |
|
| 159 |
+ assert.Equal(t, config.Nameservers[2], "5.5.5.5") |
|
| 160 |
+ |
|
| 161 |
+ assert.Equal(t, len(config.Search), 2) |
|
| 162 |
+ assert.Equal(t, config.Search[0], "example.com") |
|
| 163 |
+ assert.Equal(t, config.Search[1], "localdomain") |
|
| 164 |
+ |
|
| 165 |
+ assert.Equal(t, len(config.Options), 1) |
|
| 166 |
+ assert.Equal(t, config.Options[0], "ndots:9") |
|
| 167 |
+} |
|
| 168 |
+ |
|
| 123 | 169 |
func TestUpdateMounts(t *testing.T) {
|
| 124 | 170 |
flags := newUpdateCommand(nil).Flags() |
| 125 | 171 |
flags.Set("mount-add", "type=volume,source=vol2,target=/toadd")
|
| ... | ... |
@@ -25,6 +25,14 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
|
| 25 | 25 |
TTY: c.TTY, |
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
+ if c.DNSConfig != nil {
|
|
| 29 |
+ containerSpec.DNSConfig = &types.DNSConfig{
|
|
| 30 |
+ Nameservers: c.DNSConfig.Nameservers, |
|
| 31 |
+ Search: c.DNSConfig.Search, |
|
| 32 |
+ Options: c.DNSConfig.Options, |
|
| 33 |
+ } |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 28 | 36 |
// Mounts |
| 29 | 37 |
for _, m := range c.Mounts {
|
| 30 | 38 |
mount := mounttypes.Mount{
|
| ... | ... |
@@ -81,6 +89,14 @@ func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
|
| 81 | 81 |
TTY: c.TTY, |
| 82 | 82 |
} |
| 83 | 83 |
|
| 84 |
+ if c.DNSConfig != nil {
|
|
| 85 |
+ containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{
|
|
| 86 |
+ Nameservers: c.DNSConfig.Nameservers, |
|
| 87 |
+ Search: c.DNSConfig.Search, |
|
| 88 |
+ Options: c.DNSConfig.Options, |
|
| 89 |
+ } |
|
| 90 |
+ } |
|
| 91 |
+ |
|
| 84 | 92 |
if c.StopGracePeriod != nil {
|
| 85 | 93 |
containerSpec.StopGracePeriod = ptypes.DurationProto(*c.StopGracePeriod) |
| 86 | 94 |
} |
| ... | ... |
@@ -327,6 +327,12 @@ func (c *containerConfig) hostConfig() *enginecontainer.HostConfig {
|
| 327 | 327 |
GroupAdd: c.spec().Groups, |
| 328 | 328 |
} |
| 329 | 329 |
|
| 330 |
+ if c.spec().DNSConfig != nil {
|
|
| 331 |
+ hc.DNS = c.spec().DNSConfig.Nameservers |
|
| 332 |
+ hc.DNSSearch = c.spec().DNSConfig.Search |
|
| 333 |
+ hc.DNSOptions = c.spec().DNSConfig.Options |
|
| 334 |
+ } |
|
| 335 |
+ |
|
| 330 | 336 |
if c.task.LogDriver != nil {
|
| 331 | 337 |
hc.LogConfig = enginecontainer.LogConfig{
|
| 332 | 338 |
Type: c.task.LogDriver.Name, |
| ... | ... |
@@ -169,6 +169,7 @@ This section lists each version from latest to oldest. Each listing includes a |
| 169 | 169 |
* `GET /info` now returns more structured information about security options. |
| 170 | 170 |
* The `HostConfig` field now includes `CpuCount` that represents the number of CPUs available for execution by the container. Windows daemon only. |
| 171 | 171 |
* `POST /services/create` and `POST /services/(id or name)/update` now accept the `TTY` parameter, which allocate a pseudo-TTY in container. |
| 172 |
+* `POST /services/create` and `POST /services/(id or name)/update` now accept the `DNSConfig` parameter, which specifies DNS related configurations in resolver configuration file (resolv.conf) through `Nameservers`, `Search`, and `Options`. |
|
| 172 | 173 |
|
| 173 | 174 |
### v1.24 API changes |
| 174 | 175 |
|
| ... | ... |
@@ -5114,7 +5114,12 @@ image](#create-an-image) section for more details. |
| 5114 | 5114 |
} |
| 5115 | 5115 |
], |
| 5116 | 5116 |
"User": "33", |
| 5117 |
- "TTY": false |
|
| 5117 |
+ "TTY": false, |
|
| 5118 |
+ "DNSConfig": {
|
|
| 5119 |
+ "Nameservers": ["8.8.8.8"], |
|
| 5120 |
+ "Search": ["example.org"], |
|
| 5121 |
+ "Options": ["timeout:3"] |
|
| 5122 |
+ } |
|
| 5118 | 5123 |
}, |
| 5119 | 5124 |
"LogDriver": {
|
| 5120 | 5125 |
"Name": "json-file", |
| ... | ... |
@@ -5209,6 +5214,11 @@ image](#create-an-image) section for more details. |
| 5209 | 5209 |
- **Options** - key/value map of driver specific options. |
| 5210 | 5210 |
- **StopGracePeriod** – Amount of time to wait for the container to terminate before |
| 5211 | 5211 |
forcefully killing it. |
| 5212 |
+ - **DNSConfig** – Specification for DNS related configurations in |
|
| 5213 |
+ resolver configuration file (resolv.conf). |
|
| 5214 |
+ - **Nameservers** – A list of the IP addresses of the name servers. |
|
| 5215 |
+ - **Search** – A search list for host-name lookup. |
|
| 5216 |
+ - **Options** – A list of internal resolver variables to be modified (e.g., `debug`, `ndots:3`, etc.). |
|
| 5212 | 5217 |
- **LogDriver** - Log configuration for containers created as part of the |
| 5213 | 5218 |
service. |
| 5214 | 5219 |
- **Name** - Name of the logging driver to use (`json-file`, `syslog`, |
| ... | ... |
@@ -5394,7 +5404,12 @@ image](#create-an-image) section for more details. |
| 5394 | 5394 |
"Args": [ |
| 5395 | 5395 |
"top" |
| 5396 | 5396 |
], |
| 5397 |
- "TTY": true |
|
| 5397 |
+ "TTY": true, |
|
| 5398 |
+ "DNSConfig": {
|
|
| 5399 |
+ "Nameservers": ["8.8.8.8"], |
|
| 5400 |
+ "Search": ["example.org"], |
|
| 5401 |
+ "Options": ["timeout:3"] |
|
| 5402 |
+ } |
|
| 5398 | 5403 |
}, |
| 5399 | 5404 |
"Resources": {
|
| 5400 | 5405 |
"Limits": {},
|
| ... | ... |
@@ -5460,6 +5475,11 @@ image](#create-an-image) section for more details. |
| 5460 | 5460 |
- **Options** - key/value map of driver specific options |
| 5461 | 5461 |
- **StopGracePeriod** – Amount of time to wait for the container to terminate before |
| 5462 | 5462 |
forcefully killing it. |
| 5463 |
+ - **DNSConfig** – Specification for DNS related configurations in |
|
| 5464 |
+ resolver configuration file (resolv.conf). |
|
| 5465 |
+ - **Nameservers** – A list of the IP addresses of the name servers. |
|
| 5466 |
+ - **Search** – A search list for host-name lookup. |
|
| 5467 |
+ - **Options** – A list of internal resolver variables to be modified (e.g., `debug`, `ndots:3`, etc.). |
|
| 5463 | 5468 |
- **Resources** – Resource requirements which apply to each individual container created as part |
| 5464 | 5469 |
of the service. |
| 5465 | 5470 |
- **Limits** – Define resources limits. |
| ... | ... |
@@ -23,6 +23,9 @@ Create a new service |
| 23 | 23 |
Options: |
| 24 | 24 |
--constraint value Placement constraints (default []) |
| 25 | 25 |
--container-label value Service container labels (default []) |
| 26 |
+ --dns list Set custom DNS servers (default []) |
|
| 27 |
+ --dns-options list Set DNS options (default []) |
|
| 28 |
+ --dns-search list Set custom DNS search domains (default []) |
|
| 26 | 29 |
--endpoint-mode string Endpoint mode (vip or dnsrr) |
| 27 | 30 |
-e, --env value Set environment variables (default []) |
| 28 | 31 |
--env-file value Read in a file of environment variables (default []) |
| ... | ... |
@@ -26,6 +26,12 @@ Options: |
| 26 | 26 |
--constraint-rm list Remove a constraint (default []) |
| 27 | 27 |
--container-label-add list Add or update a container label (default []) |
| 28 | 28 |
--container-label-rm list Remove a container label by its key (default []) |
| 29 |
+ --dns-add list Add or update custom DNS servers (default []) |
|
| 30 |
+ --dns-options-add list Add or update DNS options (default []) |
|
| 31 |
+ --dns-options-rm list Remove DNS options (default []) |
|
| 32 |
+ --dns-rm list Remove custom DNS servers (default []) |
|
| 33 |
+ --dns-search-add list Add or update custom DNS search domains (default []) |
|
| 34 |
+ --dns-search-rm list Remove DNS search domains (default []) |
|
| 29 | 35 |
--endpoint-mode string Endpoint mode (vip or dnsrr) |
| 30 | 36 |
--env-add list Add or update an environment variable (default []) |
| 31 | 37 |
--env-rm list Remove an environment variable (default []) |
| ... | ... |
@@ -789,3 +789,49 @@ func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) {
|
| 789 | 789 |
c.Assert(err, checker.IsNil) |
| 790 | 790 |
c.Assert(strings.TrimSpace(out), checker.Equals, "true") |
| 791 | 791 |
} |
| 792 |
+ |
|
| 793 |
+func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) {
|
|
| 794 |
+ d := s.AddDaemon(c, true, true) |
|
| 795 |
+ |
|
| 796 |
+ // Create a service |
|
| 797 |
+ name := "top" |
|
| 798 |
+ _, err := d.Cmd("service", "create", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-options=timeout:3", "busybox", "top")
|
|
| 799 |
+ c.Assert(err, checker.IsNil) |
|
| 800 |
+ |
|
| 801 |
+ // Make sure task has been deployed. |
|
| 802 |
+ waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) |
|
| 803 |
+ |
|
| 804 |
+ // We need to get the container id. |
|
| 805 |
+ out, err := d.Cmd("ps", "-a", "-q", "--no-trunc")
|
|
| 806 |
+ c.Assert(err, checker.IsNil) |
|
| 807 |
+ id := strings.TrimSpace(out) |
|
| 808 |
+ |
|
| 809 |
+ // Compare against expected output. |
|
| 810 |
+ expectedOutput1 := "nameserver 1.2.3.4" |
|
| 811 |
+ expectedOutput2 := "search example.com" |
|
| 812 |
+ expectedOutput3 := "options timeout:3" |
|
| 813 |
+ out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf")
|
|
| 814 |
+ c.Assert(err, checker.IsNil) |
|
| 815 |
+ c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out))
|
|
| 816 |
+ c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out))
|
|
| 817 |
+ c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out))
|
|
| 818 |
+} |
|
| 819 |
+ |
|
| 820 |
+func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) {
|
|
| 821 |
+ d := s.AddDaemon(c, true, true) |
|
| 822 |
+ |
|
| 823 |
+ // Create a service |
|
| 824 |
+ name := "top" |
|
| 825 |
+ _, err := d.Cmd("service", "create", "--name", name, "busybox", "top")
|
|
| 826 |
+ c.Assert(err, checker.IsNil) |
|
| 827 |
+ |
|
| 828 |
+ // Make sure task has been deployed. |
|
| 829 |
+ waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1) |
|
| 830 |
+ |
|
| 831 |
+ _, err = d.Cmd("service", "update", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-options-add=timeout:3", name)
|
|
| 832 |
+ c.Assert(err, checker.IsNil) |
|
| 833 |
+ |
|
| 834 |
+ out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name)
|
|
| 835 |
+ c.Assert(err, checker.IsNil) |
|
| 836 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}")
|
|
| 837 |
+} |