Cloud Native 12 min read

How Calico CNI Plugin Creates Pod Network When Kubelet Launches a Sandbox Container

This article explains the step‑by‑step process by which kubelet creates a sandbox container, invokes the CNI interface, runs Calico’s ADD command, and sets up routes, virtual interfaces, and IP allocation for pods in a Kubernetes cluster, including relevant Go code excerpts.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
How Calico CNI Plugin Creates Pod Network When Kubelet Launches a Sandbox Container

The author shares notes on the source code of the Kubernetes Calico CNI plugin, aiming to help readers understand how Calico creates pod routes, virtual interfaces, and assigns pod IPs on worker nodes.

Overview : Calico is installed as two binaries (calico and calico‑ipam) via the calico.go source, where the former creates routes and virtual interfaces, and the latter handles IP allocation.

Sandbox container creation : When kubelet starts, it calls SyncPod which eventually creates a sandbox container. This step includes generating pod sandbox configuration, creating log directories, and invoking the container runtime (Docker in this case) to run the sandbox.

func (m *kubeGenericRuntimeManager) createPodSandbox(pod *v1.Pod, attempt uint32) (string, string, error) {
    // generate pod related config
    podSandboxConfig, err := m.generatePodSandboxConfig(pod, attempt)
    // ... create log directory
    err = m.osInterface.MkdirAll(podSandboxConfig.LogDirectory, 0755)
    // run sandbox container via runtime service
    podSandBoxID, err := m.runtimeService.RunPodSandbox(podSandboxConfig, runtimeHandler)
    return podSandBoxID, "", nil
}

The kubelet uses the CRI (Container Runtime Interface); because Docker lacks native CRI support, kubelet uses the dockershim adapter (pkg/kubelet/dockershim). The dockerService.RunPodSandbox method pulls the sandbox image, creates the container, sets up a checkpoint, starts the container, and finally calls the CNI plugin to configure networking.

func (ds *dockerService) RunPodSandbox(ctx context.Context, r *runtimeapi.RunPodSandboxRequest) (*runtimeapi.RunPodSandboxResponse, error) {
    config := r.GetConfig()
    // Pull image
    image := defaultSandboxImage
    if len(ds.podSandboxImage) != 0 {
        image = ds.podSandboxImage
    }
    if err := ensureSandboxImageExists(ds.client, image); err != nil {
        return nil, err
    }
    // Create container
    createResp, err := ds.client.CreateContainer(*createConfig)
    // Set up checkpoint, start container
    err = ds.client.StartContainer(createResp.ID)
    // Set up networking via CNI
    err = ds.network.SetUpPod(config.GetMetadata().Namespace, config.GetMetadata().Name, kubecontainer.BuildContainerID(runtimeName, createResp.ID), config.Annotations, networkOptions)
    return &runtimeapi.RunPodSandboxResponse{PodSandboxId: createResp.ID}, nil
}

The CNI plugin is invoked through cniNetworkPlugin.SetUpPod, which obtains the network namespace path, adds the loopback interface if needed, and then calls addToNetwork to hand over control to the Calico binary.

func (plugin *cniNetworkPlugin) SetUpPod(namespace string, name string, id kubecontainer.ContainerID, annotations, options map[string]string) error {
    netnsPath, err := plugin.host.GetNetNS(id.ID)
    if plugin.loNetwork != nil {
        if _, err = plugin.addToNetwork(cniTimeoutCtx, plugin.loNetwork, name, namespace, id, netnsPath, annotations, options); err != nil {
            return err
        }
    }
    _, err = plugin.addToNetwork(cniTimeoutCtx, plugin.getDefaultNetwork(), name, namespace, id, netnsPath, annotations, options)
    return err
}

The addToNetwork function builds a CNI runtime configuration and calls the CNI library’s AddNetworkList, which ultimately executes the Calico binary with the “ADD” command, passing all necessary parameters via environment variables.

func (plugin *cniNetworkPlugin) addToNetwork(ctx context.Context, network *cniNetwork, podName string, podNamespace string, podSandboxID kubecontainer.ContainerID, podNetnsPath string, annotations, options map[string]string) (cnitypes.Result, error) {
    rt, err := plugin.buildCNIRuntimeConf(podName, podNamespace, podSandboxID, podNetnsPath, annotations, options)
    res, err := cniNet.AddNetworkList(ctx, netConf, rt)
    return res, nil
}

The Calico CNI configuration (found in /etc/cni/net.d/) specifies the plugin type, IPAM method, logging, MTU, and other options. When kubelet runs the sandbox, it passes the --cni-bin-dir and --cni-conf-dir flags so that the Calico binary is located and the JSON config is read.

In summary, kubelet creates a sandbox container, invokes the CNI plugin (Calico) via the standard CNI AddNetworkList flow, and Calico then creates the necessary routes, virtual interfaces, and pod IP allocations, storing the state in its datastore.

KubernetesGoNetworksandboxCNIPodCalico
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.