导读:京东数科一直致力于构建基于kubernetes的大规模容器集群,经受618和双11的流量考验。
在我们京东数科的kubernetes容器集群中,网络插件使用的是contiv,容器运行时使用的是默认的docker,一直以来它们配合的非常好。但是当我们把容器运行时更换为containerd或者cri-o时,pod却一直无法创建成功。查看日志发现,一直打印类似这样的错误:Err: invalid nw name space: /var/run/netns/cni-4128c748-11b7-58bf-9a98-6e740c4e7f13
,于是定位到导致该错误的源码位于nsToPID函数中,如下:
// mgmtfn/k8splugin/driver.go// nsToPID is a utility that extracts the PID from the netns
func nsToPID(ns string) (int, error) {
ok := strings.HasPrefix(ns, "/proc/")if !ok {
return -1, fmt.Errorf("invalid nw name space: %v", ns)}
elements := strings.Split(ns, "/")return strconv.Atoi(elements[2])}
该函数的实现比较简单,首先检查传入的ns字符串是否以/proc/开头,如果不是则直接返回错误。而出错的时候,ns的值类似/var/run/netns/cni-4128c748-11b7-58bf-9a98-6e740c4e7f13这种格式,显然不符合条件。我们也通过日志发现,当容器运行时是默认的docker时,ns的值是类似proc/12345/ns/net这种格式的,它可以通过格式检查,并返回正确的pid。那现在问题基本明确了,当容器运行时是docker时,ns的值是proc/[pid]/ns/net
这种格式的;当容器运行时是containerd或者cri-o时,ns的值是/var/run/netns/[xxx]
这种格式的,导致解析失败。所以我们就从最初的源头分析,到底是什么原因导致了两种格式的ns的存在,以及如何解决这个问题。
1. contiv的整体架构
contiv是kubernetes集群中提供容器跨主机通讯的开源网络插件,能够支持二层、三层、overlay、aci等多种模式。它的整体架构如下图:
其中,netctl是一个命令行管理工具。netmaster是整个contiv集群的管理控制结点。netplugin需要部署在集群的每个结点上,负责创建ovs流表、通告BGP路由等实际工作。contivk8s也需要部署在集群的每个结点上,它是kubelet与netplugin之间的适配器,负责将kubelet发送过来的cni(container network interface)请求转换为netplugin可以接受的数据格式。
2. kubernetes集群中使用非docker容器运行时
在kubernetes集群中,kubelet里面默认配置的容器运行时是docker,但是可以通过kubelet的参数container-runtime和container-runtime-endpoint来使用其他的容器运行时,例如containerd和cri-o。此时,container-runtime需要设置为remote,同时container-runtime-endpoint需要设置为具体的容器运行时监听的套接字地址,例如unix:///run/containerd/containerd.sock
。在kubernetes集群中,之所以能够使用各种不同的容器运行时,是因为kubernetes中规定了容器运行时(container runtime interface)的标准,只要按照cri标准开发的容器运行时,都可以集成到kubernete集群中。
我们知道,kubelet在创建pod时,首先创