简介
在上几篇文章中,我们使用自己程序创建的网桥和手动配置,让容器的网络功能正常,本篇就利用之前的知识,自动配置容器网络
源码说明
同时放到了 Gitee 和 Github 上,都可进行获取
本章节对应的版本标签是:6.3,防止后面代码过多,不好查看,可切换到标签版本进行查看
代码实现
书中原来的实现基本上是顺序是合理的,但在博主机器上在网络启动部分有些问题,做一些调整,在后面的代码部分会讲到
整体的思路是根据我们上两篇文章:
整体的思路如下:
- 使用 network 命令创建网桥
- 程序启动的时候,制定网桥
- 设置宿主机段的 veth:挂载到网桥,设置启动
- 设置端口映射,如果有-p 选项
- 设置容器内的 veth:先进入容器,设置 lo 和 veth,分配 IP,设置启动
在书中是先设置容器内的 veth,在进入容器网络命名空间,在博主机器上有点问题,就做了调整
新增命令选项
在 run 命令中增加-net 和-p 选项,用于制定网桥和端口映射
var RunCommand = cli.Command{
Name: "run",
Usage: `Create a container with namespace and cgroups limit mydocker run -ti [command]`,
Flags: []cli.Flag{
......
cli.StringFlag{
Name: "net",
Usage: "container network",
},
cli.StringSliceFlag{
Name: "p",
Usage: "port mapping",
},
},
Action: func(context *cli.Context) error {
......
network := context.String("net")
portMapping := context.StringSlice("p")
run.Run(tty, detach, cmdArray, resConfig, volume, containerName, envSlice, network, portMapping)
return nil
},
}
启动是配置网络
在 Run 函数中,如果有 net 选项,就为容器配置网络
func Run(tty, detach bool, cmdArray []string, config *subsystem.ResourceConfig, volume, containerName string,
......
if nw != "" {
// 定义网络
_ = network.Init()
containerInfo := &container.ContainerInfo{
ID: id,
Pid: strconv.Itoa(parent.Process.Pid),
Name: containerName,
PortMapping: portMapping,
}
if err := network.Connect(nw, containerInfo); err != nil {
log.Errorf("connnect network err: %v", err)
return
}
}
......
}
配置网络就分为三部分了:配置宿主机 veth、配置宿主机端口映射路由、配置容器 veth
func Connect(networkName string, cinfo *container.ContainerInfo) error {
network, ok := networks[networkName]
if !ok {
return fmt.Errorf("no such network: %s", networkName)
}
// 分配容器IP地址
_, ipNet, _ := net.ParseCIDR(network.Subnet)
ip, err := ipAllocator.Allocate(ipNet)
if err != nil {
return err
}
log.Infof("分配的容器ip地址为: %s", ip)
// 创建网络端点
ep := &Endpoint{
ID: fmt.Sprintf("%s-%s", cinfo.ID, networkName),
IpAddress: ip,
Network: network,
PortMapping: cinfo.PortMapping,
}
// 调用网络驱动挂载和配置网络端点
if err = drivers[network.Driver].Connect(network, ep); err != nil {
log.Errorf("connet err: %v", err)
return err
}
// 配置端口映射
if err = configPortMapping(ep, cinfo); err != nil {
log.Errorf("config port mapping: %v", err)
return err
}
// 到容器的namespace配置容器的网络设备IP地址
if err = configEndpointIpAddressAndRoute(ep, cinfo); err != nil {
log.Errorf("configEndpointIpAddressAndRoute err: %v", err)
return err
}
return nil
}
配置宿主机 veth
这部分是调用原来的驱动的 Connect 函数,这里就不再重复说明了
配置宿主机端口映射路由
设置端口映射就是我们上两篇文字中的配置 iptables 的 DNAT 规则,这里实现也是直接使用的命令
// 配置端口映射
func configPortMapping(ep *Endpoint, cinfo *container.ContainerInfo) error {
log.