Added ability for Docker containers to set usage of dns settings along with hostNetwork is true

Introduced chages:
   1. Re-writing of the resolv.conf file generated by docker.
      Cluster dns settings aren't passed anymore to docker api in all cases, not only for pods with host network:
      the resolver conf will be overwritten after infra-container creation to override docker's behaviour.

   2. Added new one dnsPolicy - 'ClusterFirstWithHostNet', so now there are:
      - ClusterFirstWithHostNet - use dns settings in all cases, i.e. with hostNet=true as well
      - ClusterFirst - use dns settings unless hostNetwork is true
      - Default

Fixes #17406
This commit is contained in:
vefimova 2016-08-05 03:19:17 -05:00
parent c7b53794d0
commit fc8a37ec86
31 changed files with 146 additions and 80 deletions

View File

@ -39466,7 +39466,7 @@
} }
}, },
"dnsPolicy": { "dnsPolicy": {
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\".", "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.",
"type": "string" "type": "string"
}, },
"hostIPC": { "hostIPC": {

View File

@ -1303,7 +1303,7 @@
}, },
"dnsPolicy": { "dnsPolicy": {
"type": "string", "type": "string",
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\"." "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'."
}, },
"nodeSelector": { "nodeSelector": {
"type": "object", "type": "object",

View File

@ -2542,7 +2542,7 @@
}, },
"dnsPolicy": { "dnsPolicy": {
"type": "string", "type": "string",
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\"." "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'."
}, },
"nodeSelector": { "nodeSelector": {
"type": "object", "type": "object",

View File

@ -1325,7 +1325,7 @@
}, },
"dnsPolicy": { "dnsPolicy": {
"type": "string", "type": "string",
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\"." "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'."
}, },
"nodeSelector": { "nodeSelector": {
"type": "object", "type": "object",

View File

@ -6789,7 +6789,7 @@
}, },
"dnsPolicy": { "dnsPolicy": {
"type": "string", "type": "string",
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\"." "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'."
}, },
"nodeSelector": { "nodeSelector": {
"type": "object", "type": "object",

View File

@ -18628,7 +18628,7 @@
}, },
"dnsPolicy": { "dnsPolicy": {
"type": "string", "type": "string",
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\"." "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'."
}, },
"nodeSelector": { "nodeSelector": {
"type": "object", "type": "object",

View File

@ -3568,7 +3568,7 @@ The StatefulSet guarantees that a given network identity will always map to the
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst".</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirstWithHostNet</em>, <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to <em>ClusterFirstWithHostNet</em>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>
@ -6152,7 +6152,7 @@ Examples:<br>
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-text"> <div id="footer-text">
Last updated 2017-03-01 11:37:39 UTC Last updated 2017-03-01 17:05:47 UTC
</div> </div>
</div> </div>
</body> </body>

View File

@ -4821,7 +4821,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst".</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirstWithHostNet</em>, <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to <em>ClusterFirstWithHostNet</em>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>

View File

@ -4359,7 +4359,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst".</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirstWithHostNet</em>, <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to <em>ClusterFirstWithHostNet</em>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>

View File

@ -5086,7 +5086,7 @@ The resulting set of endpoints can be viewed as:<br>
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">dnsPolicy</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst".</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Set DNS policy for containers within the pod. One of <em>ClusterFirstWithHostNet</em>, <em>ClusterFirst</em> or <em>Default</em>. Defaults to "ClusterFirst". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to <em>ClusterFirstWithHostNet</em>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
<td class="tableblock halign-left valign-top"></td> <td class="tableblock halign-left valign-top"></td>

View File

@ -12626,7 +12626,7 @@
} }
}, },
"dnsPolicy": { "dnsPolicy": {
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\".", "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.",
"type": "string" "type": "string"
}, },
"hostIPC": { "hostIPC": {

View File

@ -4595,7 +4595,7 @@
}, },
"dnsPolicy": { "dnsPolicy": {
"type": "string", "type": "string",
"description": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\"." "description": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'."
}, },
"nodeSelector": { "nodeSelector": {
"type": "object", "type": "object",

View File

@ -1679,9 +1679,14 @@ type PodList struct {
type DNSPolicy string type DNSPolicy string
const ( const (
// DNSClusterFirstWithHostNet indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default
// (as determined by kubelet) DNS settings.
DNSClusterFirstWithHostNet DNSPolicy = "ClusterFirstWithHostNet"
// DNSClusterFirst indicates that the pod should use cluster DNS // DNSClusterFirst indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default (as // first unless hostNetwork is true, if it is available, then
// determined by kubelet) DNS settings. // fall back on the default (as determined by kubelet) DNS settings.
DNSClusterFirst DNSPolicy = "ClusterFirst" DNSClusterFirst DNSPolicy = "ClusterFirst"
// DNSDefault indicates that the pod should use the default (as // DNSDefault indicates that the pod should use the default (as

View File

@ -2607,8 +2607,9 @@ message PodSpec {
optional int64 activeDeadlineSeconds = 5; optional int64 activeDeadlineSeconds = 5;
// Set DNS policy for containers within the pod. // Set DNS policy for containers within the pod.
// One of 'ClusterFirst' or 'Default'. // One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'.
// Defaults to "ClusterFirst". // Defaults to "ClusterFirst".
// To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.
// +optional // +optional
optional string dnsPolicy = 6; optional string dnsPolicy = 6;

View File

@ -1888,9 +1888,14 @@ const (
type DNSPolicy string type DNSPolicy string
const ( const (
// DNSClusterFirstWithHostNet indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default
// (as determined by kubelet) DNS settings.
DNSClusterFirstWithHostNet DNSPolicy = "ClusterFirstWithHostNet"
// DNSClusterFirst indicates that the pod should use cluster DNS // DNSClusterFirst indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default (as // first unless hostNetwork is true, if it is available, then
// determined by kubelet) DNS settings. // fall back on the default (as determined by kubelet) DNS settings.
DNSClusterFirst DNSPolicy = "ClusterFirst" DNSClusterFirst DNSPolicy = "ClusterFirst"
// DNSDefault indicates that the pod should use the default (as // DNSDefault indicates that the pod should use the default (as
@ -2245,8 +2250,9 @@ type PodSpec struct {
// +optional // +optional
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"` ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"`
// Set DNS policy for containers within the pod. // Set DNS policy for containers within the pod.
// One of 'ClusterFirst' or 'Default'. // One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'.
// Defaults to "ClusterFirst". // Defaults to "ClusterFirst".
// To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.
// +optional // +optional
DNSPolicy DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"` DNSPolicy DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"`
// NodeSelector is a selector which must be true for the pod to fit on a node. // NodeSelector is a selector which must be true for the pod to fit on a node.

View File

@ -1321,7 +1321,7 @@ var map_PodSpec = map[string]string{
"restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: http://kubernetes.io/docs/user-guide/pod-states#restartpolicy", "restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: http://kubernetes.io/docs/user-guide/pod-states#restartpolicy",
"terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.", "terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.",
"activeDeadlineSeconds": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.", "activeDeadlineSeconds": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.",
"dnsPolicy": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\".", "dnsPolicy": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.",
"nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://kubernetes.io/docs/user-guide/node-selection/README", "nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://kubernetes.io/docs/user-guide/node-selection/README",
"serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md", "serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md",
"serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.", "serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.",

View File

@ -1788,12 +1788,12 @@ func validateRestartPolicy(restartPolicy *api.RestartPolicy, fldPath *field.Path
func validateDNSPolicy(dnsPolicy *api.DNSPolicy, fldPath *field.Path) field.ErrorList { func validateDNSPolicy(dnsPolicy *api.DNSPolicy, fldPath *field.Path) field.ErrorList {
allErrors := field.ErrorList{} allErrors := field.ErrorList{}
switch *dnsPolicy { switch *dnsPolicy {
case api.DNSClusterFirst, api.DNSDefault: case api.DNSClusterFirstWithHostNet, api.DNSClusterFirst, api.DNSDefault:
break break
case "": case "":
allErrors = append(allErrors, field.Required(fldPath, "")) allErrors = append(allErrors, field.Required(fldPath, ""))
default: default:
validValues := []string{string(api.DNSClusterFirst), string(api.DNSDefault)} validValues := []string{string(api.DNSClusterFirstWithHostNet), string(api.DNSClusterFirst), string(api.DNSDefault)}
allErrors = append(allErrors, field.NotSupported(fldPath, dnsPolicy, validValues)) allErrors = append(allErrors, field.NotSupported(fldPath, dnsPolicy, validValues))
} }
return allErrors return allErrors

View File

@ -6491,7 +6491,7 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope
}, },
"dnsPolicy": { "dnsPolicy": {
SchemaProps: spec.SchemaProps{ SchemaProps: spec.SchemaProps{
Description: "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\".", Description: "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.",
Type: []string{"string"}, Type: []string{"string"},
Format: "", Format: "",
}, },

View File

@ -49,8 +49,8 @@ type HandlerRunner interface {
// RuntimeHelper wraps kubelet to make container runtime // RuntimeHelper wraps kubelet to make container runtime
// able to get necessary informations like the RunContainerOptions, DNS settings. // able to get necessary informations like the RunContainerOptions, DNS settings.
type RuntimeHelper interface { type RuntimeHelper interface {
GenerateRunContainerOptions(pod *v1.Pod, container *v1.Container, podIP string) (*RunContainerOptions, error) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Container, podIP string) (contOpts *RunContainerOptions, useClusterFirstPolicy bool, err error)
GetClusterDNS(pod *v1.Pod) (dnsServers []string, dnsSearches []string, err error) GetClusterDNS(pod *v1.Pod) (dnsServers []string, dnsSearches []string, useClusterFirstPolicy bool, err error)
// GetPodCgroupParent returns the the CgroupName identifer, and its literal cgroupfs form on the host // GetPodCgroupParent returns the the CgroupName identifer, and its literal cgroupfs form on the host
// of a pod. // of a pod.
GetPodCgroupParent(pod *v1.Pod) (cm.CgroupName, string) GetPodCgroupParent(pod *v1.Pod) (cm.CgroupName, string)

View File

@ -33,20 +33,20 @@ type FakeRuntimeHelper struct {
Err error Err error
} }
func (f *FakeRuntimeHelper) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Container, podIP string) (*kubecontainer.RunContainerOptions, error) { func (f *FakeRuntimeHelper) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Container, podIP string) (*kubecontainer.RunContainerOptions, bool, error) {
var opts kubecontainer.RunContainerOptions var opts kubecontainer.RunContainerOptions
if len(container.TerminationMessagePath) != 0 { if len(container.TerminationMessagePath) != 0 {
opts.PodContainerDir = f.PodContainerDir opts.PodContainerDir = f.PodContainerDir
} }
return &opts, nil return &opts, false, nil
} }
func (f *FakeRuntimeHelper) GetPodCgroupParent(pod *v1.Pod) (cm.CgroupName, string) { func (f *FakeRuntimeHelper) GetPodCgroupParent(pod *v1.Pod) (cm.CgroupName, string) {
return "", "" return "", ""
} }
func (f *FakeRuntimeHelper) GetClusterDNS(pod *v1.Pod) ([]string, []string, error) { func (f *FakeRuntimeHelper) GetClusterDNS(pod *v1.Pod) ([]string, []string, bool, error) {
return f.DNSServers, f.DNSSearches, f.Err return f.DNSServers, f.DNSSearches, false, f.Err
} }
// This is not used by docker runtime. // This is not used by docker runtime.

View File

@ -858,6 +858,8 @@ func (dm *DockerManager) runContainer(
// setInfraContainerNetworkConfig sets the network configuration for the infra-container. We only set network configuration for infra-container, all // setInfraContainerNetworkConfig sets the network configuration for the infra-container. We only set network configuration for infra-container, all
// the user containers will share the same network namespace with infra-container. // the user containers will share the same network namespace with infra-container.
// NOTE: cluster dns settings aren't passed anymore to docker api in all cases, not only for pods with host network:
// the resolver conf will be overwritten after infra-container creation to override docker's behaviour
func setInfraContainerNetworkConfig(pod *v1.Pod, netMode string, opts *kubecontainer.RunContainerOptions, dockerOpts *dockertypes.ContainerCreateConfig) { func setInfraContainerNetworkConfig(pod *v1.Pod, netMode string, opts *kubecontainer.RunContainerOptions, dockerOpts *dockertypes.ContainerCreateConfig) {
exposedPorts, portBindings := makePortsAndBindings(opts.PortMappings) exposedPorts, portBindings := makePortsAndBindings(opts.PortMappings)
dockerOpts.Config.ExposedPorts = exposedPorts dockerOpts.Config.ExposedPorts = exposedPorts
@ -865,12 +867,6 @@ func setInfraContainerNetworkConfig(pod *v1.Pod, netMode string, opts *kubeconta
if netMode != namespaceModeHost { if netMode != namespaceModeHost {
dockerOpts.Config.Hostname = opts.Hostname dockerOpts.Config.Hostname = opts.Hostname
if len(opts.DNS) > 0 {
dockerOpts.HostConfig.DNS = opts.DNS
}
if len(opts.DNSSearch) > 0 {
dockerOpts.HostConfig.DNSSearch = opts.DNSSearch
}
} }
} }
@ -1759,7 +1755,7 @@ func (dm *DockerManager) runContainerInPod(pod *v1.Pod, container *v1.Container,
glog.V(5).Infof("Generating ref for container %s: %#v", container.Name, ref) glog.V(5).Infof("Generating ref for container %s: %#v", container.Name, ref)
} }
opts, err := dm.runtimeHelper.GenerateRunContainerOptions(pod, container, podIP) opts, useClusterFirstPolicy, err := dm.runtimeHelper.GenerateRunContainerOptions(pod, container, podIP)
if err != nil { if err != nil {
return kubecontainer.ContainerID{}, fmt.Errorf("GenerateRunContainerOptions: %v", err) return kubecontainer.ContainerID{}, fmt.Errorf("GenerateRunContainerOptions: %v", err)
} }
@ -1813,14 +1809,15 @@ func (dm *DockerManager) runContainerInPod(pod *v1.Pod, container *v1.Container,
return kubecontainer.ContainerID{}, err return kubecontainer.ContainerID{}, err
} }
// The addNDotsOption call appends the ndots option to the resolv.conf file generated by docker. // Re-write resolv.conf file generated by docker.
// NOTE: cluster dns settings aren't passed anymore to docker api in all cases, not only for pods with host network:
// the resolver conf will be overwritten after infra-container creation to override docker's behaviour
// This resolv.conf file is shared by all containers of the same pod, and needs to be modified only once per pod. // This resolv.conf file is shared by all containers of the same pod, and needs to be modified only once per pod.
// we modify it when the pause container is created since it is the first container created in the pod since it holds // we modify it when the pause container is created since it is the first container created in the pod since it holds
// the networking namespace. // the networking namespace.
if container.Name == PodInfraContainerName && utsMode != namespaceModeHost { if container.Name == PodInfraContainerName {
err = addNDotsOption(containerInfo.ResolvConfPath) if err := rewriteResolvFile(containerInfo.ResolvConfPath, opts.DNS, opts.DNSSearch, useClusterFirstPolicy); err != nil {
if err != nil { return kubecontainer.ContainerID{}, err
return kubecontainer.ContainerID{}, fmt.Errorf("addNDotsOption: %v", err)
} }
} }
@ -1885,7 +1882,7 @@ func (dm *DockerManager) checkDockerAPIVersion(expectedVersion string) (int, err
return result, nil return result, nil
} }
func addNDotsOption(resolvFilePath string) error { func rewriteResolvFile(resolvFilePath string, dns []string, dnsSearch []string, useClusterFirstPolicy bool) error {
if len(resolvFilePath) == 0 { if len(resolvFilePath) == 0 {
glog.Errorf("ResolvConfPath is empty.") glog.Errorf("ResolvConfPath is empty.")
return nil return nil
@ -1895,23 +1892,42 @@ func addNDotsOption(resolvFilePath string) error {
return fmt.Errorf("ResolvConfPath %q does not exist", resolvFilePath) return fmt.Errorf("ResolvConfPath %q does not exist", resolvFilePath)
} }
glog.V(4).Infof("DNS ResolvConfPath exists: %s. Will attempt to add ndots option: %s", resolvFilePath, ndotsDNSOption) var resolvFileContent []string
if err := appendToFile(resolvFilePath, ndotsDNSOption); err != nil { for _, srv := range dns {
glog.Errorf("resolv.conf could not be updated: %v", err) resolvFileContent = append(resolvFileContent, "nameserver "+srv)
return err
} }
if len(dnsSearch) > 0 {
resolvFileContent = append(resolvFileContent, "search "+strings.Join(dnsSearch, " "))
}
if len(resolvFileContent) > 0 {
if useClusterFirstPolicy {
resolvFileContent = append(resolvFileContent, ndotsDNSOption)
}
resolvFileContentStr := strings.Join(resolvFileContent, "\n")
resolvFileContentStr += "\n"
glog.V(4).Infof("Will attempt to re-write config file %s with: \n%s", resolvFilePath, resolvFileContent)
if err := rewriteFile(resolvFilePath, resolvFileContentStr); err != nil {
glog.Errorf("resolv.conf could not be updated: %v", err)
return err
}
}
return nil return nil
} }
func appendToFile(filePath, stringToAppend string) error { func rewriteFile(filePath, stringToWrite string) error {
f, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644) f, err := os.OpenFile(filePath, os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil { if err != nil {
return err return err
} }
defer f.Close() defer f.Close()
_, err = f.WriteString(stringToAppend) _, err = f.WriteString(stringToWrite)
return err return err
} }

View File

@ -1268,22 +1268,22 @@ func (kl *Kubelet) GetKubeClient() clientset.Interface {
// GetClusterDNS returns a list of the DNS servers and a list of the DNS search // GetClusterDNS returns a list of the DNS servers and a list of the DNS search
// domains of the cluster. // domains of the cluster.
func (kl *Kubelet) GetClusterDNS(pod *v1.Pod) ([]string, []string, error) { func (kl *Kubelet) GetClusterDNS(pod *v1.Pod) ([]string, []string, bool, error) {
var hostDNS, hostSearch []string var hostDNS, hostSearch []string
// Get host DNS settings // Get host DNS settings
if kl.resolverConfig != "" { if kl.resolverConfig != "" {
f, err := os.Open(kl.resolverConfig) f, err := os.Open(kl.resolverConfig)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, false, err
} }
defer f.Close() defer f.Close()
hostDNS, hostSearch, err = kl.parseResolvConf(f) hostDNS, hostSearch, err = kl.parseResolvConf(f)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, false, err
} }
} }
useClusterFirstPolicy := pod.Spec.DNSPolicy == v1.DNSClusterFirst useClusterFirstPolicy := ((pod.Spec.DNSPolicy == v1.DNSClusterFirst && !kubecontainer.IsHostNetworkPod(pod)) || pod.Spec.DNSPolicy == v1.DNSClusterFirstWithHostNet)
if useClusterFirstPolicy && len(kl.clusterDNS) == 0 { if useClusterFirstPolicy && len(kl.clusterDNS) == 0 {
// clusterDNS is not known. // clusterDNS is not known.
// pod with ClusterDNSFirst Policy cannot be created // pod with ClusterDNSFirst Policy cannot be created
@ -1309,7 +1309,7 @@ func (kl *Kubelet) GetClusterDNS(pod *v1.Pod) ([]string, []string, error) {
} else { } else {
hostSearch = kl.formDNSSearchForDNSDefault(hostSearch, pod) hostSearch = kl.formDNSSearchForDNSDefault(hostSearch, pod)
} }
return hostDNS, hostSearch, nil return hostDNS, hostSearch, useClusterFirstPolicy, nil
} }
// for a pod with DNSClusterFirst policy, the cluster DNS server is the only nameserver configured for // for a pod with DNSClusterFirst policy, the cluster DNS server is the only nameserver configured for
@ -1321,7 +1321,7 @@ func (kl *Kubelet) GetClusterDNS(pod *v1.Pod) ([]string, []string, error) {
} }
dnsSearch := kl.formDNSSearch(hostSearch, pod) dnsSearch := kl.formDNSSearch(hostSearch, pod)
return dns, dnsSearch, nil return dns, dnsSearch, useClusterFirstPolicy, nil
} }
// syncPod is the transaction script for the sync of a single pod. // syncPod is the transaction script for the sync of a single pod.

View File

@ -274,13 +274,14 @@ func (kl *Kubelet) GetPodCgroupParent(pod *v1.Pod) (cm.CgroupName, string) {
// GenerateRunContainerOptions generates the RunContainerOptions, which can be used by // GenerateRunContainerOptions generates the RunContainerOptions, which can be used by
// the container runtime to set parameters for launching a container. // the container runtime to set parameters for launching a container.
func (kl *Kubelet) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Container, podIP string) (*kubecontainer.RunContainerOptions, error) { func (kl *Kubelet) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Container, podIP string) (*kubecontainer.RunContainerOptions, bool, error) {
var err error var err error
useClusterFirstPolicy := false
_, cgroupParent := kl.GetPodCgroupParent(pod) _, cgroupParent := kl.GetPodCgroupParent(pod)
opts := &kubecontainer.RunContainerOptions{CgroupParent: cgroupParent} opts := &kubecontainer.RunContainerOptions{CgroupParent: cgroupParent}
hostname, hostDomainName, err := kl.GeneratePodHostNameAndDomain(pod) hostname, hostDomainName, err := kl.GeneratePodHostNameAndDomain(pod)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
opts.Hostname = hostname opts.Hostname = hostname
podName := volumehelper.GetUniquePodName(pod) podName := volumehelper.GetUniquePodName(pod)
@ -290,16 +291,16 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Contai
// TODO(random-liu): Move following convert functions into pkg/kubelet/container // TODO(random-liu): Move following convert functions into pkg/kubelet/container
opts.Devices, err = kl.makeDevices(pod, container) opts.Devices, err = kl.makeDevices(pod, container)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes) opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
opts.Envs, err = kl.makeEnvironmentVariables(pod, container, podIP) opts.Envs, err = kl.makeEnvironmentVariables(pod, container, podIP)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
// Disabling adding TerminationMessagePath on Windows as these files would be mounted as docker volume and // Disabling adding TerminationMessagePath on Windows as these files would be mounted as docker volume and
@ -313,9 +314,9 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Contai
} }
} }
opts.DNS, opts.DNSSearch, err = kl.GetClusterDNS(pod) opts.DNS, opts.DNSSearch, useClusterFirstPolicy, err = kl.GetClusterDNS(pod)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
// only do this check if the experimental behavior is enabled, otherwise allow it to default to false // only do this check if the experimental behavior is enabled, otherwise allow it to default to false
@ -323,7 +324,7 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *v1.Pod, container *v1.Contai
opts.EnableHostUserNamespace = kl.enableHostUserNamespace(pod) opts.EnableHostUserNamespace = kl.enableHostUserNamespace(pod)
} }
return opts, nil return opts, useClusterFirstPolicy, nil
} }
var masterServices = sets.NewString("kubernetes") var masterServices = sets.NewString("kubernetes")

View File

@ -176,14 +176,17 @@ func TestGenerateRunContainerOptions_DNSConfigurationParams(t *testing.T) {
kubelet.clusterDomain = "kubernetes.io" kubelet.clusterDomain = "kubernetes.io"
kubelet.clusterDNS = []net.IP{net.ParseIP(clusterNS)} kubelet.clusterDNS = []net.IP{net.ParseIP(clusterNS)}
pods := newTestPods(2) pods := newTestPods(4)
pods[0].Spec.DNSPolicy = v1.DNSClusterFirst pods[0].Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
pods[1].Spec.DNSPolicy = v1.DNSDefault pods[1].Spec.DNSPolicy = v1.DNSClusterFirst
pods[2].Spec.DNSPolicy = v1.DNSClusterFirst
pods[2].Spec.HostNetwork = false
pods[3].Spec.DNSPolicy = v1.DNSDefault
options := make([]*kubecontainer.RunContainerOptions, 2) options := make([]*kubecontainer.RunContainerOptions, 4)
for i, pod := range pods { for i, pod := range pods {
var err error var err error
options[i], err = kubelet.GenerateRunContainerOptions(pod, &v1.Container{}, "") options[i], _, err = kubelet.GenerateRunContainerOptions(pod, &v1.Container{}, "")
if err != nil { if err != nil {
t.Fatalf("failed to generate container options: %v", err) t.Fatalf("failed to generate container options: %v", err)
} }
@ -200,11 +203,23 @@ func TestGenerateRunContainerOptions_DNSConfigurationParams(t *testing.T) {
if len(options[1].DNSSearch) != 1 || options[1].DNSSearch[0] != "." { if len(options[1].DNSSearch) != 1 || options[1].DNSSearch[0] != "." {
t.Errorf("expected search \".\", got %+v", options[1].DNSSearch) t.Errorf("expected search \".\", got %+v", options[1].DNSSearch)
} }
if len(options[2].DNS) != 1 || options[2].DNS[0] != clusterNS {
t.Errorf("expected nameserver %s, got %+v", clusterNS, options[2].DNS)
}
if len(options[2].DNSSearch) == 0 || options[2].DNSSearch[0] != ".svc."+kubelet.clusterDomain {
t.Errorf("expected search %s, got %+v", ".svc."+kubelet.clusterDomain, options[2].DNSSearch)
}
if len(options[3].DNS) != 1 || options[3].DNS[0] != "127.0.0.1" {
t.Errorf("expected nameserver 127.0.0.1, got %+v", options[3].DNS)
}
if len(options[3].DNSSearch) != 1 || options[3].DNSSearch[0] != "." {
t.Errorf("expected search \".\", got %+v", options[3].DNSSearch)
}
kubelet.resolverConfig = "/etc/resolv.conf" kubelet.resolverConfig = "/etc/resolv.conf"
for i, pod := range pods { for i, pod := range pods {
var err error var err error
options[i], err = kubelet.GenerateRunContainerOptions(pod, &v1.Container{}, "") options[i], _, err = kubelet.GenerateRunContainerOptions(pod, &v1.Container{}, "")
if err != nil { if err != nil {
t.Fatalf("failed to generate container options: %v", err) t.Fatalf("failed to generate container options: %v", err)
} }
@ -224,6 +239,16 @@ func TestGenerateRunContainerOptions_DNSConfigurationParams(t *testing.T) {
} else if options[0].DNSSearch[0] != ".svc."+kubelet.clusterDomain { } else if options[0].DNSSearch[0] != ".svc."+kubelet.clusterDomain {
t.Errorf("expected domain %s, got %s", ".svc."+kubelet.clusterDomain, options[0].DNSSearch) t.Errorf("expected domain %s, got %s", ".svc."+kubelet.clusterDomain, options[0].DNSSearch)
} }
if len(options[2].DNS) != 1 {
t.Errorf("expected cluster nameserver only, got %+v", options[2].DNS)
} else if options[2].DNS[0] != clusterNS {
t.Errorf("expected nameserver %s, got %v", clusterNS, options[2].DNS[0])
}
if len(options[2].DNSSearch) != expLength {
t.Errorf("expected prepend of cluster domain, got %+v", options[2].DNSSearch)
} else if options[2].DNSSearch[0] != ".svc."+kubelet.clusterDomain {
t.Errorf("expected domain %s, got %s", ".svc."+kubelet.clusterDomain, options[0].DNSSearch)
}
} }
type testServiceLister struct { type testServiceLister struct {

View File

@ -132,7 +132,7 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb
// generateContainerConfig generates container config for kubelet runtime v1. // generateContainerConfig generates container config for kubelet runtime v1.
func (m *kubeGenericRuntimeManager) generateContainerConfig(container *v1.Container, pod *v1.Pod, restartCount int, podIP, imageRef string) (*runtimeapi.ContainerConfig, error) { func (m *kubeGenericRuntimeManager) generateContainerConfig(container *v1.Container, pod *v1.Pod, restartCount int, podIP, imageRef string) (*runtimeapi.ContainerConfig, error) {
opts, err := m.runtimeHelper.GenerateRunContainerOptions(pod, container, podIP) opts, _, err := m.runtimeHelper.GenerateRunContainerOptions(pod, container, podIP)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -75,7 +75,7 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *v1.Pod, attemp
} }
if !kubecontainer.IsHostNetworkPod(pod) { if !kubecontainer.IsHostNetworkPod(pod) {
dnsServers, dnsSearches, err := m.runtimeHelper.GetClusterDNS(pod) dnsServers, dnsSearches, _, err := m.runtimeHelper.GetClusterDNS(pod)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -810,7 +810,7 @@ func (r *Runtime) newAppcRuntimeApp(pod *v1.Pod, podIP string, c v1.Container, r
} }
// TODO: determine how this should be handled for rkt // TODO: determine how this should be handled for rkt
opts, err := r.runtimeHelper.GenerateRunContainerOptions(pod, &c, podIP) opts, _, err := r.runtimeHelper.GenerateRunContainerOptions(pod, &c, podIP)
if err != nil { if err != nil {
return err return err
} }
@ -1009,7 +1009,7 @@ func (r *Runtime) generateRunCommand(pod *v1.Pod, uuid, netnsName string) (strin
} }
} else { } else {
// Setup DNS. // Setup DNS.
dnsServers, dnsSearches, err := r.runtimeHelper.GetClusterDNS(pod) dnsServers, dnsSearches, _, err := r.runtimeHelper.GetClusterDNS(pod)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -1679,9 +1679,14 @@ type PodList struct {
type DNSPolicy string type DNSPolicy string
const ( const (
// DNSClusterFirstWithHostNet indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default
// (as determined by kubelet) DNS settings.
DNSClusterFirstWithHostNet DNSPolicy = "ClusterFirstWithHostNet"
// DNSClusterFirst indicates that the pod should use cluster DNS // DNSClusterFirst indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default (as // first unless hostNetwork is true, if it is available, then
// determined by kubelet) DNS settings. // fall back on the default (as determined by kubelet) DNS settings.
DNSClusterFirst DNSPolicy = "ClusterFirst" DNSClusterFirst DNSPolicy = "ClusterFirst"
// DNSDefault indicates that the pod should use the default (as // DNSDefault indicates that the pod should use the default (as

View File

@ -2607,8 +2607,9 @@ message PodSpec {
optional int64 activeDeadlineSeconds = 5; optional int64 activeDeadlineSeconds = 5;
// Set DNS policy for containers within the pod. // Set DNS policy for containers within the pod.
// One of 'ClusterFirst' or 'Default'. // One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'.
// Defaults to "ClusterFirst". // Defaults to "ClusterFirst".
// To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.
// +optional // +optional
optional string dnsPolicy = 6; optional string dnsPolicy = 6;

View File

@ -1888,9 +1888,14 @@ const (
type DNSPolicy string type DNSPolicy string
const ( const (
// DNSClusterFirstWithHostNet indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default
// (as determined by kubelet) DNS settings.
DNSClusterFirstWithHostNet DNSPolicy = "ClusterFirstWithHostNet"
// DNSClusterFirst indicates that the pod should use cluster DNS // DNSClusterFirst indicates that the pod should use cluster DNS
// first, if it is available, then fall back on the default (as // first unless hostNetwork is true, if it is available, then
// determined by kubelet) DNS settings. // fall back on the default (as determined by kubelet) DNS settings.
DNSClusterFirst DNSPolicy = "ClusterFirst" DNSClusterFirst DNSPolicy = "ClusterFirst"
// DNSDefault indicates that the pod should use the default (as // DNSDefault indicates that the pod should use the default (as
@ -2245,8 +2250,9 @@ type PodSpec struct {
// +optional // +optional
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"` ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"`
// Set DNS policy for containers within the pod. // Set DNS policy for containers within the pod.
// One of 'ClusterFirst' or 'Default'. // One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'.
// Defaults to "ClusterFirst". // Defaults to "ClusterFirst".
// To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.
// +optional // +optional
DNSPolicy DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"` DNSPolicy DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"`
// NodeSelector is a selector which must be true for the pod to fit on a node. // NodeSelector is a selector which must be true for the pod to fit on a node.

View File

@ -1321,7 +1321,7 @@ var map_PodSpec = map[string]string{
"restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: http://kubernetes.io/docs/user-guide/pod-states#restartpolicy", "restartPolicy": "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: http://kubernetes.io/docs/user-guide/pod-states#restartpolicy",
"terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.", "terminationGracePeriodSeconds": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds.",
"activeDeadlineSeconds": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.", "activeDeadlineSeconds": "Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer.",
"dnsPolicy": "Set DNS policy for containers within the pod. One of 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\".", "dnsPolicy": "Set DNS policy for containers within the pod. One of 'ClusterFirstWithHostNet', 'ClusterFirst' or 'Default'. Defaults to \"ClusterFirst\". To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.",
"nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://kubernetes.io/docs/user-guide/node-selection/README", "nodeSelector": "NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. More info: http://kubernetes.io/docs/user-guide/node-selection/README",
"serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md", "serviceAccountName": "ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: http://releases.k8s.io/HEAD/docs/design/service_accounts.md",
"serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.", "serviceAccount": "DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.",