mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-15 06:01:50 +00:00
Add support for managing ELB attributes with service annotations
This commit is contained in:
committed by
Kent Rancourt
parent
5962874414
commit
96dad1f0f3
@@ -84,6 +84,38 @@ const ServiceAnnotationLoadBalancerInternal = "service.beta.kubernetes.io/aws-lo
|
|||||||
// certain backends.
|
// certain backends.
|
||||||
const ServiceAnnotationLoadBalancerProxyProtocol = "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"
|
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"
|
||||||
|
|
||||||
// ServiceAnnotationLoadBalancerCertificate is the annotation used on the
|
// ServiceAnnotationLoadBalancerCertificate is the annotation used on the
|
||||||
// service to request a secure listener. Value is a valid certificate ARN.
|
// 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
|
// For more, see http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html
|
||||||
@@ -194,6 +226,9 @@ type ELB interface {
|
|||||||
ApplySecurityGroupsToLoadBalancer(*elb.ApplySecurityGroupsToLoadBalancerInput) (*elb.ApplySecurityGroupsToLoadBalancerOutput, error)
|
ApplySecurityGroupsToLoadBalancer(*elb.ApplySecurityGroupsToLoadBalancerInput) (*elb.ApplySecurityGroupsToLoadBalancerOutput, error)
|
||||||
|
|
||||||
ConfigureHealthCheck(*elb.ConfigureHealthCheckInput) (*elb.ConfigureHealthCheckOutput, error)
|
ConfigureHealthCheck(*elb.ConfigureHealthCheckInput) (*elb.ConfigureHealthCheckOutput, error)
|
||||||
|
|
||||||
|
DescribeLoadBalancerAttributes(*elb.DescribeLoadBalancerAttributesInput) (*elb.DescribeLoadBalancerAttributesOutput, error)
|
||||||
|
ModifyLoadBalancerAttributes(*elb.ModifyLoadBalancerAttributesInput) (*elb.ModifyLoadBalancerAttributesOutput, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ASG is a simple pass-through of the Autoscaling client interface, which
|
// ASG is a simple pass-through of the Autoscaling client interface, which
|
||||||
@@ -2369,6 +2404,104 @@ func (c *Cloud) EnsureLoadBalancer(clusterName string, apiService *api.Service,
|
|||||||
proxyProtocol = true
|
proxyProtocol = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some load balancer attributes are required, so defaults are set. These can be overridden by annotations.
|
||||||
|
loadBalancerAttributes := &elb.LoadBalancerAttributes{
|
||||||
|
AccessLog: &elb.AccessLog{Enabled: aws.Bool(false)},
|
||||||
|
ConnectionDraining: &elb.ConnectionDraining{Enabled: aws.Bool(false)},
|
||||||
|
ConnectionSettings: &elb.ConnectionSettings{IdleTimeout: aws.Int64(60)},
|
||||||
|
CrossZoneLoadBalancing: &elb.CrossZoneLoadBalancing{Enabled: aws.Bool(false)},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if an access log emit interval has been specified
|
||||||
|
accessLogEmitIntervalAnnotation := annotations[ServiceAnnotationLoadBalancerAccessLogEmitInterval]
|
||||||
|
if accessLogEmitIntervalAnnotation != "" {
|
||||||
|
accessLogEmitInterval, err := strconv.ParseInt(accessLogEmitIntervalAnnotation, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing service annotation: %s=%s",
|
||||||
|
ServiceAnnotationLoadBalancerAccessLogEmitInterval,
|
||||||
|
accessLogEmitIntervalAnnotation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
loadBalancerAttributes.AccessLog.EmitInterval = &accessLogEmitInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if access log enabled/disabled has been specified
|
||||||
|
accessLogEnabledAnnotation := annotations[ServiceAnnotationLoadBalancerAccessLogEnabled]
|
||||||
|
if accessLogEnabledAnnotation != "" {
|
||||||
|
accessLogEnabled, err := strconv.ParseBool(accessLogEnabledAnnotation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing service annotation: %s=%s",
|
||||||
|
ServiceAnnotationLoadBalancerAccessLogEnabled,
|
||||||
|
accessLogEnabledAnnotation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
loadBalancerAttributes.AccessLog.Enabled = &accessLogEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if access log s3 bucket name has been specified
|
||||||
|
accessLogS3BucketNameAnnotation := annotations[ServiceAnnotationLoadBalancerAccessLogS3BucketName]
|
||||||
|
if accessLogS3BucketNameAnnotation != "" {
|
||||||
|
loadBalancerAttributes.AccessLog.S3BucketName = &accessLogS3BucketNameAnnotation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if access log s3 bucket prefix has been specified
|
||||||
|
accessLogS3BucketPrefixAnnotation := annotations[ServiceAnnotationLoadBalancerAccessLogS3BucketPrefix]
|
||||||
|
if accessLogS3BucketPrefixAnnotation != "" {
|
||||||
|
loadBalancerAttributes.AccessLog.S3BucketPrefix = &accessLogS3BucketPrefixAnnotation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if connection draining enabled/disabled has been specified
|
||||||
|
connectionDrainingEnabledAnnotation := annotations[ServiceAnnotationLoadBalancerConnectionDrainingEnabled]
|
||||||
|
if connectionDrainingEnabledAnnotation != "" {
|
||||||
|
connectionDrainingEnabled, err := strconv.ParseBool(connectionDrainingEnabledAnnotation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing service annotation: %s=%s",
|
||||||
|
ServiceAnnotationLoadBalancerConnectionDrainingEnabled,
|
||||||
|
connectionDrainingEnabledAnnotation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
loadBalancerAttributes.ConnectionDraining.Enabled = &connectionDrainingEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if connection draining timeout has been specified
|
||||||
|
connectionDrainingTimeoutAnnotation := annotations[ServiceAnnotationLoadBalancerConnectionDrainingTimeout]
|
||||||
|
if connectionDrainingTimeoutAnnotation != "" {
|
||||||
|
connectionDrainingTimeout, err := strconv.ParseInt(connectionDrainingTimeoutAnnotation, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing service annotation: %s=%s",
|
||||||
|
ServiceAnnotationLoadBalancerConnectionDrainingTimeout,
|
||||||
|
connectionDrainingTimeoutAnnotation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
loadBalancerAttributes.ConnectionDraining.Timeout = &connectionDrainingTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if connection idle timeout has been specified
|
||||||
|
connectionIdleTimeoutAnnotation := annotations[ServiceAnnotationLoadBalancerConnectionIdleTimeout]
|
||||||
|
if connectionIdleTimeoutAnnotation != "" {
|
||||||
|
connectionIdleTimeout, err := strconv.ParseInt(connectionIdleTimeoutAnnotation, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing service annotation: %s=%s",
|
||||||
|
ServiceAnnotationLoadBalancerConnectionIdleTimeout,
|
||||||
|
connectionIdleTimeoutAnnotation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
loadBalancerAttributes.ConnectionSettings.IdleTimeout = &connectionIdleTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if cross zone load balancing enabled/disabled has been specified
|
||||||
|
crossZoneLoadBalancingEnabledAnnotation := annotations[ServiceAnnotationLoadBalancerCrossZoneLoadBalancingEnabled]
|
||||||
|
if crossZoneLoadBalancingEnabledAnnotation != "" {
|
||||||
|
crossZoneLoadBalancingEnabled, err := strconv.ParseBool(crossZoneLoadBalancingEnabledAnnotation)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing service annotation: %s=%s",
|
||||||
|
ServiceAnnotationLoadBalancerCrossZoneLoadBalancingEnabled,
|
||||||
|
crossZoneLoadBalancingEnabledAnnotation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
loadBalancerAttributes.CrossZoneLoadBalancing.Enabled = &crossZoneLoadBalancingEnabled
|
||||||
|
}
|
||||||
|
|
||||||
// Find the subnets that the ELB will live in
|
// Find the subnets that the ELB will live in
|
||||||
subnetIDs, err := c.findELBSubnets(internalELB)
|
subnetIDs, err := c.findELBSubnets(internalELB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2442,6 +2575,7 @@ func (c *Cloud) EnsureLoadBalancer(clusterName string, apiService *api.Service,
|
|||||||
securityGroupIDs,
|
securityGroupIDs,
|
||||||
internalELB,
|
internalELB,
|
||||||
proxyProtocol,
|
proxyProtocol,
|
||||||
|
loadBalancerAttributes,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@@ -18,6 +18,7 @@ package aws
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
@@ -30,7 +31,7 @@ import (
|
|||||||
|
|
||||||
const ProxyProtocolPolicyName = "k8s-proxyprotocol-enabled"
|
const ProxyProtocolPolicyName = "k8s-proxyprotocol-enabled"
|
||||||
|
|
||||||
func (c *Cloud) ensureLoadBalancer(namespacedName types.NamespacedName, loadBalancerName string, listeners []*elb.Listener, subnetIDs []string, securityGroupIDs []string, internalELB, proxyProtocol bool) (*elb.LoadBalancerDescription, error) {
|
func (c *Cloud) ensureLoadBalancer(namespacedName types.NamespacedName, loadBalancerName string, listeners []*elb.Listener, subnetIDs []string, securityGroupIDs []string, internalELB, proxyProtocol bool, loadBalancerAttributes *elb.LoadBalancerAttributes) (*elb.LoadBalancerDescription, error) {
|
||||||
loadBalancer, err := c.describeLoadBalancer(loadBalancerName)
|
loadBalancer, err := c.describeLoadBalancer(loadBalancerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -276,6 +277,33 @@ func (c *Cloud) ensureLoadBalancer(namespacedName types.NamespacedName, loadBala
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether the ELB was new or existing, sync attributes regardless. This accounts for things
|
||||||
|
// that cannot be specified at the time of creation and can only be modified after the fact,
|
||||||
|
// e.g. idle connection timeout.
|
||||||
|
{
|
||||||
|
describeAttributesRequest := &elb.DescribeLoadBalancerAttributesInput{}
|
||||||
|
describeAttributesRequest.LoadBalancerName = aws.String(loadBalancerName)
|
||||||
|
describeAttributesOutput, err := c.elb.DescribeLoadBalancerAttributes(describeAttributesRequest)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warning("Unable to retrieve load balancer attributes during attribute sync")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
foundAttributes := &describeAttributesOutput.LoadBalancerAttributes
|
||||||
|
|
||||||
|
// Update attributes if they're dirty
|
||||||
|
if !reflect.DeepEqual(loadBalancerAttributes, foundAttributes) {
|
||||||
|
modifyAttributesRequest := &elb.ModifyLoadBalancerAttributesInput{}
|
||||||
|
modifyAttributesRequest.LoadBalancerName = aws.String(loadBalancerName)
|
||||||
|
modifyAttributesRequest.LoadBalancerAttributes = loadBalancerAttributes
|
||||||
|
_, err = c.elb.ModifyLoadBalancerAttributes(modifyAttributesRequest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to update load balancer attributes during attribute sync: %v", err)
|
||||||
|
}
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if dirty {
|
if dirty {
|
||||||
loadBalancer, err = c.describeLoadBalancer(loadBalancerName)
|
loadBalancer, err = c.describeLoadBalancer(loadBalancerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -497,6 +497,14 @@ func (elb *FakeELB) SetLoadBalancerPoliciesForBackendServer(*elb.SetLoadBalancer
|
|||||||
panic("Not implemented")
|
panic("Not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (elb *FakeELB) DescribeLoadBalancerAttributes(*elb.DescribeLoadBalancerAttributesInput) (*elb.DescribeLoadBalancerAttributesOutput, error) {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (elb *FakeELB) ModifyLoadBalancerAttributes(*elb.ModifyLoadBalancerAttributesInput) (*elb.ModifyLoadBalancerAttributesOutput, error) {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
type FakeASG struct {
|
type FakeASG struct {
|
||||||
aws *FakeAWSServices
|
aws *FakeAWSServices
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user