Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Surface cloud-provider-specific information in Services of type LoadBalancer #52670

Closed
yujuhong opened this issue Sep 18, 2017 · 16 comments
Closed
Assignees
Labels
kind/design Categorizes issue or PR as related to design. kind/feature Categorizes issue or PR as related to a new feature. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. sig/architecture Categorizes an issue or PR as relevant to SIG Architecture. sig/network Categorizes an issue or PR as relevant to SIG Network.

Comments

@yujuhong
Copy link
Contributor

yujuhong commented Sep 18, 2017

Service of type LoadBalancer is backed by a cloud-provider-specific load balancer. Due to the inherent differences in networking, each cloud provider supports a very different sets of features and/or configurations exposed via annotations. For example, the Service annotations supported on AWS:

const ServiceAnnotationLoadBalancerProxyProtocol = "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"
// ServiceAnnotationLoadBalancerAccessLogEmitInterval is the annotation used to
// specify access log emit interval.
const ServiceAnnotationLoadBalancerAccessLogEmitInterval = "service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval"
// ServiceAnnotationLoadBalancerAccessLogEnabled is the annotation used on the
// service to enable or disable access logs.
const ServiceAnnotationLoadBalancerAccessLogEnabled = "service.beta.kubernetes.io/aws-load-balancer-access-log-enabled"
// ServiceAnnotationLoadBalancerAccessLogS3BucketName is the annotation used to
// specify access log s3 bucket name.
const ServiceAnnotationLoadBalancerAccessLogS3BucketName = "service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name"
// ServiceAnnotationLoadBalancerAccessLogS3BucketPrefix is the annotation used
// to specify access log s3 bucket prefix.
const ServiceAnnotationLoadBalancerAccessLogS3BucketPrefix = "service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix"
// ServiceAnnotationLoadBalancerConnectionDrainingEnabled is the annnotation
// used on the service to enable or disable connection draining.
const ServiceAnnotationLoadBalancerConnectionDrainingEnabled = "service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled"
// ServiceAnnotationLoadBalancerConnectionDrainingTimeout is the annotation
// used on the service to specify a connection draining timeout.
const ServiceAnnotationLoadBalancerConnectionDrainingTimeout = "service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout"
// ServiceAnnotationLoadBalancerConnectionIdleTimeout is the annotation used
// on the service to specify the idle connection timeout.
const ServiceAnnotationLoadBalancerConnectionIdleTimeout = "service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout"
// ServiceAnnotationLoadBalancerCrossZoneLoadBalancingEnabled is the annotation
// used on the service to enable or disable cross-zone load balancing.
const ServiceAnnotationLoadBalancerCrossZoneLoadBalancingEnabled = "service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled"
// ServiceAnnotationLoadBalancerExtraSecurityGroups is the annotation used
// one the service to specify additional security groups to be added to ELB created
const ServiceAnnotationLoadBalancerExtraSecurityGroups = "service.beta.kubernetes.io/aws-load-balancer-extra-security-groups"
// ServiceAnnotationLoadBalancerCertificate is the annotation used on the
// service to request a secure listener. Value is a valid certificate ARN.
// For more, see http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html
// CertARN is an IAM or CM certificate ARN, e.g. arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
const ServiceAnnotationLoadBalancerCertificate = "service.beta.kubernetes.io/aws-load-balancer-ssl-cert"
// ServiceAnnotationLoadBalancerSSLPorts is the annotation used on the service
// to specify a comma-separated list of ports that will use SSL/HTTPS
// listeners. Defaults to '*' (all).
const ServiceAnnotationLoadBalancerSSLPorts = "service.beta.kubernetes.io/aws-load-balancer-ssl-ports"
// ServiceAnnotationLoadBalancerBEProtocol is the annotation used on the service
// to specify the protocol spoken by the backend (pod) behind a listener.
// If `http` (default) or `https`, an HTTPS listener that terminates the
// connection and parses headers is created.
// If set to `ssl` or `tcp`, a "raw" SSL listener is used.
// If set to `http` and `aws-load-balancer-ssl-cert` is not used then
// a HTTP listener is used.
const ServiceAnnotationLoadBalancerBEProtocol = "service.beta.kubernetes.io/aws-load-balancer-backend-protocol"
// ServiceAnnotationLoadBalancerAdditionalTags is the annotation used on the service
// to specify a comma-separated list of key-value pairs which will be recorded as
// additional tags in the ELB.
// For example: "Key1=Val1,Key2=Val2,KeyNoVal1=,KeyNoVal2"
const ServiceAnnotationLoadBalancerAdditionalTags = "service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags"

There are many known downsides of using annotations (e.g., lack of validation, defaulting, etc), but that's not the focus of this issue.

One problem with hiding all these vastly different implementations behind a generic Service object is that it's hard for users to introspect the status using the kubernetes API.
In fact, the LoadBalancerStatus contains only a single field, LoadBalancerIngress, which is the lowest common denominator of all possible load balancers.

// LoadBalancerStatus represents the status of a load-balancer.
type LoadBalancerStatus struct {
	// Ingress is a list containing ingress points for the load-balancer.
	// Traffic intended for the service should be sent to these ingress points.
	// +optional
	Ingress []LoadBalancerIngress `json:"ingress,omitempty" protobuf:"bytes,1,rep,name=ingress"`
}

Users would not be able to verify whether a LB is configured as expected, or whether a change to an annotation has taken effect or not (and all annotations are mutable). To actually verify the correctness of a load balancer, a user would need in-depth understanding of the both cloud networking and the implementation of cloud-provider code in the controller while interacting directly with the cloud platform UI. That doesn't lead to great user experience.

Some potential solutions that have been brought up in previous discussions:

  1. Add an opaque key-value map as part of LoadBalancerStatus.
  2. Include cloud-provide-specific information in Events. (caveat: events are ephemeral and can be spammy when used this way).

Thoughts?

@kubernetes/sig-network-feature-requests @thockin @bowei

@yujuhong yujuhong added kind/feature Categorizes issue or PR as related to a new feature. sig/network Categorizes an issue or PR as relevant to SIG Network. labels Sep 18, 2017
@thockin
Copy link
Member

thockin commented Sep 18, 2017

I like the idea of status for this. We've tried to stay away from string-string maps in general, but it seems appropriate here. Something like:

status:
  loadBalancer:
    ingress:
    - 1.2.3.4
    properties:
        cloud.google.com/fowarding-rule: a1234567890abcdef
        cloud.google.com/somethign: SomeValue

"properties" is a terrible name, but you get the idea. Better than storing annotations perhaps, though it is sort of a slippery distinction.

@smarterclayton @bgrant0607

@bowei
Copy link
Member

bowei commented Sep 18, 2017

Should there be something like a HasError: bool field at the top level? Seems useful to make that piece generic

@yujuhong
Copy link
Contributor Author

Should there be something like a HasError: bool field at the top level? Seems useful to make that piece generic

I agree that some generic fields will be useful (in addition to the opaque field), and I think it can be more than a boolean field. There is a long discussion thread on state/phase/condition/outlook in #7856. I am not sure whether any conclusion has been drawn yet.

@smarterclayton
Copy link
Contributor

smarterclayton commented Sep 19, 2017 via email

@thockin
Copy link
Member

thockin commented Sep 19, 2017 via email

@thockin thockin self-assigned this Sep 19, 2017
@bgrant0607
Copy link
Member

As for general properties, such as cases where the LB is not functioning, I agree those should just be fields, as proposed in #7856. Further motivation is discussed in #34363 and #1899.

As for cloud-specific properties or other types of extensions (e.g., with kube-proxy replaced by another solution), I think we have a number of cases where we need that across the system. Some are discussed in #31571 and in the architectural roadmap.

I can see why @smarterclayton suggested a CRD in this case.

Rather than annotations, I would like to be able to express a schema for extension parameters, sort of like StorageClass, but also with parameter descriptions and types. That starts to look like what was proposed for CRD validation. Not only could we then validate the parameters, but users could also see what options were available.

Similarly for status, we'd want to at least document what information the user could expect to be provided. And the cloud provider controller would need a mechanism to report it. A CRD with a status subresource would provide such a mechanism.

That seems much cleaner than annotations and a map of strings.

Whether we choose a status map or a CRD, I think we're going to need significant changes to Service next year, before moving it to a new API group, so we will have an opportunity to change this in the future.

OOC, is the Service type NodePort for AWS rather than type LoadBalancer? Do we need to support the additional status properties for multiple types of services?

cc @kubernetes/sig-architecture-proposals

@k8s-ci-robot k8s-ci-robot added sig/architecture Categorizes an issue or PR as relevant to SIG Architecture. kind/design Categorizes issue or PR as related to design. labels Sep 23, 2017
@thockin
Copy link
Member

thockin commented Oct 9, 2017 via email

@smarterclayton
Copy link
Contributor

smarterclayton commented Oct 9, 2017 via email

@thockin
Copy link
Member

thockin commented Oct 9, 2017 via email

@bgrant0607
Copy link
Member

bgrant0607 commented Oct 25, 2017

Ref #18451, #9106, #8992

@bgrant0607
Copy link
Member

Probably nothing prevents the service controller from writing annotations via the service /status endpoint. Is there a reason to not do that for now?

@thockin
Copy link
Member

thockin commented Oct 25, 2017 via email

@bgrant0607
Copy link
Member

In terms of patterns, I would like to be able to express application "topology" in a fully portable manner, but then also automatically discover provider-specific spec and status extensions. I think that implies we will want to embed the extensions in the portable resources, but that we do need a way to specify the schema for discovery purposes. I had originally wanted to specify such extension schemas in FooClass-style resources, but with something more like JSON schema than just a map of strings. We could potentially even automatically inject the schemas into the appropriate places in our OpenAPI spec at runtime, once we have the ability to express unions.

That may seem heavyweight, but we need more formal specs in order to build the kinds of docs and tools we need. The mass of annotations and maps of arbitrary strings we have is undiscoverable and incomprehensible to almost everyone but core project contributors.

Ref #31571.

@thockin
Copy link
Member

thockin commented Oct 27, 2017 via email

@thockin thockin added the lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. label Dec 27, 2017
@thockin thockin added the triage/unresolved Indicates an issue that can not or will not be resolved. label Mar 8, 2019
@thockin thockin removed the triage/unresolved Indicates an issue that can not or will not be resolved. label May 2, 2019
@thockin
Copy link
Member

thockin commented May 2, 2019

Moving discussion to #70159

@thockin thockin closed this as completed May 2, 2019
@sftim
Copy link
Contributor

sftim commented Dec 21, 2022

For tidiness
/close not-planned

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/design Categorizes issue or PR as related to design. kind/feature Categorizes issue or PR as related to a new feature. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. sig/architecture Categorizes an issue or PR as relevant to SIG Architecture. sig/network Categorizes an issue or PR as relevant to SIG Network.
Projects
None yet
Development

No branches or pull requests

7 participants