Merge pull request #35526 from justinsb/fix_35521_b

Automatic merge from submit-queue

kubelet bootstrap: start hostNetwork pods before we have PodCIDR

Network readiness was checked in the pod admission phase, but pods that
fail admission are not retried.  Move the check to the pod start phase.

Issue #35409 
Issue #35521
pull/6/head
Kubernetes Submit Queue 2016-11-06 12:53:14 -08:00 committed by GitHub
commit 182a09c3c7
9 changed files with 64 additions and 15 deletions

View File

@ -91,7 +91,6 @@ EOF
if [[ ! -z "${KUBELET_APISERVER:-}" ]] && [[ ! -z "${KUBELET_CERT:-}" ]] && [[ ! -z "${KUBELET_KEY:-}" ]]; then if [[ ! -z "${KUBELET_APISERVER:-}" ]] && [[ ! -z "${KUBELET_CERT:-}" ]] && [[ ! -z "${KUBELET_KEY:-}" ]]; then
cat <<EOF >>/etc/salt/minion.d/grains.conf cat <<EOF >>/etc/salt/minion.d/grains.conf
kubelet_api_servers: '${KUBELET_APISERVER}' kubelet_api_servers: '${KUBELET_APISERVER}'
cbr-cidr: 10.123.45.0/29
EOF EOF
else else
# If the kubelet is running disconnected from a master, give it a fixed # If the kubelet is running disconnected from a master, give it a fixed
@ -110,7 +109,6 @@ salt-node-role() {
grains: grains:
roles: roles:
- kubernetes-pool - kubernetes-pool
cbr-cidr: 10.123.45.0/29
cloud: aws cloud: aws
api_servers: '${API_SERVERS}' api_servers: '${API_SERVERS}'
EOF EOF

View File

@ -958,7 +958,6 @@ EOF
if [[ ! -z "${KUBELET_APISERVER:-}" ]] && [[ ! -z "${KUBELET_CERT:-}" ]] && [[ ! -z "${KUBELET_KEY:-}" ]]; then if [[ ! -z "${KUBELET_APISERVER:-}" ]] && [[ ! -z "${KUBELET_CERT:-}" ]] && [[ ! -z "${KUBELET_KEY:-}" ]]; then
cat <<EOF >>/etc/salt/minion.d/grains.conf cat <<EOF >>/etc/salt/minion.d/grains.conf
kubelet_api_servers: '${KUBELET_APISERVER}' kubelet_api_servers: '${KUBELET_APISERVER}'
cbr-cidr: 10.123.45.0/29
EOF EOF
else else
# If the kubelet is running disconnected from a master, give it a fixed # If the kubelet is running disconnected from a master, give it a fixed
@ -977,7 +976,6 @@ function salt-node-role() {
grains: grains:
roles: roles:
- kubernetes-pool - kubernetes-pool
cbr-cidr: 10.123.45.0/29
cloud: gce cloud: gce
api_servers: '${KUBERNETES_MASTER_NAME}' api_servers: '${KUBERNETES_MASTER_NAME}'
EOF EOF

View File

@ -483,11 +483,8 @@ function start-kubelet {
if [[ ! -z "${KUBELET_APISERVER:-}" && ! -z "${KUBELET_CERT:-}" && ! -z "${KUBELET_KEY:-}" ]]; then if [[ ! -z "${KUBELET_APISERVER:-}" && ! -z "${KUBELET_CERT:-}" && ! -z "${KUBELET_KEY:-}" ]]; then
flags+=" --api-servers=https://${KUBELET_APISERVER}" flags+=" --api-servers=https://${KUBELET_APISERVER}"
flags+=" --register-schedulable=false" flags+=" --register-schedulable=false"
# need at least a /29 pod cidr for now due to #32844
# TODO: determine if we still allow non-hostnetwork pods to run on master, clean up master pod setup
# WARNING: potential ip range collision with 10.123.45.0/29
flags+=" --pod-cidr=10.123.45.0/29"
else else
# Standalone mode (not widely used?)
flags+=" --pod-cidr=${MASTER_IP_RANGE}" flags+=" --pod-cidr=${MASTER_IP_RANGE}"
fi fi
else # For nodes else # For nodes

View File

@ -155,7 +155,7 @@ assemble_kubelet_flags() {
if [ ! -z "${KUBELET_APISERVER:-}" ] && \ if [ ! -z "${KUBELET_APISERVER:-}" ] && \
[ ! -z "${KUBELET_CERT:-}" ] && \ [ ! -z "${KUBELET_CERT:-}" ] && \
[ ! -z "${KUBELET_KEY:-}" ]; then [ ! -z "${KUBELET_KEY:-}" ]; then
KUBELET_CMD_FLAGS="${KUBELET_CMD_FLAGS} --api-servers=https://${KUBELET_APISERVER} --register-schedulable=false --pod-cidr=10.123.45.0/29" KUBELET_CMD_FLAGS="${KUBELET_CMD_FLAGS} --api-servers=https://${KUBELET_APISERVER} --register-schedulable=false"
else else
KUBELET_CMD_FLAGS="${KUBELET_CMD_FLAGS} --pod-cidr=${MASTER_IP_RANGE}" KUBELET_CMD_FLAGS="${KUBELET_CMD_FLAGS} --pod-cidr=${MASTER_IP_RANGE}"
fi fi

View File

@ -1422,6 +1422,11 @@ func (kl *Kubelet) syncPod(o syncPodOptions) error {
return syncErr return syncErr
} }
// If the network plugin is not ready, only start the pod if it uses the host network
if rs := kl.runtimeState.networkErrors(); len(rs) != 0 && !podUsesHostNetwork(pod) {
return fmt.Errorf("network is not ready: %v", rs)
}
// Create Cgroups for the pod and apply resource parameters // Create Cgroups for the pod and apply resource parameters
// to them if cgroup-per-qos flag is enabled. // to them if cgroup-per-qos flag is enabled.
pcm := kl.containerManager.NewPodContainerManager() pcm := kl.containerManager.NewPodContainerManager()
@ -1696,7 +1701,7 @@ func (kl *Kubelet) syncLoop(updates <-chan kubetypes.PodUpdate, handler SyncHand
defer housekeepingTicker.Stop() defer housekeepingTicker.Stop()
plegCh := kl.pleg.Watch() plegCh := kl.pleg.Watch()
for { for {
if rs := kl.runtimeState.errors(); len(rs) != 0 { if rs := kl.runtimeState.runtimeErrors(); len(rs) != 0 {
glog.Infof("skipping pod synchronization - %v", rs) glog.Infof("skipping pod synchronization - %v", rs)
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
continue continue

View File

@ -591,7 +591,8 @@ func (kl *Kubelet) setNodeReadyCondition(node *api.Node) {
// ref: https://github.com/kubernetes/kubernetes/issues/16961 // ref: https://github.com/kubernetes/kubernetes/issues/16961
currentTime := unversioned.NewTime(kl.clock.Now()) currentTime := unversioned.NewTime(kl.clock.Now())
var newNodeReadyCondition api.NodeCondition var newNodeReadyCondition api.NodeCondition
if rs := kl.runtimeState.errors(); len(rs) == 0 { rs := append(kl.runtimeState.runtimeErrors(), kl.runtimeState.networkErrors()...)
if len(rs) == 0 {
newNodeReadyCondition = api.NodeCondition{ newNodeReadyCondition = api.NodeCondition{
Type: api.NodeReady, Type: api.NodeReady,
Status: api.ConditionTrue, Status: api.ConditionTrue,

View File

@ -1054,6 +1054,48 @@ func TestPrivilegedContainerDisallowed(t *testing.T) {
assert.Error(t, err, "expected pod infra creation to fail") assert.Error(t, err, "expected pod infra creation to fail")
} }
func TestNetworkErrorsWithoutHostNetwork(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
kubelet := testKubelet.kubelet
kubelet.runtimeState.setNetworkState(fmt.Errorf("simulated network error"))
capabilities.SetForTests(capabilities.Capabilities{
PrivilegedSources: capabilities.PrivilegedSources{
HostNetworkSources: []string{kubetypes.ApiserverSource, kubetypes.FileSource},
},
})
pod := podWithUidNameNsSpec("12345678", "hostnetwork", "new", api.PodSpec{
SecurityContext: &api.PodSecurityContext{
HostNetwork: false,
},
Containers: []api.Container{
{Name: "foo"},
},
})
kubelet.podManager.SetPods([]*api.Pod{pod})
err := kubelet.syncPod(syncPodOptions{
pod: pod,
podStatus: &kubecontainer.PodStatus{},
updateType: kubetypes.SyncPodUpdate,
})
assert.Error(t, err, "expected pod with hostNetwork=false to fail when network in error")
pod.Annotations[kubetypes.ConfigSourceAnnotationKey] = kubetypes.FileSource
pod.Spec.SecurityContext.HostNetwork = true
err = kubelet.syncPod(syncPodOptions{
pod: pod,
podStatus: &kubecontainer.PodStatus{},
updateType: kubetypes.SyncPodUpdate,
})
assert.NoError(t, err, "expected pod with hostNetwork=true to succeed when network in error")
}
func TestFilterOutTerminatedPods(t *testing.T) { func TestFilterOutTerminatedPods(t *testing.T) {
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */) testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
kubelet := testKubelet.kubelet kubelet := testKubelet.kubelet

View File

@ -83,6 +83,7 @@ func TestRunOnce(t *testing.T) {
kubeClient: &fake.Clientset{}, kubeClient: &fake.Clientset{},
hostname: testKubeletHostname, hostname: testKubeletHostname,
nodeName: testKubeletHostname, nodeName: testKubeletHostname,
runtimeState: newRuntimeState(time.Second),
} }
kb.containerManager = cm.NewStubContainerManager() kb.containerManager = cm.NewStubContainerManager()

View File

@ -68,16 +68,13 @@ func (s *runtimeState) setInitError(err error) {
s.initError = err s.initError = err
} }
func (s *runtimeState) errors() []string { func (s *runtimeState) runtimeErrors() []string {
s.RLock() s.RLock()
defer s.RUnlock() defer s.RUnlock()
var ret []string var ret []string
if s.initError != nil { if s.initError != nil {
ret = append(ret, s.initError.Error()) ret = append(ret, s.initError.Error())
} }
if s.networkError != nil {
ret = append(ret, s.networkError.Error())
}
if !s.lastBaseRuntimeSync.Add(s.baseRuntimeSyncThreshold).After(time.Now()) { if !s.lastBaseRuntimeSync.Add(s.baseRuntimeSyncThreshold).After(time.Now()) {
ret = append(ret, "container runtime is down") ret = append(ret, "container runtime is down")
} }
@ -87,6 +84,16 @@ func (s *runtimeState) errors() []string {
return ret return ret
} }
func (s *runtimeState) networkErrors() []string {
s.RLock()
defer s.RUnlock()
var ret []string
if s.networkError != nil {
ret = append(ret, s.networkError.Error())
}
return ret
}
func newRuntimeState( func newRuntimeState(
runtimeSyncThreshold time.Duration, runtimeSyncThreshold time.Duration,
) *runtimeState { ) *runtimeState {