mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 11:13:48 +00:00
Updated comments
Updated documentation Fixed e2e test
This commit is contained in:
parent
d399a8f8cc
commit
9e6c45c395
@ -418,9 +418,6 @@ Valid values for the `ServiceType` field are:
|
|||||||
which forwards to the `Service` exposed as a `<NodeIP>:NodePort`
|
which forwards to the `Service` exposed as a `<NodeIP>:NodePort`
|
||||||
for each Node.
|
for each Node.
|
||||||
|
|
||||||
Note that while `NodePort`s can be TCP or UDP, `LoadBalancer`s only support TCP
|
|
||||||
as of Kubernetes 1.0.
|
|
||||||
|
|
||||||
### Type NodePort
|
### Type NodePort
|
||||||
|
|
||||||
If you set the `type` field to `"NodePort"`, the Kubernetes master will
|
If you set the `type` field to `"NodePort"`, the Kubernetes master will
|
||||||
@ -537,8 +534,6 @@ This makes some kinds of firewalling impossible. The iptables proxier does not
|
|||||||
obscure in-cluster source IPs, but it does still impact clients coming through
|
obscure in-cluster source IPs, but it does still impact clients coming through
|
||||||
a load-balancer or node-port.
|
a load-balancer or node-port.
|
||||||
|
|
||||||
LoadBalancers only support TCP, not UDP.
|
|
||||||
|
|
||||||
The `Type` field is designed as nested functionality - each level adds to the
|
The `Type` field is designed as nested functionality - each level adds to the
|
||||||
previous. This is not strictly required on all cloud providers (e.g. Google Compute Engine does
|
previous. This is not strictly required on all cloud providers (e.g. Google Compute Engine does
|
||||||
not need to allocate a `NodePort` to make `LoadBalancer` work, but AWS does)
|
not need to allocate a `NodePort` to make `LoadBalancer` work, but AWS does)
|
||||||
|
@ -1458,7 +1458,7 @@ func ValidateService(service *api.Service) field.ErrorList {
|
|||||||
for i := range service.Spec.Ports {
|
for i := range service.Spec.Ports {
|
||||||
portPath := portsPath.Index(i)
|
portPath := portsPath.Index(i)
|
||||||
if !supportedPortProtocols.Has(string(service.Spec.Ports[i].Protocol)) {
|
if !supportedPortProtocols.Has(string(service.Spec.Ports[i].Protocol)) {
|
||||||
allErrs = append(allErrs, validation.NewInvalidError(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP/UDP ports"))
|
allErrs = append(allErrs, field.Invalid(portPath.Child("protocol"), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP/UDP ports"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,6 +660,7 @@ func (lb *LoadBalancer) EnsureLoadBalancer(name, region string, loadBalancerIP n
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The service controller verified all the protocols match on the ports, just check and use the first one
|
// The service controller verified all the protocols match on the ports, just check and use the first one
|
||||||
|
// TODO: Convert all error messages to use an event recorder
|
||||||
if ports[0].Protocol != api.ProtocolTCP {
|
if ports[0].Protocol != api.ProtocolTCP {
|
||||||
return nil, fmt.Errorf("Only TCP LoadBalancer is supported for openstack load balancers")
|
return nil, fmt.Errorf("Only TCP LoadBalancer is supported for openstack load balancers")
|
||||||
}
|
}
|
||||||
|
@ -378,8 +378,9 @@ func (s *ServiceController) createLoadBalancer(service *api.Service) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
name := s.loadBalancerName(service)
|
name := s.loadBalancerName(service)
|
||||||
// getPortsForLB already verified that the protocol matches for all ports.
|
// - Only one protocol supported per service
|
||||||
// The cloud provider will verify the protocol is supported
|
// - Not all cloud providers support all protocols and the next step is expected to return
|
||||||
|
// an error for unsupported protocols
|
||||||
status, err := s.balancer.EnsureLoadBalancer(name, s.zone.Region, net.ParseIP(service.Spec.LoadBalancerIP),
|
status, err := s.balancer.EnsureLoadBalancer(name, s.zone.Region, net.ParseIP(service.Spec.LoadBalancerIP),
|
||||||
ports, hostsFromNodeList(&nodes), service.Spec.SessionAffinity)
|
ports, hostsFromNodeList(&nodes), service.Spec.SessionAffinity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -494,6 +495,7 @@ func getPortsForLB(service *api.Service) ([]*api.ServicePort, error) {
|
|||||||
if protocol == "" {
|
if protocol == "" {
|
||||||
protocol = sp.Protocol
|
protocol = sp.Protocol
|
||||||
} else if protocol != sp.Protocol && wantsLoadBalancer(service) {
|
} else if protocol != sp.Protocol && wantsLoadBalancer(service) {
|
||||||
|
// TODO: Convert error messages to use event recorder
|
||||||
return nil, fmt.Errorf("mixed protocol external load balancers are not supported.")
|
return nil, fmt.Errorf("mixed protocol external load balancers are not supported.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,38 +200,6 @@ var _ = Describe("Cluster Upgrade [Skipped]", func() {
|
|||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
SkipUnlessProviderIs("gce")
|
SkipUnlessProviderIs("gce")
|
||||||
})
|
})
|
||||||
// The version is determined once at the beginning of the test so that
|
|
||||||
// the master and nodes won't be skewed if the value changes during the
|
|
||||||
// test.
|
|
||||||
By(fmt.Sprintf("Getting real version for %q", testContext.UpgradeTarget))
|
|
||||||
var err error
|
|
||||||
v, err = realVersion(testContext.UpgradeTarget)
|
|
||||||
expectNoError(err)
|
|
||||||
Logf("Version for %q is %q", testContext.UpgradeTarget, v)
|
|
||||||
|
|
||||||
By("Setting up the service, RC, and pods")
|
|
||||||
f.beforeEach()
|
|
||||||
w = NewServerTest(f.Client, f.Namespace.Name, svcName)
|
|
||||||
rc := w.CreateWebserverRC(replicas)
|
|
||||||
rcName = rc.ObjectMeta.Name
|
|
||||||
svc := w.BuildServiceSpec()
|
|
||||||
svc.Spec.Type = api.ServiceTypeLoadBalancer
|
|
||||||
w.CreateService(svc)
|
|
||||||
|
|
||||||
By("Waiting for the service to become reachable")
|
|
||||||
result, err := waitForLoadBalancerIngress(f.Client, svcName, f.Namespace.Name)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
ingresses := result.Status.LoadBalancer.Ingress
|
|
||||||
if len(ingresses) != 1 {
|
|
||||||
Failf("Was expecting only 1 ingress IP but got %d (%v): %v", len(ingresses), ingresses, result)
|
|
||||||
}
|
|
||||||
ingress = ingresses[0]
|
|
||||||
Logf("Got load balancer ingress point %v", ingress)
|
|
||||||
ip = ingress.IP
|
|
||||||
if ip == "" {
|
|
||||||
ip = ingress.Hostname
|
|
||||||
}
|
|
||||||
testLoadBalancerReachable(ingress, 80)
|
|
||||||
|
|
||||||
It("of master should maintain responsive services", func() {
|
It("of master should maintain responsive services", func() {
|
||||||
By("Validating cluster before master upgrade")
|
By("Validating cluster before master upgrade")
|
||||||
|
@ -825,7 +825,7 @@ var _ = Describe("Services", func() {
|
|||||||
svc2 := t2.BuildServiceSpec()
|
svc2 := t2.BuildServiceSpec()
|
||||||
svc2.Spec.Type = api.ServiceTypeLoadBalancer
|
svc2.Spec.Type = api.ServiceTypeLoadBalancer
|
||||||
svc2.Spec.Ports[0].Port = servicePort
|
svc2.Spec.Ports[0].Port = servicePort
|
||||||
// Let this one be UDP so that we can test that as well without an additional test
|
// UDP loadbalancing is tested via test NetcatTest
|
||||||
svc2.Spec.Ports[0].Protocol = api.ProtocolUDP
|
svc2.Spec.Ports[0].Protocol = api.ProtocolUDP
|
||||||
svc2.Spec.Ports[0].TargetPort = intstr.FromInt(80)
|
svc2.Spec.Ports[0].TargetPort = intstr.FromInt(80)
|
||||||
svc2.Spec.LoadBalancerIP = loadBalancerIP
|
svc2.Spec.LoadBalancerIP = loadBalancerIP
|
||||||
@ -1171,13 +1171,14 @@ func testLoadBalancerReachable(ingress api.LoadBalancerIngress, port int) bool {
|
|||||||
return testLoadBalancerReachableInTime(ingress, port, podStartTimeout)
|
return testLoadBalancerReachableInTime(ingress, port, podStartTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNetcatLoadBalancerReachable(ingress api.LoadBalancerIngress, port int) {
|
func testNetcatLoadBalancerReachable(ingress api.LoadBalancerIngress, port int) bool {
|
||||||
ip := ingress.IP
|
return testNetcatLoadBalancerReachableInTime(ingress, port, podStartTimeout)
|
||||||
if ip == "" {
|
}
|
||||||
ip = ingress.Hostname
|
|
||||||
}
|
|
||||||
|
|
||||||
testNetcatReachable(ip, port)
|
func conditionFuncDecorator(ip string, port int, fn func(string, int) (bool, error)) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
return fn(ip, port)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLoadBalancerReachableInTime(ingress api.LoadBalancerIngress, port int, timeout time.Duration) bool {
|
func testLoadBalancerReachableInTime(ingress api.LoadBalancerIngress, port int, timeout time.Duration) bool {
|
||||||
@ -1186,7 +1187,17 @@ func testLoadBalancerReachableInTime(ingress api.LoadBalancerIngress, port int,
|
|||||||
ip = ingress.Hostname
|
ip = ingress.Hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
return testReachableInTime(ip, port, timeout)
|
return testReachableInTime(conditionFuncDecorator(ip, port, testReachable), timeout)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNetcatLoadBalancerReachableInTime(ingress api.LoadBalancerIngress, port int, timeout time.Duration) bool {
|
||||||
|
ip := ingress.IP
|
||||||
|
if ip == "" {
|
||||||
|
ip = ingress.Hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
return testReachableInTime(conditionFuncDecorator(ip, port, testNetcatReachable), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLoadBalancerNotReachable(ingress api.LoadBalancerIngress, port int) {
|
func testLoadBalancerNotReachable(ingress api.LoadBalancerIngress, port int) {
|
||||||
@ -1198,72 +1209,83 @@ func testLoadBalancerNotReachable(ingress api.LoadBalancerIngress, port int) {
|
|||||||
testNotReachable(ip, port)
|
testNotReachable(ip, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testReachable(ip string, port int) bool {
|
func testReachable(ip string, port int) (bool, error) {
|
||||||
return testReachableInTime(ip, port, podStartTimeout)
|
url := fmt.Sprintf("http://%s:%d", ip, port)
|
||||||
|
if ip == "" {
|
||||||
|
Failf("Got empty IP for reachability check (%s)", url)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if port == 0 {
|
||||||
|
Failf("Got port==0 for reachability check (%s)", url)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Logf("Testing reachability of %v", url)
|
||||||
|
|
||||||
|
resp, err := httpGetNoConnectionPool(url)
|
||||||
|
if err != nil {
|
||||||
|
Logf("Got error waiting for reachability of %s: %v", url, err)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
Logf("Got error reading response from %s: %v", url, err)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return false, fmt.Errorf("received non-success return status %q trying to access %s; got body: %s", resp.Status, url, string(body))
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(body), "test-webserver") {
|
||||||
|
return false, fmt.Errorf("received response body without expected substring 'test-webserver': %s", string(body))
|
||||||
|
}
|
||||||
|
Logf("Successfully reached %v", url)
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNetcatReachable(ip string, port int) {
|
func testNetcatReachable(ip string, port int) (bool, error) {
|
||||||
|
uri := fmt.Sprintf("udp://%s:%d", ip, port)
|
||||||
|
if ip == "" {
|
||||||
|
Failf("Got empty IP for reachability check (%s)", uri)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if port == 0 {
|
||||||
|
Failf("Got port==0 for reachability check (%s)", uri)
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
Logf("Testing reachability of %v", uri)
|
||||||
|
|
||||||
con, err := net.Dial("udp", ip+":"+string(port))
|
con, err := net.Dial("udp", ip+":"+string(port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Failf("Failed to connect to: %s:%d (%s)", ip, port, err.Error())
|
return false, fmt.Errorf("Failed to connect to: %s:%d (%s)", ip, port, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = con.Write([]byte("\n"))
|
_, err = con.Write([]byte("\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Failf("Failed to send newline: %s", err.Error())
|
return false, fmt.Errorf("Failed to send newline: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf []byte = make([]byte, len("SUCCESS")+1)
|
var buf []byte = make([]byte, len("SUCCESS")+1)
|
||||||
|
|
||||||
_, err = con.Read(buf)
|
_, err = con.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Failf("Failed to read result: %s", err.Error())
|
return false, fmt.Errorf("Failed to read result: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(string(buf), "SUCCESS") {
|
if !strings.HasPrefix(string(buf), "SUCCESS") {
|
||||||
Failf("Failed to retrieve: \"SUCCESS\"")
|
return false, fmt.Errorf("Failed to retrieve: \"SUCCESS\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
Logf("Successfully retrieved \"SUCCESS\"")
|
Logf("Successfully retrieved \"SUCCESS\"")
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testReachableInTime(ip string, port int, timeout time.Duration) bool {
|
func testReachableInTime(testFunc wait.ConditionFunc, timeout time.Duration) bool {
|
||||||
url := fmt.Sprintf("http://%s:%d", ip, port)
|
By(fmt.Sprintf("Waiting up to %v", timeout))
|
||||||
if ip == "" {
|
err := wait.PollImmediate(poll, timeout, testFunc)
|
||||||
Failf("Got empty IP for reachability check (%s)", url)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if port == 0 {
|
|
||||||
Failf("Got port==0 for reachability check (%s)", url)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
desc := fmt.Sprintf("the url %s to be reachable", url)
|
|
||||||
By(fmt.Sprintf("Waiting up to %v for %s", timeout, desc))
|
|
||||||
start := time.Now()
|
|
||||||
err := wait.PollImmediate(poll, timeout, func() (bool, error) {
|
|
||||||
resp, err := httpGetNoConnectionPool(url)
|
|
||||||
if err != nil {
|
|
||||||
Logf("Got error waiting for reachability of %s: %v (%v)", url, err, time.Since(start))
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
Logf("Got error reading response from %s: %v", url, err)
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
return false, fmt.Errorf("received non-success return status %q trying to access %s; got body: %s", resp.Status, url, string(body))
|
|
||||||
}
|
|
||||||
if !strings.Contains(string(body), "test-webserver") {
|
|
||||||
return false, fmt.Errorf("received response body without expected substring 'test-webserver': %s", string(body))
|
|
||||||
}
|
|
||||||
Logf("Successfully reached %v", url)
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Expect(err).NotTo(HaveOccurred(), "Error waiting for %s", desc)
|
Expect(err).NotTo(HaveOccurred(), "Error waiting")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
Loading…
Reference in New Issue
Block a user