mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
Endpoints controller respects unready service annotation
This commit is contained in:
parent
377957a173
commit
74ccd24574
@ -20,6 +20,7 @@ package endpoint
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -53,6 +54,14 @@ const (
|
|||||||
// We must avoid syncing service until the pod store has synced. If it hasn't synced, to
|
// We must avoid syncing service until the pod store has synced. If it hasn't synced, to
|
||||||
// avoid a hot loop, we'll wait this long between checks.
|
// avoid a hot loop, we'll wait this long between checks.
|
||||||
PodStoreSyncedPollPeriod = 100 * time.Millisecond
|
PodStoreSyncedPollPeriod = 100 * time.Millisecond
|
||||||
|
|
||||||
|
// An annotation on the Service denoting if the endpoints controller should
|
||||||
|
// go ahead and create endpoints for unready pods. This annotation is
|
||||||
|
// currently only used by PetSets, where we need the pet to be DNS
|
||||||
|
// resolvable during initialization. In this situation we create a headless
|
||||||
|
// service just for the PetSet, and clients shouldn't be using this Service
|
||||||
|
// for anything so unready endpoints don't matter.
|
||||||
|
TolerateUnreadyEndpointsAnnotation = "service.alpha.kubernetes.io/tolerate-unready-endpoints"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -356,6 +365,16 @@ func (e *EndpointController) syncService(key string) {
|
|||||||
subsets := []api.EndpointSubset{}
|
subsets := []api.EndpointSubset{}
|
||||||
podHostNames := map[string]endpoints.HostRecord{}
|
podHostNames := map[string]endpoints.HostRecord{}
|
||||||
|
|
||||||
|
var tolerateUnreadyEndpoints bool
|
||||||
|
if v, ok := service.Annotations[TolerateUnreadyEndpointsAnnotation]; ok {
|
||||||
|
b, err := strconv.ParseBool(v)
|
||||||
|
if err == nil {
|
||||||
|
tolerateUnreadyEndpoints = b
|
||||||
|
} else {
|
||||||
|
glog.Errorf("Failed to parse annotation %v: %v", TolerateUnreadyEndpointsAnnotation, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i := range pods.Items {
|
for i := range pods.Items {
|
||||||
pod := &pods.Items[i]
|
pod := &pods.Items[i]
|
||||||
|
|
||||||
@ -401,7 +420,7 @@ func (e *EndpointController) syncService(key string) {
|
|||||||
epa.Hostname = hostname
|
epa.Hostname = hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
if api.IsPodReady(pod) {
|
if tolerateUnreadyEndpoints || api.IsPodReady(pod) {
|
||||||
subsets = append(subsets, api.EndpointSubset{
|
subsets = append(subsets, api.EndpointSubset{
|
||||||
Addresses: []api.EndpointAddress{epa},
|
Addresses: []api.EndpointAddress{epa},
|
||||||
Ports: []api.EndpointPort{epp},
|
Ports: []api.EndpointPort{epp},
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/errors"
|
"k8s.io/kubernetes/pkg/api/errors"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/controller/endpoint"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/types"
|
"k8s.io/kubernetes/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/util"
|
"k8s.io/kubernetes/pkg/util"
|
||||||
@ -900,6 +901,64 @@ var _ = framework.KubeDescribe("Services", func() {
|
|||||||
service, err = t.CreateService(service)
|
service, err = t.CreateService(service)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("should create endpoints for unready pods", func() {
|
||||||
|
serviceName := "never-ready"
|
||||||
|
ns := f.Namespace.Name
|
||||||
|
|
||||||
|
t := NewServerTest(c, ns, serviceName)
|
||||||
|
defer func() {
|
||||||
|
defer GinkgoRecover()
|
||||||
|
errs := t.Cleanup()
|
||||||
|
if len(errs) != 0 {
|
||||||
|
framework.Failf("errors in cleanup: %v", errs)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
service := t.BuildServiceSpec()
|
||||||
|
service.Annotations = map[string]string{endpoint.TolerateUnreadyEndpointsAnnotation: "true"}
|
||||||
|
rcSpec := rcByNameContainer(t.name, 1, t.image, t.Labels, api.Container{
|
||||||
|
Name: t.name,
|
||||||
|
Image: t.image,
|
||||||
|
Ports: []api.ContainerPort{{ContainerPort: int32(80), Protocol: api.ProtocolTCP}},
|
||||||
|
ReadinessProbe: &api.Probe{
|
||||||
|
Handler: api.Handler{
|
||||||
|
Exec: &api.ExecAction{
|
||||||
|
Command: []string{"/bin/false"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
By(fmt.Sprintf("createing RC %v with selectors %v", rcSpec.Name, rcSpec.Spec.Selector))
|
||||||
|
_, err := t.createRC(rcSpec)
|
||||||
|
ExpectNoError(err)
|
||||||
|
|
||||||
|
By(fmt.Sprintf("creating Service %v with selectors %v", service.Name, service.Spec.Selector))
|
||||||
|
_, err = t.CreateService(service)
|
||||||
|
ExpectNoError(err)
|
||||||
|
|
||||||
|
By("Verifying pods for RC " + t.name)
|
||||||
|
ExpectNoError(framework.VerifyPods(t.Client, t.Namespace, t.name, false, 1))
|
||||||
|
|
||||||
|
svcName := fmt.Sprintf("%v.%v", serviceName, f.Namespace.Name)
|
||||||
|
By("waiting for endpoints of Service with DNS name " + svcName)
|
||||||
|
|
||||||
|
createExecPodOrFail(f.Client, f.Namespace.Name, "exec")
|
||||||
|
cmd := fmt.Sprintf("wget -qO- %v", svcName)
|
||||||
|
var stdout string
|
||||||
|
if pollErr := wait.PollImmediate(framework.Poll, kubeProxyLagTimeout, func() (bool, error) {
|
||||||
|
var err error
|
||||||
|
stdout, err = framework.RunHostCmd(f.Namespace.Name, "exec", cmd)
|
||||||
|
if err != nil {
|
||||||
|
framework.Logf("expected un-ready endpoint for Service %v, stdout: %v, err %v", t.name, stdout, err)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}); pollErr != nil {
|
||||||
|
framework.Failf("expected un-ready endpoint for Service %v within %v, stdout: %v", t.name, kubeProxyLagTimeout, stdout)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// updateService fetches a service, calls the update function on it,
|
// updateService fetches a service, calls the update function on it,
|
||||||
|
Loading…
Reference in New Issue
Block a user