Change:
If the content of is only could recognize the last option and is ignored. And user has to use to workaround the issue. But this format is valid actually and able to read correctly in golang and libc. Able to parse multiple options lines in correctly. Use in the host's file and then inside POD's , it would become No response Any version. N.A. Ubuntu 22.04 No response No response No response
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the label and provide further guidance. The label can be by org members by writing in a comment. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
/sig sig-node
The label(s) cannot be applied, because the repository doesn't have them. <detailsIn response to : /sig sig-node </details
/sig node
Seems this behaviour is introduced by you at , is it an expected behaviour or a bug?
are those options parsed and used correctly or one of both is ignored?
Others are ignored and online the last line is parsed by kubelet correctly.
and in a normal , does libc use all the options or ignore some and use only one?
I tried centos/ubuntu, both will append extra options to the options list and overwrite them if it already exists by the later settings. For instance, is the same as . But I still think the workaround looks a perfered format.
Yes, but it looks like a bug since kubelet's behavior is different.
I tried to fix it in But I am still not sure if this is a valid fix. I will wait for pr review comments or further confirmation about whether this is valid.
/sig network
EDITED The feature was by a long time ago by There is a design kubernetes/community. The PR does not follow the design per The KEP can be found in KEP
/remove-sig node
Previous discussion and interesting comment from
Just want to clarify that these two are not related --- the change does not follow the design.
Just have the book on my desktop. !
I think the book just said could write it as , but didn't mention is invalid. And since glibc/golang DNS resolve is able to recognize it correctly, should we consider it as a de-facto way that we should support?
what about muslc, does it support it? we have to support muslc too, a lot of busybox/alpine users can break
I did some initial test with busybox:1.34.1-musl. It supports multi options. for , it works with multi-options. ndots:1, ping will fail for .
/assign
I'm trying to understand this, how the options are merged if they are duplicated? the man page for is clear ,notation%20as%20per%20RFC%. for only says it seems that apply the same logic to handle conflict if I try with this only the last option is used (same for muslc and libc) if I have two different options in different lines then things start to get more complicated, because I can not test all possible options combinations and musl resolver is not compatible with glibc resolver , see I'm worried we can break musl based containers by assuming the host configuration, that is mostly libc based, will be compatible with the container. I think we should be conservative and document this behavior of the dns options, and ask users to merge the options in the same line, raise a warning of something too EDIT I see is suggesting to parse all options and merge them in one line :eyes:
Add a small warning in log maybe another option. We may document it with some details. This is a little aggressive way.
I still can't find any spec that says how this is SUPPOSED to work, and I share concerns that this is likely to break someone somewhere. Did someone encounter this in the wild? Does it REALLY make sense to copy ALL of the options from the host config? Does it make sense to copy ANY of them? Looking at the man page, they seem very specific and maybe we should just leave them alone. What does Docker do here?
I found that there is a logic to merging DNS options in the pod DNS spec generating process. So I followed the logic. If the pod is using with , the current kubelet will merge the node's last option line in with . I did a simple test in Centos 7.9 with docker 19.03.8 like below. keeps the options as is if no new DNS options. will overwrite the local DNS options. there are multi , docker will not merge them and keep them in one line.
Absent a real user who is really impacted by this, my inclination is to (again) do nothing. The risk of breakage is non-zero. The reward is zero (nobody is complaining, IIUC).
Hi, actually I am impacted by this (in production services) . And looks like I am not the first user who raise this, as other issues link to this thread.
Thanks for your input, I checked muslc and verified via code, muslc would parse all options if we write multiple line . So I don't think would break any user. Instead, it addresses the similar problem happens to muslc users as well.
OK. I am accepting it. Since libc's seem to do this anyway, I don't see why we should break it.
Many thanks

Discussion:
} } if fields[0] == "options" { <del> options = fields[1:] </del> <ins> options = appendOptions(options, fields[1:]...) </ins> } }

return options } <ins> // appendOptions appends options to the given list, but does not add duplicates. // append option will overwrite the previous one either in new line or in the same line. func appendOptions(options []string, newOption ...string) []string { var optionMap = make(map[string]string) for _, option := range options { optName := strings.Split(option, ":")[0] optionMap[optName] = option } for _, option := range newOption { optName := strings.Split(option, ":")[0] optionMap[optName] = option } options = []string{} for _, v := range optionMap { options = append(options, v) } return options } </ins> // appendDNSConfig appends DNS servers, search paths and options given by // PodDNSConfig to the existing DNS config. Duplicated entries will be merged. // This assumes existingDNSConfig and dnsConfig are not nil.

{"#commentnnameserver 1.2.3.4n#commentnsearch fooncomment", []string{"1.2.3.4"}, []string{"foo"}, []string{}, false}, {"options ", []string{}, []string{}, []string{}, false}, {"options ndots:5 attempts:2", []string{}, []string{}, []string{"ndots:5", "attempts:2"}, false}, <ins> {"options ndots:1 ndots:5 attempts:2", []string{}, []string{}, []string{"ndots:5", "attempts:2"}, false}, {"options ndots:1 edns0 attempts:2 single-request-reopen", []string{}, []string{}, []string{"edns0", "attempts:2", "single-request-reopen", "ndots:1"}, false}, </ins> {"options ndots:1noptions ndots:5 attempts:3", []string{}, []string{}, []string{"ndots:5", "attempts:3"}, false}, <ins> {"options ndots:1 timeout:3 timeout:1 attempts:3noptions ndots:5", []string{}, []string{}, []string{"ndots:5", "timeout:1", "attempts:3"}, false}, {"options ndots:1 attempts:3noptions ndots:1 attempts:3 ndots:5", []string{}, []string{}, []string{"ndots:5", "attempts:3"}, false}, </ins> {"nameserver 1.2.3.4nsearch foonnameserver 5.6.7.8nsearch barnoptions ndots:5 attempts:4", []string{"1.2.3.4", "5.6.7.8"}, []string{"bar"}, []string{"ndots:5", "attempts:4"}, false}, } for i, tc := range testCases {

require.NoError(t, err) assert.EqualValues(t, tc.nameservers, ns, "test case [%d]: name servers", i) assert.EqualValues(t, tc.searches, srch, "test case [%d] searches", i) <del> assert.EqualValues(t, tc.options, opts, "test case [%d] options", i) </del> <ins> assert.EqualValues(t, sets.NewString(tc.options...), sets.NewString(opts...), "test case [%d] options", i) </ins> } else { require.Error(t, err, "tc.searches %v", tc.searches) }