Skip to content

Commit db4166e

Browse files
feat: support for cilium + nodesubnet
1 parent f91ab26 commit db4166e

File tree

11 files changed

+183
-59
lines changed

11 files changed

+183
-59
lines changed

.pipelines/pipeline.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,17 @@ stages:
261261
k8sVersion: ""
262262
dependsOn: "containerize"
263263

264+
# Cilium Nodesubnet E2E tests
265+
- template: singletenancy/cilium-nodesubnet/cilium-nodesubnet-e2e-job-template.yaml
266+
parameters:
267+
name: "cilium_nodesubnet_e2e"
268+
displayName: Cilium NodeSubnet
269+
clusterType: nodesubnet-byocni-nokubeproxy-up
270+
clusterName: "cilndsubnete2e"
271+
vmSize: Standard_B2s
272+
k8sVersion: ""
273+
dependsOn: "containerize"
274+
264275
# Cilium Overlay E2E tests
265276
- template: singletenancy/cilium-overlay/cilium-overlay-e2e-job-template.yaml
266277
parameters:
@@ -405,6 +416,7 @@ stages:
405416
- azure_overlay_stateless_e2e
406417
- aks_swift_e2e
407418
- cilium_e2e
419+
- cilium_nodesubnet_e2e
408420
- cilium_overlay_e2e
409421
- cilium_h_overlay_e2e
410422
- aks_ubuntu_22_linux_e2e
@@ -425,6 +437,10 @@ stages:
425437
cilium_e2e:
426438
name: cilium_e2e
427439
clusterName: "ciliume2e"
440+
region: $(REGION_AKS_CLUSTER_TEST)
441+
cilium_nodesubnet_e2e:
442+
name: cilium_nodesubnet_e2e
443+
clusterName: "cilndsubnete2e"
428444
region: $(REGION_AKS_CLUSTER_TEST)
429445
cilium_overlay_e2e:
430446
name: cilium_overlay_e2e

.pipelines/singletenancy/cilium-nodesubnet/cilium-nodesubnet-e2e-job-template.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ stages:
7171
os: ${{ parameters.os }}
7272
datapath: true
7373
dns: true
74+
cni: cilium
7475
portforward: true
7576
service: true
76-
hostport: true
7777
dependsOn: ${{ parameters.name }}
7878

7979
- job: failedE2ELogs

.pipelines/singletenancy/cilium-nodesubnet/cilium-nodesubnet-e2e-step-template.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ steps:
5757
pwd
5858
kubectl cluster-info
5959
kubectl get po -owide -A
60+
CILIUM_VERSION_TAG=${CILIUM_NODE_SUBNET_VERSION}
6061
echo "install Cilium ${CILIUM_VERSION_TAG}"
6162
export DIR=${CILIUM_VERSION_TAG%.*}
6263
echo "installing files from ${DIR}"

cns/fakes/nmagentclientfake.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ import (
1414

1515
// NMAgentClientFake can be used to query to VM Host info.
1616
type NMAgentClientFake struct {
17-
SupportedAPIsF func(context.Context) ([]string, error)
18-
GetNCVersionListF func(context.Context) (nmagent.NCVersionList, error)
19-
GetHomeAzF func(context.Context) (nmagent.AzResponse, error)
17+
SupportedAPIsF func(context.Context) ([]string, error)
18+
GetNCVersionListF func(context.Context) (nmagent.NCVersionList, error)
19+
GetHomeAzF func(context.Context) (nmagent.AzResponse, error)
20+
GetInterfaceIPInfoF func(ctx context.Context) (nmagent.Interfaces, error)
2021
}
2122

2223
func (n *NMAgentClientFake) SupportedAPIs(ctx context.Context) ([]string, error) {
@@ -30,3 +31,7 @@ func (n *NMAgentClientFake) GetNCVersionList(ctx context.Context) (nmagent.NCVer
3031
func (n *NMAgentClientFake) GetHomeAz(ctx context.Context) (nmagent.AzResponse, error) {
3132
return n.GetHomeAzF(ctx)
3233
}
34+
35+
func (n *NMAgentClientFake) GetInterfaceIPInfo(ctx context.Context) (nmagent.Interfaces, error) {
36+
return n.GetInterfaceIPInfoF(ctx)
37+
}

cns/restserver/nodesubnet.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package restserver
2+
3+
import (
4+
"context"
5+
"net/netip"
6+
7+
"github.com/Azure/azure-container-networking/cns"
8+
"github.com/Azure/azure-container-networking/cns/logger"
9+
nodesubnet "github.com/Azure/azure-container-networking/cns/nodesubnet"
10+
"github.com/Azure/azure-container-networking/cns/types"
11+
errors "github.com/pkg/errors"
12+
)
13+
14+
var _ nodesubnet.IPConsumer = &HTTPRestService{}
15+
16+
// Implement the UpdateIPsForNodeSubnet method for HTTPRestService
17+
func (service *HTTPRestService) UpdateIPsForNodeSubnet(secondaryIPs []netip.Addr) error {
18+
secondaryIPStrs := make([]string, len(secondaryIPs))
19+
for i, ip := range secondaryIPs {
20+
secondaryIPStrs[i] = ip.String()
21+
}
22+
23+
networkContainerRequest := nodesubnet.CreateNodeSubnetNCRequest(secondaryIPStrs)
24+
25+
code, msg := service.saveNetworkContainerGoalState(*networkContainerRequest)
26+
if code != types.Success {
27+
logger.Debugf("Error in processing IP change")
28+
return errors.Errorf("failed to save fetched ips. code: %d, message %s", code, msg)
29+
} else {
30+
logger.Debugf("IP change processed successfully")
31+
}
32+
33+
// saved NC successfully, generate conflist to indicate CNS is ready
34+
go service.MustGenerateCNIConflistOnce()
35+
return nil
36+
}
37+
38+
func (service *HTTPRestService) InitializeNodeSubnet(ctx context.Context, podInfoByIPProvider cns.PodInfoByIPProvider) error {
39+
// Set orchestrator type
40+
orchestrator := cns.SetOrchestratorTypeRequest{
41+
OrchestratorType: cns.KubernetesCRD,
42+
}
43+
service.SetNodeOrchestrator(&orchestrator)
44+
service.nodesubnetIPFetcher = nodesubnet.NewIPFetcher(service.nma, service, 0, 0, logger.Log)
45+
if podInfoByIPProvider == nil {
46+
logger.Printf("PodInfoByIPProvider is nil, this usually means no saved endpoint state. Skipping reconciliation")
47+
} else if _, err := nodesubnet.ReconcileInitialCNSState(ctx, service, podInfoByIPProvider); err != nil {
48+
return errors.Wrap(err, "reconcile initial CNS state")
49+
}
50+
51+
return nil
52+
}
53+
54+
func (service *HTTPRestService) StartNodeSubnet(ctx context.Context) {
55+
service.nodesubnetIPFetcher.Start(ctx)
56+
}

cns/restserver/restserver.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ import (
1313
"github.com/Azure/azure-container-networking/cns/dockerclient"
1414
"github.com/Azure/azure-container-networking/cns/logger"
1515
"github.com/Azure/azure-container-networking/cns/networkcontainers"
16+
nodesubnet "github.com/Azure/azure-container-networking/cns/nodesubnet"
1617
"github.com/Azure/azure-container-networking/cns/routes"
1718
"github.com/Azure/azure-container-networking/cns/types"
1819
"github.com/Azure/azure-container-networking/cns/types/bounded"
1920
"github.com/Azure/azure-container-networking/cns/wireserver"
2021
acn "github.com/Azure/azure-container-networking/common"
22+
"github.com/Azure/azure-container-networking/nmagent"
2123
nma "github.com/Azure/azure-container-networking/nmagent"
2224
"github.com/Azure/azure-container-networking/store"
2325
"github.com/pkg/errors"
@@ -40,6 +42,7 @@ type nmagentClient interface {
4042
SupportedAPIs(context.Context) ([]string, error)
4143
GetNCVersionList(context.Context) (nma.NCVersionList, error)
4244
GetHomeAz(context.Context) (nma.AzResponse, error)
45+
GetInterfaceIPInfo(ctx context.Context) (nmagent.Interfaces, error)
4346
}
4447

4548
type wireserverProxy interface {
@@ -76,6 +79,7 @@ type HTTPRestService struct {
7679
IPConfigsHandlerMiddleware cns.IPConfigsHandlerMiddleware
7780
PnpIDByMacAddress map[string]string
7881
imdsClient imdsClient
82+
nodesubnetIPFetcher *nodesubnet.IPFetcher
7983
}
8084

8185
type CNIConflistGenerator interface {

cns/service/main.go

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,8 @@ func main() {
661661
}
662662
if isManaged, ok := acn.GetArg(acn.OptManaged).(bool); ok && isManaged {
663663
config.ChannelMode = cns.Managed
664+
} else if cnsconfig.ChannelMode == cns.AzureHost {
665+
config.ChannelMode = cns.AzureHost
664666
}
665667

666668
homeAzMonitor := restserver.NewHomeAzMonitor(nmaClient, time.Duration(cnsconfig.AZRSettings.PopulateHomeAzCacheRetryIntervalSecs)*time.Second)
@@ -736,7 +738,6 @@ func main() {
736738
}
737739

738740
imdsClient := imds.NewClient()
739-
740741
httpRemoteRestService, err := restserver.NewHTTPRestService(&config, wsclient, &wsProxy, nmaClient,
741742
endpointStateStore, conflistGenerator, homeAzMonitor, imdsClient)
742743
if err != nil {
@@ -871,6 +872,26 @@ func main() {
871872
}
872873
}
873874

875+
if config.ChannelMode == cns.AzureHost {
876+
if !cnsconfig.ManageEndpointState {
877+
logger.Errorf("[Azure CNS] ManageEndpointState must be set to true for AzureHost mode")
878+
return
879+
} else {
880+
// If cns manageendpointstate is true, then cns maintains its own state and reconciles from it.
881+
// in this case, cns maintains state with containerid as key and so in-memory cache can lookup
882+
// and update based on container id.
883+
cns.GlobalPodInfoScheme = cns.InfraIDPodInfoScheme
884+
}
885+
886+
podInfoByIPProvider, err := getPodInfoByIPProvider(rootCtx, cnsconfig, httpRemoteRestService, nil, "")
887+
if err != nil {
888+
logger.Errorf("[Azure CNS] Failed to get PodInfoByIPProvider: %v", err)
889+
return
890+
}
891+
892+
httpRemoteRestService.InitializeNodeSubnet(rootCtx, podInfoByIPProvider)
893+
}
894+
874895
// Initialize multi-tenant controller if the CNS is running in MultiTenantCRD mode.
875896
// It must be started before we start HTTPRemoteRestService.
876897
if config.ChannelMode == cns.MultiTenantCRD {
@@ -909,6 +930,7 @@ func main() {
909930
}
910931

911932
// if user provides cns url by -c option, then only start HTTP remote server using this url
933+
912934
logger.Printf("[Azure CNS] Start HTTP Remote server")
913935
if httpRemoteRestService != nil {
914936
if cnsconfig.EnablePprof {
@@ -1019,6 +1041,10 @@ func main() {
10191041
}(privateEndpoint, infravnet, nodeID)
10201042
}
10211043

1044+
if config.ChannelMode == cns.AzureHost {
1045+
httpRemoteRestService.StartNodeSubnet(rootCtx)
1046+
}
1047+
10221048
// mark the service as "ready"
10231049
close(readyCh)
10241050
// block until process exiting
@@ -1249,40 +1275,11 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn
12491275
}
12501276
}
12511277

1252-
var podInfoByIPProvider cns.PodInfoByIPProvider
1253-
switch {
1254-
case cnsconfig.ManageEndpointState:
1255-
logger.Printf("Initializing from self managed endpoint store")
1256-
podInfoByIPProvider, err = cnireconciler.NewCNSPodInfoProvider(httpRestServiceImplementation.EndpointStateStore) // get reference to endpoint state store from rest server
1257-
if err != nil {
1258-
if errors.Is(err, store.ErrKeyNotFound) {
1259-
logger.Printf("[Azure CNS] No endpoint state found, skipping initializing CNS state")
1260-
} else {
1261-
return errors.Wrap(err, "failed to create CNS PodInfoProvider")
1262-
}
1263-
}
1264-
case cnsconfig.InitializeFromCNI:
1265-
logger.Printf("Initializing from CNI")
1266-
podInfoByIPProvider, err = cnireconciler.NewCNIPodInfoProvider()
1267-
if err != nil {
1268-
return errors.Wrap(err, "failed to create CNI PodInfoProvider")
1269-
}
1270-
default:
1271-
logger.Printf("Initializing from Kubernetes")
1272-
podInfoByIPProvider = cns.PodInfoByIPProviderFunc(func() (map[string]cns.PodInfo, error) {
1273-
pods, err := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{ //nolint:govet // ignore err shadow
1274-
FieldSelector: "spec.nodeName=" + nodeName,
1275-
})
1276-
if err != nil {
1277-
return nil, errors.Wrap(err, "failed to list Pods for PodInfoProvider")
1278-
}
1279-
podInfo, err := cns.KubePodsToPodInfoByIP(pods.Items)
1280-
if err != nil {
1281-
return nil, errors.Wrap(err, "failed to convert Pods to PodInfoByIP")
1282-
}
1283-
return podInfo, nil
1284-
})
1278+
podInfoByIPProvider, err := getPodInfoByIPProvider(ctx, cnsconfig, httpRestServiceImplementation, clientset, nodeName)
1279+
if err != nil {
1280+
return errors.Wrap(err, "failed to initialize ip state")
12851281
}
1282+
12861283
// create scoped kube clients.
12871284
directcli, err := client.New(kubeConfig, client.Options{Scheme: nodenetworkconfig.Scheme})
12881285
if err != nil {
@@ -1505,6 +1502,44 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn
15051502
return nil
15061503
}
15071504

1505+
func getPodInfoByIPProvider(ctx context.Context, cnsconfig *configuration.CNSConfig, httpRestServiceImplementation *restserver.HTTPRestService, clientset *kubernetes.Clientset, nodeName string) (podInfoByIPProvider cns.PodInfoByIPProvider, err error) {
1506+
switch {
1507+
case cnsconfig.ManageEndpointState:
1508+
logger.Printf("Initializing from self managed endpoint store")
1509+
podInfoByIPProvider, err = cnireconciler.NewCNSPodInfoProvider(httpRestServiceImplementation.EndpointStateStore) // get reference to endpoint state store from rest server
1510+
if err != nil {
1511+
if errors.Is(err, store.ErrKeyNotFound) {
1512+
logger.Printf("[Azure CNS] No endpoint state found, skipping initializing CNS state")
1513+
} else {
1514+
return podInfoByIPProvider, errors.Wrap(err, "failed to create CNS PodInfoProvider")
1515+
}
1516+
}
1517+
case cnsconfig.InitializeFromCNI:
1518+
logger.Printf("Initializing from CNI")
1519+
podInfoByIPProvider, err = cnireconciler.NewCNIPodInfoProvider()
1520+
if err != nil {
1521+
return podInfoByIPProvider, errors.Wrap(err, "failed to create CNI PodInfoProvider")
1522+
}
1523+
default:
1524+
logger.Printf("Initializing from Kubernetes")
1525+
podInfoByIPProvider = cns.PodInfoByIPProviderFunc(func() (map[string]cns.PodInfo, error) {
1526+
pods, err := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{ //nolint:govet // ignore err shadow
1527+
FieldSelector: "spec.nodeName=" + nodeName,
1528+
})
1529+
if err != nil {
1530+
return nil, errors.Wrap(err, "failed to list Pods for PodInfoProvider")
1531+
}
1532+
podInfo, err := cns.KubePodsToPodInfoByIP(pods.Items)
1533+
if err != nil {
1534+
return nil, errors.Wrap(err, "failed to convert Pods to PodInfoByIP")
1535+
}
1536+
return podInfo, nil
1537+
})
1538+
}
1539+
1540+
return podInfoByIPProvider, nil
1541+
}
1542+
15081543
// createOrUpdateNodeInfoCRD polls imds to learn the VM Unique ID and then creates or updates the NodeInfo CRD
15091544
// with that vm unique ID
15101545
func createOrUpdateNodeInfoCRD(ctx context.Context, restConfig *rest.Config, node *corev1.Node) error {

hack/aks/Makefile

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ AZIMG = mcr.microsoft.com/azure-cli
88
AZCLI ?= docker run --rm -v $(AZCFG):/root/.azure -v $(KUBECFG):/root/.kube -v $(SSH):/root/.ssh -v $(PWD):/root/tmpsrc $(AZIMG) az
99

1010
# overrideable defaults
11-
AUTOUPGRADE ?= patch
12-
K8S_VER ?= 1.30
13-
NODE_COUNT ?= 2
14-
NODE_COUNT_WIN ?= $(NODE_COUNT)
15-
NODEUPGRADE ?= NodeImage
16-
OS ?= linux # Used to signify if you want to bring up a windows nodePool on byocni clusters
17-
OS_SKU ?= Ubuntu
18-
OS_SKU_WIN ?= Windows2022
19-
REGION ?= westus2
20-
VM_SIZE ?= Standard_B2s
21-
VM_SIZE_WIN ?= Standard_B2s
11+
AUTOUPGRADE ?= patch
12+
K8S_VER ?= 1.30
13+
NODE_COUNT ?= 2
14+
NODE_COUNT_WIN ?= $(NODE_COUNT)
15+
NODEUPGRADE ?= NodeImage
16+
OS ?= linux # Used to signify if you want to bring up a windows nodePool on byocni clusters
17+
OS_SKU ?= Ubuntu
18+
OS_SKU_WIN ?= Windows2022
19+
REGION ?= westus2
20+
VM_SIZE ?= Standard_B2s
21+
VM_SIZE_WIN ?= Standard_B2s
22+
KUBE_PROXY_JSON_PATH ?= ./kube-proxy.json
2223

2324
# overrideable variables
2425
SUB ?= $(AZURE_SUBSCRIPTION)
@@ -103,13 +104,13 @@ nodesubnet-byocni-nokubeproxy-up: rg-up overlay-net-up ## Brings up an NodeSubne
103104
--kubernetes-version $(K8S_VER) \
104105
--node-count $(NODE_COUNT) \
105106
--node-vm-size $(VM_SIZE) \
106-
--load-balancer-sku basic \
107+
--load-balancer-sku standard \
107108
--max-pods 250 \
108109
--network-plugin none \
109110
--vnet-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/nodenet \
110111
--os-sku $(OS_SKU) \
111112
--no-ssh-key \
112-
--kube-proxy-config ./kube-proxy.json \
113+
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
113114
--yes
114115
@$(MAKE) set-kubeconf
115116

@@ -146,7 +147,7 @@ overlay-byocni-nokubeproxy-up: rg-up overlay-net-up ## Brings up an Overlay BYO
146147
--pod-cidr 192.168.0.0/16 \
147148
--vnet-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/nodenet \
148149
--no-ssh-key \
149-
--kube-proxy-config ./kube-proxy.json \
150+
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
150151
--yes
151152
@$(MAKE) set-kubeconf
152153

@@ -215,7 +216,7 @@ swift-byocni-nokubeproxy-up: rg-up swift-net-up ## Bring up a SWIFT BYO CNI clus
215216
--pod-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/podnet \
216217
--no-ssh-key \
217218
--os-sku $(OS_SKU) \
218-
--kube-proxy-config ./kube-proxy.json \
219+
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
219220
--yes
220221
@$(MAKE) set-kubeconf
221222

@@ -305,7 +306,7 @@ vnetscale-swift-byocni-nokubeproxy-up: rg-up vnetscale-swift-net-up ## Bring up
305306
--pod-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/podnet \
306307
--no-ssh-key \
307308
--os-sku $(OS_SKU) \
308-
--kube-proxy-config ./kube-proxy.json \
309+
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
309310
--yes
310311
@$(MAKE) set-kubeconf
311312

@@ -434,7 +435,7 @@ dualstack-byocni-nokubeproxy-up: rg-up overlay-net-up ## Brings up a Dualstack o
434435
--ip-families ipv4,ipv6 \
435436
--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/AzureOverlayDualStackPreview \
436437
--no-ssh-key \
437-
--kube-proxy-config ./kube-proxy.json \
438+
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
438439
--yes
439440
@$(MAKE) set-kubeconf
440441

0 commit comments

Comments
 (0)