Skip to content

feat: add support to set ProtocolVersion based on annotation values #1589

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

Merged
merged 4 commits into from
Nov 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/guide/ingress/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ You can add annotations to kubernetes Ingress and Service objects to customize t
|[alb.ingress.kubernetes.io/ssl-policy](#ssl-policy)|string|ELBSecurityPolicy-2016-08|Ingress|Exclusive|
|[alb.ingress.kubernetes.io/target-type](#target-type)|instance \| ip|instance|Ingress,Service|N/A|
|[alb.ingress.kubernetes.io/backend-protocol](#backend-protocol)|HTTP \| HTTPS|HTTP|Ingress,Service|N/A|
|[alb.ingress.kubernetes.io/backend-protocol-version](#backend-protocol-version)|string | HTTP1 |Ingress,Service|N/A|
|[alb.ingress.kubernetes.io/target-group-attributes](#target-group-attributes)|stringMap|N/A|Ingress,Service|N/A|
|[alb.ingress.kubernetes.io/healthcheck-port](#healthcheck-port)|integer \| traffic-port|traffic-port|Ingress,Service|N/A|
|[alb.ingress.kubernetes.io/healthcheck-protocol](#healthcheck-protocol)|HTTP \| HTTPS|HTTP|Ingress,Service|N/A|
Expand Down Expand Up @@ -155,6 +156,13 @@ Traffic Routing can be controlled with following annotations:
alb.ingress.kubernetes.io/backend-protocol: HTTPS
```

- <a name="backend-protocol-version">`alb.ingress.kubernetes.io/backend-protocol-version`</a> specifies the application protocol used to route traffic to pods. Only valid when HTTP or HTTPS is used as the backend protocol.

!!!example
```
alb.ingress.kubernetes.io/backend-protocol-version: HTTP2
```

- <a name="subnets">`alb.ingress.kubernetes.io/subnets`</a> specifies the [Availability Zone](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) that ALB will route traffic to. See [Load Balancer subnets](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-subnets.html) for more details.

!!!note ""
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module sigs.k8s.io/aws-load-balancer-controller
go 1.13

require (
github.com/aws/aws-sdk-go v1.35.4
github.com/aws/aws-sdk-go v1.35.18
github.com/go-logr/logr v0.1.0
github.com/golang/mock v1.2.0
github.com/google/go-cmp v0.4.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ github.com/aws/aws-sdk-go v1.33.14 h1:ucjyVEvtIdtn4acf+RKsgk6ybAYeMLXpGZeqoVvi7K
github.com/aws/aws-sdk-go v1.33.14/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.35.4 h1:GG0sdhmzQSe4/UcF9iuQP9i+58bPRyU4OpujyzMlVjo=
github.com/aws/aws-sdk-go v1.35.4/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/aws/aws-sdk-go v1.35.18 h1:Gka1bopihF2e9XFhuVZPrgafmOFpCsRtAPMYLp/0AfA=
github.com/aws/aws-sdk-go v1.35.18/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
Expand Down
92 changes: 92 additions & 0 deletions mocks/aws/services/mock_ec2.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/annotations/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
IngressSuffixSSLPolicy = "ssl-policy"
IngressSuffixTargetType = "target-type"
IngressSuffixBackendProtocol = "backend-protocol"
IngressSuffixBackendProtocolVersion = "backend-protocol-version"
IngressSuffixTargetGroupAttributes = "target-group-attributes"
IngressSuffixHealthCheckPort = "healthcheck-port"
IngressSuffixHealthCheckProtocol = "healthcheck-protocol"
Expand Down
3 changes: 3 additions & 0 deletions pkg/deploy/elbv2/target_group_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ func buildSDKCreateTargetGroupInput(tgSpec elbv2model.TargetGroupSpec) *elbv2sdk
sdkObj.TargetType = awssdk.String(string(tgSpec.TargetType))
sdkObj.Port = awssdk.Int64(tgSpec.Port)
sdkObj.Protocol = awssdk.String(string(tgSpec.Protocol))
if tgSpec.ProtocolVersion != nil {
sdkObj.ProtocolVersion = (*string)(tgSpec.ProtocolVersion)
}
if tgSpec.HealthCheckConfig != nil {
hcConfig := *tgSpec.HealthCheckConfig
sdkObj.HealthCheckEnabled = awssdk.Bool(true)
Expand Down
39 changes: 39 additions & 0 deletions pkg/deploy/elbv2/target_group_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ func Test_isSDKTargetGroupHealthCheckDrifted(t *testing.T) {
func Test_buildSDKCreateTargetGroupInput(t *testing.T) {
port9090 := intstr.FromInt(9090)
protocolHTTP := elbv2model.ProtocolHTTP
protocolVersionHTTP2 := elbv2model.ProtocolVersionHTTP2
type args struct {
tgSpec elbv2model.TargetGroupSpec
}
Expand Down Expand Up @@ -394,6 +395,44 @@ func Test_buildSDKCreateTargetGroupInput(t *testing.T) {
TargetType: awssdk.String("ip"),
},
},
{
name: "standard case with protocol version",
args: args{
tgSpec: elbv2model.TargetGroupSpec{
Name: "my-tg",
TargetType: elbv2model.TargetTypeIP,
Port: 8080,
Protocol: elbv2model.ProtocolHTTP,
ProtocolVersion: &protocolVersionHTTP2,
HealthCheckConfig: &elbv2model.TargetGroupHealthCheckConfig{
Port: &port9090,
Protocol: &protocolHTTP,
Path: awssdk.String("/healthcheck"),
Matcher: &elbv2model.HealthCheckMatcher{HTTPCode: "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"),
ProtocolVersion: awssdk.String("HTTP2"),
TargetType: awssdk.String("ip"),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/deploy/elbv2/target_group_synthesizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ func isSDKTargetGroupRequiresReplacement(sdkTG TargetGroupWithTags, resTG *elbv2
if string(resTG.Spec.Protocol) != awssdk.StringValue(sdkTG.TargetGroup.Protocol) {
return true
}
if resTG.Spec.ProtocolVersion != nil {
if string(*resTG.Spec.ProtocolVersion) != awssdk.StringValue(sdkTG.TargetGroup.ProtocolVersion) {
return true
}
}

return isSDKTargetGroupRequiresReplacementDueToNLBHealthCheck(sdkTG, resTG)
}
Expand Down
25 changes: 23 additions & 2 deletions pkg/ingress/model_build_target_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ func (t *defaultModelBuildTask) buildTargetGroupSpec(ctx context.Context,
if err != nil {
return elbv2model.TargetGroupSpec{}, err
}
tgProtocolVersion, err := t.buildTargetGroupProtocolVersion(ctx, svcAndIngAnnotations)
if err != nil {
return elbv2model.TargetGroupSpec{}, err
}
healthCheckConfig, err := t.buildTargetGroupHealthCheckConfig(ctx, svc, svcAndIngAnnotations, targetType, tgProtocol)
if err != nil {
return elbv2model.TargetGroupSpec{}, err
Expand All @@ -124,12 +128,13 @@ func (t *defaultModelBuildTask) buildTargetGroupSpec(ctx context.Context,
}

tgPort := t.buildTargetGroupPort(ctx, targetType, svcPort)
name := t.buildTargetGroupName(ctx, k8s.NamespacedName(ing), svc, port, tgPort, targetType, tgProtocol)
name := t.buildTargetGroupName(ctx, k8s.NamespacedName(ing), svc, port, tgPort, targetType, tgProtocol, tgProtocolVersion)
return elbv2model.TargetGroupSpec{
Name: name,
TargetType: targetType,
Port: tgPort,
Protocol: tgProtocol,
ProtocolVersion: &tgProtocolVersion,
HealthCheckConfig: &healthCheckConfig,
TargetGroupAttributes: tgAttributes,
Tags: tags,
Expand All @@ -141,7 +146,7 @@ var invalidTargetGroupNamePattern = regexp.MustCompile("[[:^alnum:]]")
// buildTargetGroupName will calculate the targetGroup's name.
func (t *defaultModelBuildTask) buildTargetGroupName(_ context.Context,
ingKey types.NamespacedName, svc *corev1.Service, port intstr.IntOrString, tgPort int64,
targetType elbv2model.TargetType, tgProtocol elbv2model.Protocol) string {
targetType elbv2model.TargetType, tgProtocol elbv2model.Protocol, tgProtocolVersion elbv2model.ProtocolVersion) string {
uuidHash := sha256.New()
_, _ = uuidHash.Write([]byte(t.clusterName))
_, _ = uuidHash.Write([]byte(t.ingGroup.ID.String()))
Expand All @@ -152,6 +157,7 @@ func (t *defaultModelBuildTask) buildTargetGroupName(_ context.Context,
_, _ = uuidHash.Write([]byte(strconv.Itoa(int(tgPort))))
_, _ = uuidHash.Write([]byte(targetType))
_, _ = uuidHash.Write([]byte(tgProtocol))
_, _ = uuidHash.Write([]byte(tgProtocolVersion))
uuid := hex.EncodeToString(uuidHash.Sum(nil))

sanitizedNamespace := invalidTargetGroupNamePattern.ReplaceAllString(svc.Namespace, "")
Expand Down Expand Up @@ -201,6 +207,21 @@ func (t *defaultModelBuildTask) buildTargetGroupProtocol(_ context.Context, svcA
}
}

func (t *defaultModelBuildTask) buildTargetGroupProtocolVersion(_ context.Context, svcAndIngAnnotations map[string]string) (elbv2model.ProtocolVersion, error) {
rawBackendProtocolVersion := string(t.defaultBackendProtocolVersion)
_ = t.annotationParser.ParseStringAnnotation(annotations.IngressSuffixBackendProtocolVersion, &rawBackendProtocolVersion, svcAndIngAnnotations)
switch rawBackendProtocolVersion {
case string(elbv2model.ProtocolVersionHTTP1):
return elbv2model.ProtocolVersionHTTP1, nil
case string(elbv2model.ProtocolVersionHTTP2):
return elbv2model.ProtocolVersionHTTP2, nil
case string(elbv2model.ProtocolVersionGRPC):
return elbv2model.ProtocolVersionGRPC, nil
default:
return "", errors.Errorf("backend protocol version must be within [%v, %v, %v]: %v", elbv2model.ProtocolVersionHTTP1, elbv2model.ProtocolVersionHTTP2, elbv2model.ProtocolVersionGRPC, rawBackendProtocolVersion)
}
}

func (t *defaultModelBuildTask) buildTargetGroupHealthCheckConfig(ctx context.Context, svc *corev1.Service, svcAndIngAnnotations map[string]string, targetType elbv2model.TargetType, tgProtocol elbv2model.Protocol) (elbv2model.TargetGroupHealthCheckConfig, error) {
healthCheckPort, err := t.buildTargetGroupHealthCheckPort(ctx, svc, svcAndIngAnnotations, targetType)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions pkg/ingress/model_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func (b *defaultModelBuilder) Build(ctx context.Context, ingGroup Group) (core.S
defaultSSLPolicy: "ELBSecurityPolicy-2016-08",
defaultTargetType: elbv2model.TargetTypeInstance,
defaultBackendProtocol: elbv2model.ProtocolHTTP,
defaultBackendProtocolVersion: elbv2model.ProtocolVersionHTTP1,
defaultHealthCheckPath: "/",
defaultHealthCheckIntervalSeconds: 15,
defaultHealthCheckTimeoutSeconds: 5,
Expand Down Expand Up @@ -138,6 +139,7 @@ type defaultModelBuildTask struct {
defaultSSLPolicy string
defaultTargetType elbv2model.TargetType
defaultBackendProtocol elbv2model.Protocol
defaultBackendProtocolVersion elbv2model.ProtocolVersion
defaultHealthCheckPath string
defaultHealthCheckTimeoutSeconds int64
defaultHealthCheckIntervalSeconds int64
Expand Down
8 changes: 8 additions & 0 deletions pkg/model/elbv2/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ const (
ProtocolTCP_UDP Protocol = "TCP_UDP"
)

type ProtocolVersion string

const (
ProtocolVersionHTTP1 ProtocolVersion = "HTTP1"
ProtocolVersionHTTP2 ProtocolVersion = "HTTP2"
ProtocolVersionGRPC ProtocolVersion = "GRPC"
)

// The type of action.
type ActionType string

Expand Down
4 changes: 4 additions & 0 deletions pkg/model/elbv2/target_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ type TargetGroupSpec struct {
// The protocol to use for routing traffic to the targets.
Protocol Protocol `json:"protocol"`

// The target group protocol version.
// +optional
ProtocolVersion *ProtocolVersion `json:"protocolVersion,omitempty"`

// Configuration for TargetGroup's HealthCheck.
// +optional
HealthCheckConfig *TargetGroupHealthCheckConfig `json:"healthCheckConfig,omitempty"`
Expand Down