diff --git a/cluster/saltbase/salt/kubelet/default b/cluster/saltbase/salt/kubelet/default index 1f7d8fe9f28..74102e7728a 100644 --- a/cluster/saltbase/salt/kubelet/default +++ b/cluster/saltbase/salt/kubelet/default @@ -107,12 +107,12 @@ {% set system_container = "" -%} {% set kubelet_container = "" -%} {% set runtime_container = "" -%} -{% if grains['os_family'] == 'Debian' -%} +{% if grains['os_family'] == 'Debian' -%} {% if pillar.get('is_systemd') %} {% set cgroup_root = "--cgroup-root=docker" -%} {% else %} {% set cgroup_root = "--cgroup-root=/" -%} - {% set system_container = "--system-cgroups=/system" -%} + {% set system_container = "--system-cgroups=/system" -%} {% set runtime_container = "--runtime-cgroups=/docker-daemon" -%} {% set kubelet_container= "--kubelet-cgroups=/kubelet" -%} {% endif %} @@ -151,9 +151,17 @@ {% endif -%} {% endif -%} -{% set configure_hairpin_mode = "--configure-hairpin-mode=true" -%} -{% if pillar.get('hairpin_mode', '').lower() == 'false' %} - {% set configure_hairpin_mode = "--configure-hairpin-mode=false" %} +# Don't pipe the --hairpin-mode flag by default. This allows the kubelet to pick +# an appropriate value. +{% set hairpin_mode = "" -%} +# The master cannot see Services because it doesn't run kube-proxy, so we don't +# need to make its container bridge promiscuous. We also don't want to set +# the hairpin-veth flag on the master because it increases the chances of +# running into the kernel bug described in #20096. +{% if grains['roles'][0] == 'kubernetes-master' -%} + {% set hairpin_mode = "--hairpin-mode=none" -%} +{% elif pillar['hairpin_mode'] is defined and pillar['hairpin_mode'] in ['promiscuous-bridge', 'hairpin-veth', 'none'] -%} + {% set hairpin_mode = "--hairpin-mode=" + pillar['hairpin_mode'] -%} {% endif -%} {% set kubelet_port = "" -%} diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 93e4d665eb3..168967c5746 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -359,10 +359,41 @@ func NewMainKubelet( klet.podCache = kubecontainer.NewCache() + // The hairpin mode setting doesn't matter if: + // - We're not using a bridge network. This is hard to check because we might + // be using a plugin. It matters if --configure-cbr0=true, and we currently + // don't pipe it down to any plugins. + // - It's set to hairpin-veth for a container runtime that doesn't know how + // to set the hairpin flag on the veth's of containers. Currently the + // docker runtime is the only one that understands this. + // - It's set to "none" or an unrecognized string. + switch hairpinMode { + case componentconfig.PromiscuousBridge: + if !configureCBR0 { + glog.Warningf("Hairpin mode set to %v but configureCBR0 is false", hairpinMode) + break + } + fallthrough + case componentconfig.HairpinVeth: + if containerRuntime != "docker" { + glog.Warningf("Hairpin mode set to %v but container runtime is %v", hairpinMode, containerRuntime) + break + } + fallthrough + case componentconfig.HairpinNone: + if configureCBR0 { + glog.Warningf("Hairpin mode set to %q and configureCBR0 is true, this might result in loss of hairpin packets.", hairpinMode) + break + } + glog.Infof("Hairpin mode set to %q", hairpinMode) + default: + glog.Infof("Unrecognized hairpin mode setting %q, setting it to %v", hairpinMode, componentconfig.HairpinNone) + hairpinMode = componentconfig.HairpinNone + } + // Initialize the runtime. switch containerRuntime { case "docker": - glog.Infof("Hairpin mode set to %v", hairpinMode) // Only supported one for now, continue. klet.containerRuntime = dockertools.NewDockerManager( dockerClient,