自己动手写 Docker 系列 -- 6.5 启动时给容器配置网络

docker-compose文件中networks使用已经创建的网络 前置条件: docker版本为:18.06.1-ce,build e68fc7a docker-compose版本:1.22.0,build f46880fe 使用已经存在的网络 使用docker创建一个网络。给出示例如下: docker network create --driver=bridge --subnet=192.168.88.0/24 demo 执行命令查看网络是否创建... 阅读详情

简介

在上几篇文章中,我们使用自己程序创建的网桥和手动配置,让容器的网络功能正常,本篇就利用之前的知识,自动配置容器网络

源码说明

同时放到了 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.Infof("端口映射:%s, %s", ep.IpAddress, ep.PortMapping)
	// 遍历容器端口映射列表
	for _, pm := range ep.PortMapping {
		// 分割宿主机的端口和容器的端口
		portMapping := strings.Split(pm, ":")
		if len(portMapping) != 2 {
			log.Errorf("port mapping format err: %v", pm)
			continue
		}

		// 由于iptable没有go语言版本的实现,所以采用exec.command的方式直接调用命令配置
		// 在iptables的PREROUTING中添加DNAT规则
		// 将宿主机的端口请求转发到容器的地址和端口上
		iptableCmd := fmt.Sprintf("-t nat -A PREROUTING -p tcp -m tcp --dport %s -j DNAT --to-destination %s:%s",
			portMapping[0], ep.IpAddress.String(), portMapping[1])
		log.Infof(iptableCmd)
		// 执行iptables命令,添加端口映射和转发规则
		cmd := exec.Command("iptables", strings.Split(iptableCmd, " ")...)
		output, err := cmd.Output()
		if err != nil {
			log.Errorf("iptables output err:%s -- %v", output, err)
			continue
		}
	}
	return nil
}

配置容器 veth

在书中是先设置了 veth,在进入容器中,将 veth 放入容器中

但经过尝试,这样不生效,需要在将 veth 放入容器后,然后进行配置,才能生效

所有下面的代码进行了调整


// 配置容器网络端点的地址和路由
func configEndpointIpAddressAndRoute(ep *Endpoint, cinfo *container.ContainerInfo) error {
	// 通过网络端点中Veth的另一端
	peerLink, err := netlink.LinkByName(ep.Device.PeerName)
	if err != nil {
		return fmt.Errorf("fail config endpoint err: %w", err)
	}
	log.Infof("peerLink index: %d -- %s", peerLink.Attrs().Index, peerLink.Attrs().Name)

	// 将容器的网络端点加入到容器的网络空间中
	// 并使这个函数下面的操作都在这个网络空间中进行
	// 执行完函数后,恢复为默认的网络空间,具体实现参考具体函数
	defer enterContainerNetns(&peerLink, cinfo, ep)

	return nil
}

// 将容器的网络端点加入到容器的网络空间中
// 并锁定当前程序所执行的线程,使当前线程进入到容器的网络空间
// 返回值是一个函数指针,执行这个返回函数才会退出容器的网络空间,回归到宿主机的网络空间
// 这个函数中引用了之前介绍的github.com/vishvananda/netns类库来做namespace操作
func enterContainerNetns(enLink *netlink.Link, cinfo *container.ContainerInfo, ep *Endpoint) func() {
	log.Infof("enterContainerNetns: %s", cinfo.Pid)

	// 找到容器的net namespa
	// /proc/{pid}/ns/net打开这个文件的文件描述符就可以来操作net namespace
	// 而containInfo中的PID,即容器在宿主机上映射的进程ID
	// 它对应的 /proc/{pid}/ns/net 就是容器内部的net namespace
	f, err := os.OpenFile(fmt.Sprintf("/proc/%s/ns/net", cinfo.Pid), os.O_RDONLY, 0)
	if err != nil {
		log.Errorf("error get container net namespace, %v", err)
	}

	// 取到文件的文件描述符
	nsFD := f.Fd()

	// 锁定当前程序所执行的线程,如果不锁定操作系统线程的话
	// go 语言的groutine可能会调度到别的线程上去
	// 就不能保证一致在所需要的网络空间中
	// 所以调用runtime。lockOSThread时要先锁定当前程序锁定的线程
	runtime.LockOSThread()

	// 修改veth peer另外一端移动容器的namespace中
	if err = netlink.LinkSetNsFd(*enLink, int(nsFD)); err != nil {
		log.Errorf("error set link netns, %v", err)
	}

	// 获取当前网络的namespace
	originNet, err := netns.Get()
	if err != nil {
		log.Errorf("get current netns err: %v", err)
	}

	// 设置当前进程到新的网络namespace,并咋函数执行完成后,再恢复到之前的namespace
	if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
		log.Errorf("error set netns, %v", err)
	}

	// 获取到容器的ip地址及网段,用于配置容器内部接口地址
	// 比如容器IP是192.168.1.2,而网络的网段是192.168.1.0/24
	// 那么这里产出的ip字符串就是192.168.1.2/24,用于容器内veth的配置
	interfaceIp := *ep.Network.IpRange
	interfaceIp.IP = ep.IpAddress
	log.Infof("容器的ip地址和网段:%s, %s", interfaceIp.String(), interfaceIp.IP.String())

	// 启动容器内的veth端点
	if err = setInterfaceUp(ep.Device.PeerName); err != nil {
		//return fmt.Errorf("setInterfaceUp ip %s, err: %w", ep.Device.PeerName, err)
		log.Errorf("setInterfaceUp ip %s, err: %w", ep.Device.PeerName, err)
	}
	// 调用函数设置容器内的Veth端点的IP
	if err = setInterfaceIp(ep.Device.PeerName, interfaceIp.String()); err != nil {
		//return fmt.Errorf("setinterface ip %v, err: %w", ep.Network, err)
		log.Errorf("setinterface ip %v, err: %w", ep.Network, err)
	}
	// net namespace中默认的本地地址是127.0.0.1 的lo网卡关闭状态
	// 启动它以保证容器访问自己的请求
	if err = setInterfaceUp("lo"); err != nil {
		//return fmt.Errorf("setInterfaceUp ip lo, err: %w", err)
		log.Errorf("setInterfaceUp ip lo, err: %w", err)
	}

	// 设置容器内的外部请求都通过容器内的veth端点网络
	// 0.0.0.0/0 的网段,标识所有的ip地址段
	_, cidr, _ := net.ParseCIDR("0.0.0.0/0")

	// 构建要添加的路由数据,包括网络设备、网关IP及目的网段
	// 相当于route add -net 0.0.0.0/0 gw {bridge 网桥地址} dev {容器内的veth端点设备}
	defaultRoute := &netlink.Route{
		LinkIndex: (*enLink).Attrs().Index,
		Gw:        ep.Network.GatewayIP,
		Dst:       cidr,
	}
	log.Infof("default route: %s", defaultRoute.String())

	// 调用netlink的routeAdd,添加路由到容器内的网络空间
	// routeadd函数相当于route add命令
	if err = netlink.RouteAdd(defaultRoute); err != nil {
		//return fmt.Errorf("add route err: %w", err)
		log.Errorf("add route err: %w", err)
	}

	// 返回之前的net namespace
	// 在容器的网络空间中,执行完容器配置之后,调用此函数就可以将程序恢复到原生的net namespace
	return func() {
		// 恢复到上面获取到的之前的net namespace
		_ = netns.Set(originNet)
		// 关闭namespace
		_ = originNet.Close()
		// 取消对当前程序的线程锁定
		runtime.UnlockOSThread()
		// 关闭namespace文件
		_ = f.Close()
		log.Infof("退出容器网络空间")
	}
}

测试运行

先启动第一个容器,看看是否正常使用

# 创建网络
./main network create --driver bridge --subnet 192.168.10.1/24 testbridge

# 启动容器
$ ./main run -ti -net testbridge -name test1 sh
{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"load ipam file from: /var/run/mydocker/network/ipam/subnet.json","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"allocate subnet: 162.16.0.4/24, ip: 162.16.0.4","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"dump ipam file from: /var/run/mydocker/network/ipam/","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"分配的容器ip地址为: 162.16.0.4","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"init come on","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"current location: /home/lw/code/go/dockerDemo/mnt","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"peerLink index: 10 -- cif-21765","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"enterContainerNetns: 7789","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"容器的ip地址和网段:162.16.0.4/24, 162.16.0.4","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"ip link set up: cif-21765 -- 10","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"add addr, iface: 10 -- cif-21765, ip: 162.16.0.4/24","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"ip link set up: lo -- 1","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"default route: {Ifindex: 10 Dst: 0.0.0.0/0 Src: \u003cnil\u003e Gw: 162.16.0.1 Flags: [] Table: 0}","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"all command is : sh","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"parent process run","time":"2022-04-24T05:25:03+08:00"}
{"level":"info","msg":"find path: /bin/sh","time":"2022-04-24T05:25:03+08:00"}

# 看到lo和veth都设置正常
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
10: cif-21765@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue qlen 1000
    link/ether 5e:a5:ca:22:8e:53 brd ff:ff:ff:ff:ff:ff
    inet 162.16.0.4/24 brd 162.16.0.255 scope global cif-21765
       valid_lft forever preferred_lft forever
    inet6 fe80::5ca5:caff:fe22:8e53/64 scope link
       valid_lft forever preferred_lft forever

# 路由也是设置正常
/ # ip r
default via 162.16.0.1 dev cif-21765
162.16.0.0/24 dev cif-21765 scope link  src 162.16.0.4

# ping 网关正常
/ # ping 162.16.0.1
PING 162.16.0.1 (162.16.0.1): 56 data bytes
64 bytes from 162.16.0.1: seq=0 ttl=64 time=0.136 ms
64 bytes from 162.16.0.1: seq=1 ttl=64 time=0.146 ms
^C
--- 162.16.0.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.136/0.141/0.146 ms

# ping 宿主机正常
/ # ping 192.168.1.5
PING 192.168.1.5 (192.168.1.5): 56 data bytes
64 bytes from 192.168.1.5: seq=0 ttl=64 time=0.206 ms
64 bytes from 192.168.1.5: seq=1 ttl=64 time=0.163 ms
64 bytes from 192.168.1.5: seq=2 ttl=64 time=0.148 ms
^C
--- 192.168.1.5 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.148/0.172/0.206 ms

# ping 外网正常
/ # ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114): 56 data bytes
64 bytes from 114.114.114.114: seq=0 ttl=67 time=35.061 ms
64 bytes from 114.114.114.114: seq=1 ttl=70 time=34.040 ms
^C
--- 114.114.114.114 ping statistics ---
3 packets transmitted, 2 packets received, 33% packet loss
round-trip min/avg/max = 34.040/34.550/35.061 ms

启动第二个带端口映射的容器

# 启动第二个容器
$ ./main run -ti -net testbridge -name test2 -p 90:90 sh
{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"load ipam file from: /var/run/mydocker/network/ipam/subnet.json","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"allocate subnet: 162.16.0.8/24, ip: 162.16.0.8","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"dump ipam file from: /var/run/mydocker/network/ipam/","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"分配的容器ip地址为: 162.16.0.8","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"init come on","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"current location: /home/lw/code/go/dockerDemo/mnt","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"端口映射:162.16.0.8, [90:90]","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"-t nat -A PREROUTING -p tcp -m tcp --dport 90 -j DNAT --to-destination 162.16.0.8:90","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"peerLink index: 18 -- cif-76526","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"enterContainerNetns: 9443","time":"2022-04-24T05:37:19+08:00"}
{"level":"info","msg":"容器的ip地址和网段:162.16.0.8/24, 162.16.0.8","time":"2022-04-24T05:37:20+08:00"}
{"level":"info","msg":"ip link set up: cif-76526 -- 18","time":"2022-04-24T05:37:20+08:00"}
{"level":"info","msg":"add addr, iface: 18 -- cif-76526, ip: 162.16.0.8/24","time":"2022-04-24T05:37:20+08:00"}
{"level":"info","msg":"ip link set up: lo -- 1","time":"2022-04-24T05:37:20+08:00"}
{"level":"info","msg":"default route: {Ifindex: 18 Dst: 0.0.0.0/0 Src: \u003cnil\u003e Gw: 162.16.0.1 Flags: [] Table: 0}","time":"2022-04-24T05:37:20+08:00"}
{"level":"info","msg":"all command is : sh","time":"2022-04-24T05:37:20+08:00"}
{"level":"info","msg":"parent process run","time":"2022-04-24T05:37:20+08:00"}
{"level":"info","msg":"find path: /bin/sh","time":"2022-04-24T05:37:20+08:00"}

# 监听容器的90端口,可以看到从外网使用Telnet访问正常
/ # nc -lp 90
fdsj
^Cpunt!

# ping我们的第一个容器正常
/ # ping 162.16.0.4
PING 162.16.0.4 (162.16.0.4): 56 data bytes
64 bytes from 162.16.0.4: seq=0 ttl=64 time=0.119 ms
64 bytes from 162.16.0.4: seq=1 ttl=64 time=0.150 ms
64 bytes from 162.16.0.4: seq=2 ttl=64 time=0.148 ms
64 bytes from 162.16.0.4: seq=3 ttl=64 time=0.147 ms
64 bytes from 162.16.0.4: seq=4 ttl=64 time=0.149 ms
^C
--- 162.16.0.4 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.119/0.142/0.150 ms

# ping 外网正常
/ # ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114): 56 data bytes
64 bytes from 114.114.114.114: seq=0 ttl=75 time=34.561 ms
64 bytes from 114.114.114.114: seq=1 ttl=69 time=33.634 ms
^C
--- 114.114.114.114 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 33.634/34.097/34.561 ms

我们回到宿主机,看到下面的网课和 IPtables 配置和我们预期的一样

# 看到了设置的相关的规则
$ iptables  -t  nat  -nL --line-numbers
Chain PREROUTING (policy ACCEPT)
num  target     prot opt source               destination
1    DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL
2    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:90 to:162.16.0.8:90

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination
1    DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
num  target     prot opt source               destination
1    MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
2    MASQUERADE  all  --  162.16.0.0/24        0.0.0.0/0

Chain DOCKER (2 references)
num  target     prot opt source               destination
1    RETURN     all  --  0.0.0.0/0            0.0.0.0/0

# ip查看,有我们启动的两个容器veth
$ ip a
5: testbridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 42:2a:4b:44:dd:0c brd ff:ff:ff:ff:ff:ff
    inet 162.16.0.1/24 brd 162.16.0.255 scope global testbridge
       valid_lft forever preferred_lft forever
    inet6 fe80::acda:9eff:fe9d:e125/64 scope link
       valid_lft forever preferred_lft forever
11: 21765@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master testbridge state UP group default qlen 1000
    link/ether 42:2a:4b:44:dd:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::402a:4bff:fe44:dd0c/64 scope link
       valid_lft forever preferred_lft forever
19: 76526@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master testbridge state UP group default qlen 1000
    link/ether e6:d6:ef:8e:90:7c brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::e4d6:efff:fe8e:907c/64 scope link
       valid_lft forever preferred_lft forever

总结

这个网络部分总算是基本完了,这部分卡了快两周了,看了好多书和资料

本篇结合之前的手动配置知识,将容器的网络进行配置

Docker容器网络 Docker容器网络、Docker容器网络配置、容器常用操作 阅读详情

相关推荐

WARN[0000] a network with name milvus exists but was not created for project “milvus“.Set `external

如果网络已经存在,添加配置。如果网络不存在,让 Docker Compose 自动创建网络。使用检查现有网络。

NLP与推荐算法 424

Docker容器网络配置

docker容器网络配置linux内核实现名称空间的创建ip netns命令创建Network Namespace操作Network Namespace转移设备veth pair创建veth pair实现Network Namespaceveth pair设备重命名 linux内核实现名称空间的创建 ip netns命令 可以借助ip netns命令来完成对 Network Namespace 的各种操作。ip netns命令来自于iproute安装包,一般系统会默认安装,如果没有的话,请自行安装。 注意:

z07121的博客 420

如何实现三种不同RAM?(单端口RAM、伪双端口RAM、真双端口RAM|verilog代码|Testbench|仿真结果)

RAM(随机存取存储器)是计算机系统中的一种主要存储器件,用于存储和读取数据。在RAM中,单端口RAM(Single-port RAM)和双端口RAM(Dual-port RAM)是两种常见的类型,双端口RAM又分为真双端口(True dual-port RAM)和伪双端口RAM(Simple dual-port RAM)。那么什么是单端口和双端口?又该如何区分真双端口和伪双端口?输入只有一组数据线和一组地址线,读写共用地址线,输出只有一个端口。

Loudrs的博客 1万+

配置 External 网络

介绍 External 就是外部网络,相当于 Float ip,External 网络走的是 br-ex,也就是物理 eth1 网卡,对于 External 网络我们只需要创建一个就够了,而所有的租户都用这一个 External 到外网。 我们用管理员创建一个 External 网络后,剩下的就交给每个租户自己来创建自己的网络了。 Quantum 里的名词理解: Network:分为 Ex

tycoon的专栏 4523

ad23新版Geber导出-官方教程(22.11版本后)

AD23新版本geber文件导出(含官方教程)-22.11之后的版本均可用此教程

安和的博客 3万+

别再乱选保护板了!手把手教你用ABLIC S-8254A为3/4串锂电池组DIY安全保护电路

本文详细介绍了如何使用ABLIC S-8254A保护集成电路为3/4串锂电池组DIY安全保护电路。从选型策略、电路搭建到功能验证,手把手教你实现可靠的充放电保护系统,适用于无人机、电动工具等场景,确保锂电池组的安全使用。

weixin_42525264的博客 187

docker-compose加入已经存在的网络

docker-compose加入已经存在的网络

进击的豌豆的博客 1万+

实战指南:UOS专业版命令行高效下载离线安装包及依赖

本文提供了一份UOS专业版离线安装包的实战下载指南。针对无外网环境下的软件部署难题,详细介绍了如何通过命令行精准获取软件包名,并利用`apt download`命令高效下载主程序及其所有依赖。文章重点解析了使用`apt install --dry-run`模拟安装来完整获取依赖包的方法,并给出了离线安装、问题排查及自动化脚本编写等高级技巧,帮助管理员和运维人员实现可靠的批量离线部署。

honey的博客 1109

自己动手写 Docker 系列文章总览

本文章系列起源于:《自己动手写 Docker》,编程实践方得真知,虽然大部分代码书中都有,但还是遇到了不少困难,下面是对于自己写的 Docker Demo 的总览

github_35735591的博客 2268

从零开始:手把手教你检查并更新英伟达GPU驱动和CUDA版本(Windows/Linux双平台)

本文详细指导如何在Windows和Linux系统上检查并更新英伟达GPU驱动和CUDA版本,解决版本不匹配导致的常见问题。涵盖驱动更新、CUDA Toolkit安装、版本冲突排解及性能优化技巧,帮助开发者高效管理GPU计算环境。

weixin_29237635的博客 701

铁路场景雷达点云目标识别与追踪系统

本文介绍了一种基于毫米波雷达的铁路货运车站安全监控系统。该系统采用分布式架构,通过多个毫米波雷达节点采集点云数据,经过坐标转换、多雷达融合等处理后,利用机器学习算法实现列车、行人等目标的实时识别与追踪。系统包含数据采集层、处理层、目标识别层、追踪层、预警决策层和可视化层,能够克服传统视频监控受环境影响大的缺点,实现全天候可靠监测。文中详细展示了雷达数据解析和点云预处理的代码实现,包括坐标转换、数据格式解析和体素网格滤波等关键技术。该系统可有效预警铁路场景下的碰撞风险,提升货运车站的安全管理水平。

huanghm88的专栏 124

Docker的网络配置

一.基本网络配置–docker网络模式 docker的镜像是令人称道的地方,但网络功能还是相对薄弱的部分。 docker安装后会自动创建3种网络:bridge、host、none Docker在启动时会开启一个虚拟网桥设备docker0,默认的地址为172.17.0.1/16,容器启动后都会被桥接到docker0上,并自动分配到一个ip地址 实验: 1.查看docker的网络有哪些(发现有三种...

hetoto的博客 3万+

【OS】AUTOSAR OS系统调用产生Trap的过程详解

AUTOSAR OS系统调用产生Trap的过程详解

qq_36056498的博客 2438

docker 启动时指定需要绑定的网卡_Docker学习笔记:Docker 网络配置

Dokcer 通过使用 Linux 桥接提供容器之间的通信,docker0 桥接接口的目的就是方便 Docker 管理。当 Docker daemon 启动时需要做以下操作:creates the docker0 bridge if not present# 如果 docker0 不存在则创建searches for an IP address range which doesn’t o...

weixin_42511396的博客 4286

数字电路逻辑与设计实验三 译码器和数据选择器

1. 译码器功能测试 将 74LS139 按图 3.1 接线,按表 3.2 输入电平分别置位,填输出状态表。 2. 译码器转换 将双 2-4 线译码器转换为 3-8 线译码器。 (1)画出转换电路图。 (2)在实验箱上接线并验证设计是否正确。 (3)设计并填表写该 3-8 线译码器功能表,画出输入、输出波形。 3. 数据选择器的测试及应用 (1) 将双 4 选 1 数据选择器 74LS153 参照图 3.2 接线,测试其功能并填写功能表 3.3。 (2)将实验箱脉冲信号源中固定连续脉冲 4 个不

欢迎交流学习心得 3085

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

docker容器网络与配置

docker容器网络与配置 文章目录docker容器网络与配置一. docker4种网络模式1. 用 ` docker network ls ` 可以查看3种网络模式2. docker网络模式3. bridge模式,桥接模式4. container模式,容器模式5. host模式,主机模式6. none模式,无网络模式二. docker容器网络配置1. 网络名称空间的创建与配置1.1 内核名称空间的创建1.2 启动两个lo网卡1.3 创建veth pair 将veth0和veth1两个虚拟网卡连接了起来1.

mushuangpanny的博客 1417

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

6.docker容器网络配置

docker 容器网络配置

阿干tkl的博客 1105

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Docker容器该如何配置网络?

文章目录一,docker网络概述 一,docker网络概述 1.1docker网络实现的原理 docker使用的linux桥接,就是在宿主机上虚拟一个docker容器网桥(docker0),docker启动一个容器时会根据docker网桥的网段分配一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP通信。 容器内我用的是nginx镜像,所以我们用 apt-get update a

OSoooo的博客 7682

docker容器网络及其配置

docker容器网络及其配置

qq_58733916的博客 1948

docker容器网络配置

docker4种网络模式的特点、虚拟设备创建应用、容器的常用操作

tian的博客 1539

docker【6】docker网络配置

dokcer网络配置 docker修改bridge

既认准这条路,又何必在意要走多久 9637

docker网络模式及配置

一、Docker网络模式 1 1、host模式 1 2、container模式 1 3、none模式 2 4、bridge模式 2 二、Docker网络配置–设置固定IP 2 1、host宿主机下载pipework如下: 2 2、安装网桥工具包bridge-utils 2 3、创建网桥并设置IP网段 2 4、启动一个容器 2 5、设置IP 2 6、网桥管理 2 7、docker版本1.9以后可使用下面这种方式: 3 7.1创建自定义网络 3 7.2启动Docker容器 3 7.3确认自建网络的容器 3

beck_li的博客 3624

容器云系列之Docker网络管理及容器互联

Docker网络有bridge、host、overlay、macvlan和none五种模式,本文对这几种网络模式进行验证并测试容器间的互联通信。

牧羊人的方向 1981

Docker系列(四)Docker 网络模式及配置

四种网络模式摘自 Docker 网络详解及 pipework 源码解读与实践 一、Docker网络模式 docker run 创建 Docker 容器时,可以用 –net 选项指定容器的网络模式,Docker 有以下 4 种网络模式: host 模式,使用 –net=host 指定。 container 模式,使用 –net=container:NAME_or_ID 指定。 none ...

淡淡的倔强的博客 1万+

docker容器网络

。。

weixin_72901306的博客 3767
上一篇: 自己动手写Docker系列 -- 6.3 手动配置容器网络(下)
下一篇: Docker知识对应验证
_萧_
博客等级 码龄10年 55粉丝 157原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值