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

Support for NLBs targeting ALBs #2379

Closed
wants to merge 11 commits into from
22 changes: 21 additions & 1 deletion apis/elbv2/v1beta1/targetgroupbinding_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
)

// +kubebuilder:validation:Enum=instance;ip
// +kubebuilder:validation:Enum=instance;ip;alb
// TargetType is the targetType of your ELBV2 TargetGroup.
//
// * with `instance` TargetType, nodes with nodePort for your service will be registered as targets
// * with `ip` TargetType, Pods with containerPort for your service will be registered as targets
// * with `alb` TargetType, an application load balancer will be registered as the target
type TargetType string

const (
TargetTypeInstance TargetType = "instance"
TargetTypeIP TargetType = "ip"
TargetTypeALB TargetType = "alb"
)

// +kubebuilder:validation:Enum=ipv4;ipv6
Expand All @@ -43,6 +45,7 @@ const (
)

// ServiceReference defines reference to a Kubernetes Service and its ServicePort.
// This is only applicable for `instance` and `ip` target types.
type ServiceReference struct {
// Name is the name of the Service.
Name string `json:"name"`
Expand All @@ -51,6 +54,16 @@ type ServiceReference struct {
Port intstr.IntOrString `json:"port"`
}

// IngressReference defines reference to a Kubernetes Ingress and a port that it forwards traffic to.
// This is only applicable for the `alb` target type.
type IngressReference struct {
// Name is the name of the Ingress.
Name string `json:"name"`

// Port is one of the ports listed in the Ingress spec.
Port intstr.IntOrString `json:"port"`
}

// IPBlock defines source/destination IPBlock in networking rules.
type IPBlock struct {
// CIDR is the network CIDR.
Expand Down Expand Up @@ -132,8 +145,15 @@ type TargetGroupBindingSpec struct {
TargetType *TargetType `json:"targetType,omitempty"`

// serviceRef is a reference to a Kubernetes Service and ServicePort.
// This is only applicable for `instance` and `ip` target types.
// +optional
ServiceRef ServiceReference `json:"serviceRef"`

// ingressRef is a reference to a Kubernetes Ingress and a port listed in the Ingress spec.
// This is only applicable for the `alb` target type.
// +optional
IngressRef IngressReference `json:"ingressRef"`

// networking defines the networking rules to allow ELBV2 LoadBalancer to access targets in TargetGroup.
// +optional
Networking *TargetGroupBindingNetworking `json:"networking,omitempty"`
Expand Down
20 changes: 18 additions & 2 deletions config/crd/bases/elbv2.k8s.aws_targetgroupbindings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,22 @@ spec:
spec:
description: TargetGroupBindingSpec defines the desired state of TargetGroupBinding
properties:
ingressRef:
description: ingressRef is a reference to a Kubernetes Ingress and a port listed in the Ingress spec. This is only applicable for the `alb` target type.
properties:
name:
description: Name is the name of the Ingress.
type: string
port:
anyOf:
- type: integer
- type: string
description: Port is one of the ports listed in the Ingress spec.
x-kubernetes-int-or-string: true
required:
- name
- port
type: object
ipAddressType:
description: ipAddressType specifies whether the target group is of type IPv4 or IPv6. If unspecified, it will be automatically inferred.
enum:
Expand Down Expand Up @@ -283,7 +299,7 @@ spec:
type: object
type: object
serviceRef:
description: serviceRef is a reference to a Kubernetes Service and ServicePort.
description: serviceRef is a reference to a Kubernetes Service and ServicePort. This is only applicable for `instance` and `ip` target types.
properties:
name:
description: Name is the name of the Service.
Expand All @@ -307,9 +323,9 @@ spec:
enum:
- instance
- ip
- alb
type: string
required:
- serviceRef
- targetGroupARN
type: object
status:
Expand Down
5 changes: 3 additions & 2 deletions controllers/service/eventhandlers/service_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ func (h *enqueueRequestsForServiceEvent) Generic(e event.GenericEvent, queue wor
}

func (h *enqueueRequestsForServiceEvent) isServiceSupported(service *corev1.Service) bool {
lbType := ""
var lbType string
_ = h.annotationParser.ParseStringAnnotation(annotations.SvcLBSuffixLoadBalancerType, &lbType, service.Annotations)
if lbType == svcpkg.LoadBalancerTypeNLBIP {
return true
}
var lbTargetType string
_ = h.annotationParser.ParseStringAnnotation(annotations.SvcLBSuffixTargetType, &lbTargetType, service.Annotations)
if lbType == svcpkg.LoadBalancerTypeExternal && (lbTargetType == svcpkg.LoadBalancerTargetTypeIP ||
lbTargetType == svcpkg.LoadBalancerTargetTypeInstance) {
lbTargetType == svcpkg.LoadBalancerTargetTypeInstance ||
lbTargetType == svcpkg.LoadBalancerTargetTypeALB) {
return true
}
return false
Expand Down
2 changes: 1 addition & 1 deletion controllers/service/service_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func NewServiceReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorde
trackingProvider := tracking.NewDefaultProvider(serviceTagPrefix, config.ClusterName)
elbv2TaggingManager := elbv2.NewDefaultTaggingManager(cloud.ELBV2(), cloud.VpcID(), config.FeatureGates, logger)
modelBuilder := service.NewDefaultModelBuilder(annotationParser, subnetsResolver, vpcInfoProvider, cloud.VpcID(), trackingProvider,
elbv2TaggingManager, config.ClusterName, config.DefaultTags, config.ExternalManagedTags, config.DefaultSSLPolicy)
elbv2TaggingManager, k8sClient, config.ClusterName, config.DefaultTags, config.ExternalManagedTags, config.DefaultSSLPolicy)
stackMarshaller := deploy.NewDefaultStackMarshaller()
stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler, config, serviceTagPrefix, logger)
return &serviceReconciler{
Expand Down
3 changes: 2 additions & 1 deletion pkg/deploy/elbv2/target_group_binding_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func (m *defaultTargetGroupBindingManager) Delete(ctx context.Context, tgb *elbv
return err
}
if err := m.waitUntilTargetGroupBindingDeleted(ctx, tgb); err != nil {
return errors.Wrap(err, "failed to wait targetGroupBinding deletion")
return errors.Wrap(err, "failed to wait for targetGroupBinding deletion")
}
m.logger.Info("deleted targetGroupBinding",
"targetGroupBinding", k8s.NamespacedName(tgb))
Expand Down Expand Up @@ -176,6 +176,7 @@ func buildK8sTargetGroupBindingSpec(ctx context.Context, resTGB *elbv2model.Targ
TargetGroupARN: tgARN,
TargetType: resTGB.Spec.Template.Spec.TargetType,
ServiceRef: resTGB.Spec.Template.Spec.ServiceRef,
IngressRef: resTGB.Spec.Template.Spec.IngressRef,
}

if resTGB.Spec.Template.Spec.Networking != nil {
Expand Down
37 changes: 37 additions & 0 deletions pkg/deploy/elbv2/target_group_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,43 @@ func Test_buildSDKCreateTargetGroupInput(t *testing.T) {
IpAddressType: awssdk.String("ipv6"),
},
},
{
name: "standard case alb target",
args: args{
tgSpec: elbv2model.TargetGroupSpec{
Name: "my-tg",
TargetType: elbv2model.TargetTypeALB,
Port: 8080,
Protocol: elbv2model.ProtocolHTTP,
IPAddressType: &ipAddressTypeIPv4,
HealthCheckConfig: &elbv2model.TargetGroupHealthCheckConfig{
Port: &port9090,
Protocol: &protocolHTTP,
Path: awssdk.String("/healthcheck"),
Matcher: &elbv2model.HealthCheckMatcher{HTTPCode: awssdk.String("200")},
IntervalSeconds: awssdk.Int64(10),
TimeoutSeconds: awssdk.Int64(5),
HealthyThresholdCount: awssdk.Int64(3),
UnhealthyThresholdCount: awssdk.Int64(2),
},
},
},
want: &elbv2sdk.CreateTargetGroupInput{
HealthCheckEnabled: awssdk.Bool(true),
HealthCheckIntervalSeconds: awssdk.Int64(10),
HealthCheckPath: awssdk.String("/healthcheck"),
HealthCheckPort: awssdk.String("9090"),
HealthCheckProtocol: awssdk.String("HTTP"),
HealthCheckTimeoutSeconds: awssdk.Int64(5),
HealthyThresholdCount: awssdk.Int64(3),
Matcher: &elbv2sdk.Matcher{HttpCode: awssdk.String("200")},
UnhealthyThresholdCount: awssdk.Int64(2),
Name: awssdk.String("my-tg"),
Port: awssdk.Int64(8080),
Protocol: awssdk.String("HTTP"),
TargetType: awssdk.String("alb"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
17 changes: 9 additions & 8 deletions pkg/model/elbv2/target_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

var _ core.Resource = &TargetGroup{}

// TargetGroup represents a ELBV2 TargetGroup
// TargetGroup represents a ELBV2 TargetGroup.
type TargetGroup struct {
core.ResourceMeta `json:"-"`

Expand All @@ -32,12 +32,12 @@ func NewTargetGroup(stack core.Stack, id string, spec TargetGroupSpec) *TargetGr
return tg
}

// SetStatus sets the TargetGroup's status
// SetStatus sets the TargetGroup's status.
func (tg *TargetGroup) SetStatus(status TargetGroupStatus) {
tg.Status = &status
}

// LoadBalancerARN returns The Amazon Resource Name (ARN) of the target group.
// TargetGroupARN returns The Amazon Resource Name (ARN) of the target group.
func (tg *TargetGroup) TargetGroupARN() core.StringToken {
return core.NewResourceFieldStringToken(tg, "status/targetGroupARN",
func(ctx context.Context, res core.Resource, fieldPath string) (s string, err error) {
Expand All @@ -55,6 +55,7 @@ type TargetType string
const (
TargetTypeInstance TargetType = "instance"
TargetTypeIP TargetType = "ip"
TargetTypeALB TargetType = "alb"
)

type TargetGroupIPAddressType string
Expand All @@ -64,7 +65,7 @@ const (
TargetGroupIPAddressTypeIPv6 TargetGroupIPAddressType = "ipv6"
)

// Information to use when checking for a successful response from a target.
// HealthCheckMatcher contains information to use when checking for a successful response from a target.
type HealthCheckMatcher struct {
// The HTTP codes.
HTTPCode *string `json:"httpCode,omitempty"`
Expand All @@ -73,7 +74,7 @@ type HealthCheckMatcher struct {
GRPCCode *string `json:"grpcCode,omitempty"`
}

// Configuration for TargetGroup's HealthCheck.
// TargetGroupHealthCheckConfig contains configuration for TargetGroup's HealthCheck.
type TargetGroupHealthCheckConfig struct {
// The port the load balancer uses when performing health checks on targets.
// +optional
Expand Down Expand Up @@ -108,7 +109,7 @@ type TargetGroupHealthCheckConfig struct {
UnhealthyThresholdCount *int64 `json:"unhealthyThresholdCount,omitempty"`
}

// Specifies a target group attribute.
// TargetGroupAttribute specifies a target group attribute.
type TargetGroupAttribute struct {
// The name of the attribute.
Key string `json:"key"`
Expand All @@ -117,7 +118,7 @@ type TargetGroupAttribute struct {
Value string `json:"value"`
}

// TargetGroupSpec defines the observed state of TargetGroup
// TargetGroupSpec defines the observed state of TargetGroup.
type TargetGroupSpec struct {
// The name of the target group.
Name string `json:"name"`
Expand Down Expand Up @@ -152,7 +153,7 @@ type TargetGroupSpec struct {
Tags map[string]string `json:"tags,omitempty"`
}

// TargetGroupStatus defines the observed state of TargetGroup
// TargetGroupStatus defines the observed state of TargetGroup.
type TargetGroupStatus struct {
// The Amazon Resource Name (ARN) of the target group.
TargetGroupARN string `json:"targetGroupARN"`
Expand Down
7 changes: 7 additions & 0 deletions pkg/model/elbv2/target_group_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,15 @@ type TargetGroupBindingSpec struct {
TargetType *elbv2api.TargetType `json:"targetType,omitempty"`

// serviceRef is a reference to a Kubernetes Service and ServicePort.
// This is only applicable for `instance` and `ip` target types.
// +optional
ServiceRef elbv2api.ServiceReference `json:"serviceRef"`

// ingressRef is a reference to a Kubernetes Ingress and a port listed in the Ingress spec.
// This is only applicable for the `alb` target type.
// +optional
IngressRef elbv2api.IngressReference `json:"ingressRef"`

// networking provides the networking setup for ELBV2 LoadBalancer to access targets in TargetGroup.
// +optional
Networking *TargetGroupBindingNetworking `json:"networking,omitempty"`
Expand Down
Loading