前言
在上个版本中,我们实现了容器的基本操作。这一次将实现容器网络部分。
Hook
纵观OCI Runtime标准,并没有定义网络标准。根据学习和推测,我认为它是通过hook实现的网络设置。
Hook就是一些在容器特定生命周期被调用的程序。
1 | "hooks": { |
如这个例子所示,在创建容器时,我们让Runtime调用setup-network程序。
Persistent Namespace
在第一个版本里,我们并没有在创建容器时调用pviot_root
,而是在运行容器时才更换系统目录,创建新的命名空间。这将无法满足createContainer hook
的要求。
1 | (Executed in Container NS) During the create operation, after the runtime environment has been created and before the pivot root or any equivalent operation. |
要实现这个hook,我们要在创建容器时就创建命名空间,并且允许hook程序对这些命名空间做一些操作。当我们运行容器时,之前的改动都必须还在,所以这些命名空间必须被持久化。
根据Linux手册,命名空间存放在/proc/<PID>/ns/*flie
,当进程退出时,这些文件也就释放掉了,除非这些文件被bind-mount到另外的地方。
mount("/proc/pid/ns/net", "/home/ubuntu/container/ns/net", MS_BIND, nullptr)
之后,可以通过setns函数来恢复这些命名空间。
其中困难的地方在于
- mnt ns必须被挂在Private mount point
- pid ns没有必要持久化,必须保持容器进程运行,再将hook程序加入对应pid ns。每次容器运行,都创建新的pid ns
Network
Github上有一个现成的hook供我们使用,叫做netns。我们可以先用netns验证runtime工作正常,以后再实现自己的hook,从而达成全部自己实现的目标。
通过netns源码可知,在启动netns时,runtime需要将容器的status传递到netns的stdin。因为我在上一版本中,已经实现了将status保存为文件,这里只要将status.file打开,并设置fd为stdin,之后调用exec运行hook,将fd传递给子进程,就可以了。
1 | // posix ensure it opens the least available fd |
status里带有pid,netns通过访问/proc/pid/ns,获取到目标network namespace,再将创建的veth link过去。
netns默认没有打开bridge的转发功能。
1 | sudp ifconfig <bridgename> up |