Skip to content

Commit 581360c

Browse files
authored
Merge pull request #3688 from luthermonson/unmanaged-eniconfigs
Allow for Self-Managed VPC with a Secondary Subnet for Pods
2 parents 8137760 + b5f18c9 commit 581360c

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

docs/book/src/topics/eks/pod-networking.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,34 @@ spec:
4949
disableVPCCNI: false
5050
```
5151

52+
### Using Secondary CIDRs
53+
EKS allows users to assign a [secondary CIDR range](https://www.eksworkshop.com/beginner/160_advanced-networking/secondary_cidr/) for pods to be assigned. Below are how to get CAPA to generate ENIConfigs in both the managed and unmanaged VPC configurations.
54+
55+
> Secondary CIDR functionality will not work unless you enable custom network config too.
56+
57+
#### Managed (dynamic) VPC
58+
Default configuration for CAPA is to manage the VPC and all the subnets for you dynamically. It will create and delete them along with your cluster. In this method all you need to do is set a SecondaryCidrBlock to one of the allowed two IPv4 CIDR blocks: 100.64.0.0/10 and 198.19.0.0/16. CAPA will automatically generate subnets and ENIConfigs for you and the VPC CNI will do the rest.
59+
60+
```yaml
61+
kind: AWSManagedControlPlane
62+
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
63+
metadata:
64+
name: "capi-managed-test-control-plane"
65+
spec:
66+
secondaryCidrBlock: 100.64.0.0/10
67+
vpcCni:
68+
env:
69+
- name: AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG
70+
value: "true"
71+
72+
```
73+
74+
#### Unmanaged (static) VPC
75+
In an unmanaged VPC configuration CAPA will create no VPC or subnets and will instead assign the cluster pieces to the IDs you pass. In order to get ENIConfigs to generate you will need to add tags to the subnet you created and want to use as the secondary subnets for your pods. This is done through tagging the subnets with the following tag: `sigs.k8s.io/cluster-api-provider-aws/association=secondary`.
76+
77+
> Setting `SecondaryCidrBlock` in this configuration will be ignored and no subnets are created.
78+
79+
5280
## Using an alternative CNI
5381

5482
There may be scenarios where you do not want to use the Amazon VPC CNI. EKS supports a number of alternative CNIs such as Calico, Cilium, and Weave Net (see [docs](https://docs.aws.amazon.com/eks/latest/userguide/alternate-cni-plugins.html) for full list).

pkg/cloud/services/awsnode/cni.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,16 @@ func (s *Service) ReconcileCNI(ctx context.Context) error {
8080
}
8181
}
8282

83-
if s.scope.SecondaryCidrBlock() == nil {
83+
secondarySubnets := s.secondarySubnets()
84+
if len(secondarySubnets) == 0 {
8485
if needsUpdate {
8586
s.scope.Info("adding environment properties to vpc-cni", "cluster", klog.KRef(s.scope.Namespace(), s.scope.Name()))
8687
if err = remoteClient.Update(ctx, &ds, &client.UpdateOptions{}); err != nil {
8788
return err
8889
}
8990
}
91+
92+
// with no secondary subnets there is no need for eni configs
9093
return nil
9194
}
9295

@@ -101,7 +104,7 @@ func (s *Service) ReconcileCNI(ctx context.Context) error {
101104
}
102105

103106
s.scope.Info("for each subnet", "cluster", klog.KRef(s.scope.Namespace(), s.scope.Name()))
104-
for _, subnet := range s.secondarySubnets() {
107+
for _, subnet := range secondarySubnets {
105108
var eniConfig amazoncni.ENIConfig
106109
if err := remoteClient.Get(ctx, types.NamespacedName{Namespace: metav1.NamespaceSystem, Name: subnet.AvailabilityZone}, &eniConfig); err != nil {
107110
if !apierrors.IsNotFound(err) {

pkg/cloud/services/awsnode/cni_test.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"testing"
2222

23+
"github.com/aws/amazon-vpc-cni-k8s/pkg/apis/crd/v1alpha1"
2324
"github.com/aws/aws-sdk-go/aws"
2425
"github.com/golang/mock/gomock"
2526
. "github.com/onsi/gomega"
@@ -225,13 +226,30 @@ func TestReconcileCniVpcCniValues(t *testing.T) {
225226
Name: "node",
226227
},
227228
},
229+
subnets: infrav1.Subnets{
230+
{
231+
// we aren't testing reconcileSubnets where this extra conf is added so putting it in by hand
232+
ID: "sn-1234",
233+
CidrBlock: "100.0.0.1/20",
234+
Tags: infrav1.Tags{
235+
infrav1.NameAWSSubnetAssociation: infrav1.SecondarySubnetTagValue,
236+
},
237+
},
238+
},
228239
}
229240
s := NewService(m)
230241

231242
err := s.ReconcileCNI(context.Background())
232243
g.Expect(err).NotTo(HaveOccurred())
233-
g.Expect(mockClient.updateChain).NotTo(BeEmpty())
234-
ds, ok := mockClient.updateChain[0].(*v1.DaemonSet)
244+
245+
g.Expect(mockClient.updateChain).NotTo(BeEmpty()) // 0: eniconfig 1: daemonset
246+
eniconf, ok := mockClient.updateChain[0].(*v1alpha1.ENIConfig)
247+
g.Expect(ok).To(BeTrue())
248+
g.Expect(len(eniconf.Spec.SecurityGroups)).To(Equal(1))
249+
g.Expect(eniconf.Spec.SecurityGroups[0]).To(Equal(m.securityGroups["node"].ID))
250+
g.Expect(eniconf.Spec.Subnet).To(Equal(m.subnets[0].ID))
251+
252+
ds, ok := mockClient.updateChain[1].(*v1.DaemonSet)
235253
g.Expect(ok).To(BeTrue())
236254
g.Expect(ds.Spec.Template.Spec.Containers).NotTo(BeEmpty())
237255
g.Expect(ds.Spec.Template.Spec.Containers[0].Env).To(ConsistOf(tc.consistsOf))

pkg/internal/cidr/cidr_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,20 @@ func TestSplitIntoSubnetsIPv4(t *testing.T) {
3434
{
3535
// https://aws.amazon.com/about-aws/whats-new/2018/10/amazon-eks-now-supports-additional-vpc-cidr-blocks/
3636
name: "default secondary cidr block configuration with primary cidr",
37-
cidrblock: "100.64.0.0/16",
37+
cidrblock: "100.64.0.0/10",
3838
subnetcount: 3,
3939
expected: []*net.IPNet{
4040
{
4141
IP: net.IPv4(100, 64, 0, 0).To4(),
42-
Mask: net.IPv4Mask(255, 255, 192, 0),
42+
Mask: net.IPv4Mask(255, 240, 0, 0),
4343
},
4444
{
45-
IP: net.IPv4(100, 64, 64, 0).To4(),
46-
Mask: net.IPv4Mask(255, 255, 192, 0),
45+
IP: net.IPv4(100, 80, 0, 0).To4(),
46+
Mask: net.IPv4Mask(255, 240, 0, 0),
4747
},
4848
{
49-
IP: net.IPv4(100, 64, 128, 0).To4(),
50-
Mask: net.IPv4Mask(255, 255, 192, 0),
49+
IP: net.IPv4(100, 96, 0, 0).To4(),
50+
Mask: net.IPv4Mask(255, 240, 0, 0),
5151
},
5252
},
5353
},

0 commit comments

Comments
 (0)