Merge pull request #55122 from MrHohn/fix-session-affinity-e2e

Automatic merge from submit-queue (batch tested with PRs 55114, 52976, 54871, 55122, 55140). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Don't share nodePort service in session affinity tests

**What this PR does / why we need it**:
From https://github.com/kubernetes/kubernetes/issues/54524, https://github.com/kubernetes/kubernetes/issues/54571.

Spent sometime to dig into it today, found this test is flaky mostly because it sends out service requests before kube-proxy reacts on the service session affinity update, hence multiple endpoints are responding instead of one. It is more flaky in alpha CIs probably due to different test sequences.

This PR creates a separate service with `sessionAffinity=ClientIP` so there wouldn't be a race between test begins and kube-proxy reacts. On the other hand, it also seems inappropriate to tweak the`config.NodePortService`, which is shared by other networking tests.

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Fixes # (will mark them fixed later).

**Special notes for your reviewer**:
/assign @m1093782566 @bowei 
cc @spiffxp

**Release note**:

```release-note
NONE

```
This commit is contained in:
Kubernetes Submit Queue 2017-11-06 23:19:21 -08:00 committed by GitHub
commit dd00bc65f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 34 deletions

View File

@ -45,14 +45,15 @@ import (
)
const (
EndpointHttpPort = 8080
EndpointUdpPort = 8081
TestContainerHttpPort = 8080
ClusterHttpPort = 80
ClusterUdpPort = 90
testPodName = "test-container-pod"
hostTestPodName = "host-test-container-pod"
nodePortServiceName = "node-port-service"
EndpointHttpPort = 8080
EndpointUdpPort = 8081
TestContainerHttpPort = 8080
ClusterHttpPort = 80
ClusterUdpPort = 90
testPodName = "test-container-pod"
hostTestPodName = "host-test-container-pod"
nodePortServiceName = "node-port-service"
sessionAffinityServiceName = "session-affinity-service"
// wait time between poll attempts of a Service vip and/or nodePort.
// coupled with testTries to produce a net timeout value.
hitEndpointRetryDelay = 2 * time.Second
@ -110,6 +111,9 @@ type NetworkingTestConfig struct {
// NodePortService is a Service with Type=NodePort spanning over all
// endpointPods.
NodePortService *v1.Service
// SessionAffinityService is a Service with SessionAffinity=ClientIP
// spanning over all endpointPods.
SessionAffinityService *v1.Service
// ExternalAddrs is a list of external IPs of nodes in the cluster.
ExternalAddrs []string
// Nodes is a list of nodes in the cluster.
@ -463,10 +467,14 @@ func (config *NetworkingTestConfig) createTestPodSpec() *v1.Pod {
return pod
}
func (config *NetworkingTestConfig) createNodePortService(selector map[string]string) {
serviceSpec := &v1.Service{
func (config *NetworkingTestConfig) createNodePortServiceSpec(svcName string, selector map[string]string, enableSessionAffinity bool) *v1.Service {
sessionAffinity := v1.ServiceAffinityNone
if enableSessionAffinity {
sessionAffinity = v1.ServiceAffinityClientIP
}
return &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: nodePortServiceName,
Name: svcName,
},
Spec: v1.ServiceSpec{
Type: v1.ServiceTypeNodePort,
@ -474,10 +482,18 @@ func (config *NetworkingTestConfig) createNodePortService(selector map[string]st
{Port: ClusterHttpPort, Name: "http", Protocol: v1.ProtocolTCP, TargetPort: intstr.FromInt(EndpointHttpPort)},
{Port: ClusterUdpPort, Name: "udp", Protocol: v1.ProtocolUDP, TargetPort: intstr.FromInt(EndpointUdpPort)},
},
Selector: selector,
Selector: selector,
SessionAffinity: sessionAffinity,
},
}
config.NodePortService = config.createService(serviceSpec)
}
func (config *NetworkingTestConfig) createNodePortService(selector map[string]string) {
config.NodePortService = config.createService(config.createNodePortServiceSpec(nodePortServiceName, selector, false))
}
func (config *NetworkingTestConfig) createSessionAffinityService(selector map[string]string) {
config.SessionAffinityService = config.createService(config.createNodePortServiceSpec(sessionAffinityServiceName, selector, true))
}
func (config *NetworkingTestConfig) DeleteNodePortService() {
@ -549,6 +565,7 @@ func (config *NetworkingTestConfig) setup(selector map[string]string) {
By("Creating the service on top of the pods in kubernetes")
config.createNodePortService(selector)
config.createSessionAffinityService(selector)
for _, p := range config.NodePortService.Spec.Ports {
switch p.Protocol {

View File

@ -20,7 +20,6 @@ import (
"fmt"
"net/http"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/master/ports"
"k8s.io/kubernetes/test/e2e/framework"
@ -201,19 +200,12 @@ var _ = SIGDescribe("Networking", func() {
config.DialFromNode("udp", config.NodeIP, config.NodeUdpPort, config.MaxTries, config.MaxTries, sets.NewString())
})
It("should function for client IP based session affinity: http [Slow]", func() {
It("should function for client IP based session affinity: http", func() {
config := framework.NewNetworkingTestConfig(f)
By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, framework.ClusterHttpPort))
updateSessionAffinity := func(svc *v1.Service) {
svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
}
_, err := framework.UpdateService(f.ClientSet, config.NodePortService.Namespace, config.NodePortService.Name, updateSessionAffinity)
if err != nil {
framework.Failf("Failed to update service session affinity, error: %v", err)
}
By(fmt.Sprintf("dialing(http) %v --> %v:%v", config.TestContainerPod.Name, config.SessionAffinityService.Spec.ClusterIP, framework.ClusterHttpPort))
// Check if number of endpoints returned are exactly one.
eps, err := config.GetEndpointsFromTestContainer("http", config.ClusterIP, framework.ClusterHttpPort, framework.SessionAffinityChecks)
eps, err := config.GetEndpointsFromTestContainer("http", config.SessionAffinityService.Spec.ClusterIP, framework.ClusterHttpPort, framework.SessionAffinityChecks)
if err != nil {
framework.Failf("Failed to get endpoints from test container, error: %v", err)
}
@ -225,19 +217,12 @@ var _ = SIGDescribe("Networking", func() {
}
})
It("should function for client IP based session affinity: udp [Slow]", func() {
It("should function for client IP based session affinity: udp", func() {
config := framework.NewNetworkingTestConfig(f)
By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.ClusterIP, framework.ClusterUdpPort))
updateSessionAffinity := func(svc *v1.Service) {
svc.Spec.SessionAffinity = v1.ServiceAffinityClientIP
}
_, err := framework.UpdateService(f.ClientSet, config.NodePortService.Namespace, config.NodePortService.Name, updateSessionAffinity)
if err != nil {
framework.Failf("Failed to update service session affinity, error: %v", err)
}
By(fmt.Sprintf("dialing(udp) %v --> %v:%v", config.TestContainerPod.Name, config.SessionAffinityService.Spec.ClusterIP, framework.ClusterUdpPort))
// Check if number of endpoints returned are exactly one.
eps, err := config.GetEndpointsFromTestContainer("udp", config.ClusterIP, framework.ClusterUdpPort, framework.SessionAffinityChecks)
eps, err := config.GetEndpointsFromTestContainer("udp", config.SessionAffinityService.Spec.ClusterIP, framework.ClusterUdpPort, framework.SessionAffinityChecks)
if err != nil {
framework.Failf("Failed to get endpoints from test container, error: %v", err)
}