Skip to content

Commit 7500f98

Browse files
committed
Added alb.ingress.kubernetes.io/routing-target annotation which when set to pod will configure the Target Group to use the pod ip and port for the targets.
1 parent abc43a3 commit 7500f98

File tree

14 files changed

+183
-103
lines changed

14 files changed

+183
-103
lines changed

docs/ingress-resources.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ alb.ingress.kubernetes.io/healthcheck-timeout-seconds
6262
alb.ingress.kubernetes.io/healthy-threshold-count
6363
alb.ingress.kubernetes.io/unhealthy-threshold-count
6464
alb.ingress.kubernetes.io/listen-ports
65+
alb.ingress.kubernetes.io/routing-target
6566
alb.ingress.kubernetes.io/security-groups
6667
alb.ingress.kubernetes.io/subnets
6768
alb.ingress.kubernetes.io/success-codes
@@ -96,6 +97,8 @@ Optional annotations are:
9697
9798
- **listen-ports**: Defines the ports the ALB will expose. It defaults to `[{"HTTP": 80}]` unless a certificate ARN is defined, then it is `[{"HTTPS": 443}]`. Uses a format as follows '[{"HTTP":8080,"HTTPS": 443}]'.
9899
100+
- **routing-target**: Defines if the EC2 instance ID or the pod IP is added to the Target Groups. Defaults to `instance`. Valid options are `instance` and `pod`. With `instance` the Target Group targets are `<ec2 instance id>:<node port>`, for `pod` the targets are `<pod ip>:<pod port>`. When using the pod IP, it will route from all availabilty zones. `pod` is to be used when the pod network is routable and can be reached by the ALB.
101+
99102
- **security-groups**: [Security groups](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_SecurityGroups.html) that should be applied to the ALB instance. These can be referenced by security group IDs or the name tag associated with each security group. Example ID values are `sg-723a380a,sg-a6181ede,sg-a5181edd`. Example tag values are `appSG, webSG`. When the annotation is not present, the controller will create a security group with appropriate ports allowing access to `0.0.0.0/0` and attached to the ALB. It will also create a security group for instances that allows all TCP traffic when the source is the security group created for the ALB.
100103
101104
- **subnets**: The subnets where the ALB instance should be deployed. Must include 2 subnets, each in a different [availability zone](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html). These can be referenced by subnet IDs or the name tag associated with the subnet. Example values for subnet IDs are `subnet-a4f0098e,subnet-457ed533,subnet-95c904cd`. Example values for name tags are: `webSubnet,appSubnet`. If subnets are not specified the ALB controller will attempt to detect qualified subnets. This qualification is done by locating subnets that match the following criteria.
@@ -133,6 +136,7 @@ alb.ingress.kubernetes.io/healthcheck-protocol
133136
alb.ingress.kubernetes.io/healthcheck-timeout-seconds
134137
alb.ingress.kubernetes.io/healthy-threshold-count
135138
alb.ingress.kubernetes.io/unhealthy-threshold-count
139+
alb.ingress.kubernetes.io/routing-target
136140
alb.ingress.kubernetes.io/success-codes
137141
alb.ingress.kubernetes.io/target-group-attributes
138142
```

pkg/alb/lb/loadbalancer.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type NewDesiredLoadBalancerOptions struct {
4040
IngressRules []extensions.IngressRule
4141
GetServiceNodePort func(string, int32) (*int64, error)
4242
GetServiceAnnotations func(string, string) (*map[string]string, error)
43-
GetNodes func() util.AWSStringSlice
43+
TargetsFunc func(*string, string, string, *int64) albelbv2.TargetDescriptions
4444
}
4545

4646
// NewDesiredLoadBalancer returns a new loadbalancer.LoadBalancer based on the opts provided.
@@ -125,7 +125,7 @@ func NewDesiredLoadBalancer(o *NewDesiredLoadBalancerOptions) (newLoadBalancer *
125125
GetServiceNodePort: o.GetServiceNodePort,
126126
GetServiceAnnotations: o.GetServiceAnnotations,
127127
AnnotationFactory: o.AnnotationFactory,
128-
GetNodes: o.GetNodes,
128+
TargetsFunc: o.TargetsFunc,
129129
})
130130

131131
if err != nil {

pkg/alb/tg/targetgroup.go

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import (
77
"reflect"
88
"strings"
99

10-
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albrgt"
10+
api "k8s.io/api/core/v1"
1111

1212
"github.com/aws/aws-sdk-go/aws"
1313
"github.com/aws/aws-sdk-go/service/elbv2"
14+
1415
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/annotations"
1516
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albec2"
1617
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albelbv2"
18+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albrgt"
1719
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/util/log"
1820
util "github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/util/types"
19-
api "k8s.io/api/core/v1"
2021
)
2122

2223
type NewDesiredTargetGroupOptions struct {
@@ -28,7 +29,7 @@ type NewDesiredTargetGroupOptions struct {
2829
Logger *log.Logger
2930
Namespace string
3031
SvcName string
31-
Targets util.AWSStringSlice
32+
Targets albelbv2.TargetDescriptions
3233
}
3334

3435
// NewDesiredTargetGroup returns a new targetgroup.TargetGroup based on the parameters provided.
@@ -271,8 +272,8 @@ func (t *TargetGroup) modify(mods tgChange, rOpts *ReconcileOptions) error {
271272

272273
if mods&targetsModified != 0 {
273274
t.logger.Infof("Modifying target group targets.")
274-
additions := util.Difference(t.targets.desired, t.targets.current)
275-
removals := util.Difference(t.targets.current, t.targets.desired)
275+
additions := t.targets.desired.Difference(t.targets.current)
276+
removals := t.targets.current.Difference(t.targets.desired)
276277

277278
// check/change targets
278279
if len(additions) > 0 {
@@ -386,18 +387,10 @@ func (t *TargetGroup) needsModification() tgChange {
386387
}
387388

388389
// Registers Targets (ec2 instances) to TargetGroup, must be called when Current != Desired
389-
func (t *TargetGroup) registerTargets(additions util.AWSStringSlice, rOpts *ReconcileOptions) error {
390-
targets := []*elbv2.TargetDescription{}
391-
for _, target := range additions {
392-
targets = append(targets, &elbv2.TargetDescription{
393-
Id: target,
394-
Port: t.tg.current.Port,
395-
})
396-
}
397-
390+
func (t *TargetGroup) registerTargets(additions albelbv2.TargetDescriptions, rOpts *ReconcileOptions) error {
398391
in := &elbv2.RegisterTargetsInput{
399392
TargetGroupArn: t.CurrentARN(),
400-
Targets: targets,
393+
Targets: additions,
401394
}
402395

403396
if _, err := albelbv2.ELBV2svc.RegisterTargets(in); err != nil {
@@ -420,18 +413,10 @@ func (t *TargetGroup) registerTargets(additions util.AWSStringSlice, rOpts *Reco
420413
}
421414

422415
// Deregisters Targets (ec2 instances) from the TargetGroup, must be called when Current != Desired
423-
func (t *TargetGroup) deregisterTargets(removals util.AWSStringSlice, rOpts *ReconcileOptions) error {
424-
targets := []*elbv2.TargetDescription{}
425-
for _, target := range removals {
426-
targets = append(targets, &elbv2.TargetDescription{
427-
Id: target,
428-
Port: t.tg.current.Port,
429-
})
430-
}
431-
416+
func (t *TargetGroup) deregisterTargets(removals albelbv2.TargetDescriptions, rOpts *ReconcileOptions) error {
432417
in := &elbv2.DeregisterTargetsInput{
433418
TargetGroupArn: t.CurrentARN(),
434-
Targets: targets,
419+
Targets: removals,
435420
}
436421

437422
if _, err := albelbv2.ELBV2svc.DeregisterTargets(in); err != nil {
@@ -458,6 +443,6 @@ func (t *TargetGroup) CurrentARN() *string {
458443
return t.tg.current.TargetGroupArn
459444
}
460445

461-
func (t *TargetGroup) CurrentTargets() util.AWSStringSlice {
446+
func (t *TargetGroup) CurrentTargets() albelbv2.TargetDescriptions {
462447
return t.targets.current
463448
}

pkg/alb/tg/targetgroups.go

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ type NewDesiredTargetGroupsOptions struct {
129129
Logger *log.Logger
130130
GetServiceNodePort func(string, int32) (*int64, error)
131131
GetServiceAnnotations func(string, string) (*map[string]string, error)
132-
GetNodes func() util.AWSStringSlice
132+
TargetsFunc func(*string, string, string, *int64) albelbv2.TargetDescriptions
133133
}
134134

135135
// NewDesiredTargetGroups returns a new targetgroups.TargetGroups based on an extensions.Ingress.
@@ -166,7 +166,7 @@ func NewDesiredTargetGroups(o *NewDesiredTargetGroupsOptions) (TargetGroups, err
166166
Logger: o.Logger,
167167
Namespace: o.Namespace,
168168
SvcName: path.Backend.ServiceName,
169-
Targets: o.GetNodes(),
169+
Targets: o.TargetsFunc(tgAnnotations.RoutingTarget, o.Namespace, path.Backend.ServiceName, port),
170170
})
171171

172172
// If this target group is already defined, copy the current state to our new TG
@@ -178,14 +178,7 @@ func NewDesiredTargetGroups(o *NewDesiredTargetGroupsOptions) (TargetGroups, err
178178

179179
// If there is a current TG ARN we can use it to purge the desired targets of unready instances
180180
if tg.CurrentARN() != nil {
181-
targets := []*elbv2.TargetDescription{}
182-
for _, instanceID := range targetGroup.targets.desired {
183-
targets = append(targets, &elbv2.TargetDescription{
184-
Id: instanceID,
185-
Port: port,
186-
})
187-
}
188-
desired, err := albelbv2.ELBV2svc.DescribeTargetGroupTargetsForArn(tg.CurrentARN(), targets)
181+
desired, err := albelbv2.ELBV2svc.DescribeTargetGroupTargetsForArn(tg.CurrentARN(), targetGroup.targets.desired)
189182
if err != nil {
190183
return nil, err
191184
}

pkg/alb/tg/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ type attributes struct {
3535
}
3636

3737
type targets struct {
38-
current util.AWSStringSlice
39-
desired util.AWSStringSlice
38+
current albelbv2.TargetDescriptions
39+
desired albelbv2.TargetDescriptions
4040
}
4141

4242
type tags struct {

pkg/albingress/albingress.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"strings"
66
"sync"
77

8+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albelbv2"
89
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albrgt"
910

1011
"github.com/aws/aws-sdk-go/aws"
@@ -56,7 +57,7 @@ type NewALBIngressFromIngressOptions struct {
5657
ALBNamePrefix string
5758
GetServiceNodePort func(string, int32) (*int64, error)
5859
GetServiceAnnotations func(string, string) (*map[string]string, error)
59-
GetNodes func() util.AWSStringSlice
60+
TargetsFunc func(*string, string, string, *int64) albelbv2.TargetDescriptions
6061
Recorder record.EventRecorder
6162
ConnectionIdleTimeout *int64
6263
AnnotationFactory annotations.AnnotationFactory
@@ -129,7 +130,7 @@ func NewALBIngressFromIngress(o *NewALBIngressFromIngressOptions) *ALBIngress {
129130
CommonTags: newIngress.Tags(o.ClusterName),
130131
GetServiceNodePort: o.GetServiceNodePort,
131132
GetServiceAnnotations: o.GetServiceAnnotations,
132-
GetNodes: o.GetNodes,
133+
TargetsFunc: o.TargetsFunc,
133134
AnnotationFactory: o.AnnotationFactory,
134135
})
135136

pkg/albingress/albingress_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package albingress
33
import (
44
"testing"
55

6+
"github.com/aws/aws-sdk-go/service/elbv2"
7+
68
"github.com/aws/aws-sdk-go/aws"
79
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/annotations"
8-
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/util/types"
10+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albelbv2"
911
"k8s.io/api/extensions/v1beta1"
1012
extensions "k8s.io/api/extensions/v1beta1"
1113
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -71,10 +73,10 @@ func TestNewALBIngressFromIngress(t *testing.T) {
7173
a := make(map[string]string)
7274
return &a, nil
7375
},
74-
GetNodes: func() types.AWSStringSlice {
75-
instance1 := "i-1"
76-
instance2 := "i-2"
77-
return types.AWSStringSlice{&instance1, &instance2}
76+
TargetsFunc: func(*string, string, string, *int64) albelbv2.TargetDescriptions {
77+
instance1 := &elbv2.TargetDescription{Id: aws.String("i-1")}
78+
instance2 := &elbv2.TargetDescription{Id: aws.String("i-2")}
79+
return albelbv2.TargetDescriptions{instance1, instance2}
7880
},
7981
ClusterName: "testCluster",
8082
ALBNamePrefix: "albNamePrefix",

pkg/albingress/albingresses.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/annotations"
1414
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albelbv2"
1515
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albrgt"
16-
util "github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/util/types"
1716
)
1817

1918
// NewALBIngressesFromIngressesOptions are the options to NewALBIngressesFromIngresses
@@ -27,7 +26,7 @@ type NewALBIngressesFromIngressesOptions struct {
2726
DefaultIngressClass string
2827
GetServiceNodePort func(string, int32) (*int64, error)
2928
GetServiceAnnotations func(string, string) (*map[string]string, error)
30-
GetNodes func() util.AWSStringSlice
29+
TargetsFunc func(*string, string, string, *int64) albelbv2.TargetDescriptions
3130
AnnotationFactory annotations.AnnotationFactory
3231
}
3332

@@ -57,7 +56,7 @@ func NewALBIngressesFromIngresses(o *NewALBIngressesFromIngressesOptions) ALBIng
5756
ALBNamePrefix: o.ALBNamePrefix,
5857
GetServiceNodePort: o.GetServiceNodePort,
5958
GetServiceAnnotations: o.GetServiceAnnotations,
60-
GetNodes: o.GetNodes,
59+
TargetsFunc: o.TargetsFunc,
6160
Recorder: o.Recorder,
6261
AnnotationFactory: o.AnnotationFactory,
6362
})

pkg/annotations/annotations.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const (
4747
subnetsKey = "alb.ingress.kubernetes.io/subnets"
4848
successCodesKey = "alb.ingress.kubernetes.io/success-codes"
4949
successCodesAltKey = "alb.ingress.kubernetes.io/successCodes"
50+
routingTargetKey = "alb.ingress.kubernetes.io/routing-target"
5051
tagsKey = "alb.ingress.kubernetes.io/tags"
5152
ignoreHostHeader = "alb.ingress.kubernetes.io/ignore-host-header"
5253
targetGroupAttributesKey = "alb.ingress.kubernetes.io/target-group-attributes"
@@ -72,6 +73,7 @@ type Annotations struct {
7273
Ports []PortData
7374
Scheme *string
7475
IPAddressType *string
76+
RoutingTarget *string
7577
SecurityGroups util.AWSStringSlice
7678
Subnets util.Subnets
7779
SuccessCodes *string
@@ -149,6 +151,7 @@ func (vf *ValidatingAnnotationFactory) ParseAnnotations(opts *ParseAnnotationsOp
149151
a.setPorts(annotations),
150152
a.setScheme(annotations, opts.Namespace, opts.IngressName, vf.validator),
151153
a.setIPAddressType(annotations),
154+
a.setRoutingTarget(annotations),
152155
a.setSecurityGroups(annotations, vf.validator),
153156
a.setSubnets(annotations, *vf.clusterName, vf.validator),
154157
a.setSuccessCodes(annotations),
@@ -393,6 +396,18 @@ func (a *Annotations) setIPAddressType(annotations map[string]string) error {
393396
return nil
394397
}
395398

399+
func (a *Annotations) setRoutingTarget(annotations map[string]string) error {
400+
switch {
401+
case annotations[routingTargetKey] == "":
402+
a.RoutingTarget = aws.String("instance")
403+
return nil
404+
case annotations[routingTargetKey] != "instance" && annotations[routingTargetKey] != "pod":
405+
return fmt.Errorf("ALB Routing Type [%v] must be either `instance` or `pod`", annotations[routingTargetKey])
406+
}
407+
a.RoutingTarget = aws.String(annotations[routingTargetKey])
408+
return nil
409+
}
410+
396411
func (a *Annotations) setSecurityGroups(annotations map[string]string, validator Validator) error {
397412
// no security groups specified means controller should manage them, if so return and sg will be
398413
// created and managed during reconcile.

pkg/aws/albec2/ec2.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"os"
66
"time"
77

8+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/albelbv2"
9+
810
"github.com/aws/aws-sdk-go/aws"
911
"github.com/aws/aws-sdk-go/aws/ec2metadata"
1012
"github.com/aws/aws-sdk-go/aws/session"
@@ -203,10 +205,17 @@ func (e *EC2) DeleteSecurityGroupByID(sgID *string) error {
203205

204206
// DisassociateSGFromInstanceIfNeeded loops through a list of instances to see if a managedSG
205207
// exists. If it does, it attempts to remove the managedSG from the list.
206-
func (e *EC2) DisassociateSGFromInstanceIfNeeded(instances []*string, managedSG *string) error {
208+
func (e *EC2) DisassociateSGFromInstanceIfNeeded(targetDescriptions albelbv2.TargetDescriptions, managedSG *string) error {
207209
if managedSG == nil {
208210
return fmt.Errorf("Managed SG passed was empty unable to disassociate from instances")
209211
}
212+
213+
instances := targetDescriptions.InstanceIds()
214+
215+
if len(instances) < 1 {
216+
return nil
217+
}
218+
210219
in := &ec2.DescribeInstancesInput{
211220
InstanceIds: instances,
212221
}
@@ -264,7 +273,13 @@ func (e *EC2) DisassociateSGFromInstanceIfNeeded(instances []*string, managedSG
264273

265274
// AssociateSGToInstanceIfNeeded loops through a list of instances to see if newSG exists
266275
// for them. It not, it is appended to the instances(s).
267-
func (e *EC2) AssociateSGToInstanceIfNeeded(instances []*string, newSG *string) error {
276+
func (e *EC2) AssociateSGToInstanceIfNeeded(targetDescriptions albelbv2.TargetDescriptions, newSG *string) error {
277+
instances := targetDescriptions.InstanceIds()
278+
279+
if len(instances) < 1 {
280+
return nil
281+
}
282+
268283
in := &ec2.DescribeInstancesInput{
269284
InstanceIds: instances,
270285
}

0 commit comments

Comments
 (0)