Documentation Contents
Installation
Prerequisites
- Kubernetes cluster running on AWS (e.g., EKS)
- kubectl configured to access your cluster
- Helm 3.0+ (for Helm installation)
- IAM permissions for EC2 ENI operations
Install with Helm (Recommended)
# Install the latest version helm install aws-multi-eni oci://ghcr.io/johnlam90/charts/aws-multi-eni-controller --version 1.3.2 \ --namespace eni-controller-system --create-namespace # With custom values helm install aws-multi-eni oci://ghcr.io/johnlam90/charts/aws-multi-eni-controller --version 1.3.0 \ --namespace eni-controller-system --create-namespace \ --set awsRegion=us-east-1 \ --set nodeSelector.ng=multi-eni
Configuration
Basic NodeENI Resource
apiVersion: networking.k8s.aws/v1alpha1 kind: NodeENI metadata: name: multus-eni-config spec: nodeSelector: ng: multi-eni subnetID: subnet-0f59b4f14737be9ad # Use your subnet ID securityGroupIDs: - sg-05da196f3314d4af8 # Use your security group ID deviceIndex: 2 mtu: 9001 # Optional: Set MTU for jumbo frames deleteOnTermination: true description: "Multus ENI for secondary network interfaces"
Using Subnet Names Instead of IDs
apiVersion: networking.k8s.aws/v1alpha1 kind: NodeENI metadata: name: multus-eni-subnet-name spec: nodeSelector: ng: multi-eni subnetName: my-subnet-name # Subnet with this Name tag will be used securityGroupIDs: - sg-05da196f3314d4af8 deviceIndex: 2
Controller Concurrency Configuration
# In Helm values.yaml controller: maxConcurrentReconciles: 10 # Default: 5 maxConcurrentENICleanup: 5 # Default: 3
Usage Examples
Label Your Nodes
kubectl label node your-node-name ng=multi-eni
Verify ENI Creation
kubectl get nodeeni multus-eni-config -o yaml
Check Controller Logs
kubectl logs -n eni-controller-system deployment/eni-controller
Check ENI Manager Logs
kubectl logs -n eni-controller-system daemonset/eni-manager
Integration with Multus CNI
The AWS Multi-ENI Controller was primarily built to simplify the use of Multus CNI with AWS EC2 instances. Multus CNI enables attaching multiple network interfaces to Kubernetes pods, but it requires those interfaces to exist on the node first.
Example NetworkAttachmentDefinition for Multus
apiVersion: k8s.cni.cncf.io/v1 kind: NetworkAttachmentDefinition metadata: name: secondary-network spec: config: '{ "cniVersion": "0.3.1", "type": "ipvlan", "master": "eth2", "mode": "l2", "ipam": { "type": "host-local", "subnet": "192.168.1.0/24", "rangeStart": "192.168.1.200", "rangeEnd": "192.168.1.250" } }'
Example DPDK NetworkAttachmentDefinition
apiVersion: k8s.cni.cncf.io/v1 kind: NetworkAttachmentDefinition metadata: name: dpdk-network spec: config: '{ "cniVersion": "0.3.1", "type": "host-device", "device": "0000:00:06.0", "vlan": 1000, "ipam": { "type": "host-local", "subnet": "192.168.1.0/24", "rangeStart": "192.168.1.200", "rangeEnd": "192.168.1.250" } }'
Troubleshooting
Common Issues
- ENI not being created:
- Check controller logs:
kubectl logs -n eni-controller-system deployment/eni-controller
- Verify node labels:
kubectl get nodes --show-labels | grep multi-eni
- Check AWS permissions for ENI creation
- Check controller logs:
- ENI not being deleted:
- Check finalizers on NodeENI:
kubectl get nodeeni -o yaml
- Verify AWS permissions for ENI deletion
- Check finalizers on NodeENI:
- Interface not coming up:
- Check ENI Manager logs:
kubectl logs -n eni-controller-system daemonset/eni-manager
- Verify ENI Manager is running on the node
- Check ENI Manager logs:
- MTU not being applied:
- Ensure MTU is set in the NodeENI resource
- Check ENI Manager logs for MTU configuration issues
Using as a Library
The AWS Multi-ENI Controller can also be used as a Go library for programmatic ENI management:
go get github.com/johnlam90/aws-multi-eni-controller
Basic Example
package main import ( "context" "log" "time" "github.com/go-logr/logr" "github.com/go-logr/zapr" "github.com/johnlam90/aws-multi-eni-controller/pkg/lib" "go.uber.org/zap" ) func main() { // Create a logger zapLog, _ := zap.NewDevelopment() logger := zapr.NewLogger(zapLog) // Create a context with timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() // Create an ENI manager eniManager, err := lib.NewENIManager(ctx, "us-east-1", logger) if err != nil { log.Fatalf("Failed to create ENI manager: %v", err) } // Create an ENI options := lib.ENIOptions{ SubnetID: "subnet-12345678", SecurityGroupIDs: []string{"sg-12345678"}, Description: "Example ENI", DeviceIndex: 1, DeleteOnTermination: true, } eniID, err := eniManager.CreateENI(ctx, options) if err != nil { log.Fatalf("Failed to create ENI: %v", err) } log.Printf("Created ENI: %s", eniID) }