1. 前言
由于原理在前面几篇文章已经介绍过了, 如果直接用
go
语言直接执行命令也可以达到目的, 目前有直接可以用的api
, 所以接下来就看看这些api
如何操作的.
2. 关于网桥的API 测试
使用
github.com/vishvananda/netlink
相关的api.
2.1 添加一个网桥
// 等于 ip link add name testbridge type bridge
func TestNet001(t *testing.T) {
bridgeName := "testbridge"
_, err := net.InterfaceByName(bridgeName)
if err == nil || !strings.Contains(err.Error(), "no such network interface") {
log.Printf("error:%v\n", err)
}
// create *netlink.Bridge object
la := netlink.NewLinkAttrs()
la.Name = bridgeName
br := &netlink.Bridge{la}
// 等于 ip link add name testbridge type bridge
if err := netlink.LinkAdd(br); err != nil {
fmt.Errorf("Bridge creation failed for bridge %s: %v", bridgeName, err)
}
}
测试, 可以看到经过运行后增加一个
testbridge
设备, 但是目前是DOWN
状态并且没有ip
地址.
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:58:9a:c3 brd ff:ff:ff:ff:ff:ff
3: docker0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# go test -v api_test.go -test.run TestNet001
=== RUN TestNet001
--- PASS: TestNet001 (0.00s)
PASS
ok command-line-arguments 0.003s
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:58:9a:c3 brd ff:ff:ff:ff:ff:ff
3: docker0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
32: testbridge: mtu 1500 qdisc noop state DOWN mode DEFAULT group default
link/ether e6:e5:e4:62:ee:a8 brd ff:ff:ff:ff:ff:ff
2.2 设置网桥地址 状态
- 根据设备名找到设备testbridge
- ip addr add 13. 92.168.0.1/24 dev testbridge
- ip link set testbridge up
func TestNet002(t *testing.T) {
name := "testbridge"
rawIP := "192.168.0.1/24"
retries := 2
var iface netlink.Link
var err error
for i := 0; i < retries; i++ {
// 根据名字找到设备
iface, err = netlink.LinkByName(name)
if err == nil {
break
}
log.Printf("error retrieving new bridge netlink link [ %s ]... retrying", name)
time.Sleep(2 * time.Second)
}
if err != nil {
fmt.Errorf("Abandoning retrieving the new bridge link from netlink, Run [ ip link ] to troubleshoot the error: %v", err)
}
// 将原始ip转换成*net.IPNet类型
ipNet, err := netlink.ParseIPNet(rawIP)
if err != nil {
log.Printf("ParseIPNet error:%v\n", err)
}
log.Printf("ipNet:%v\n", ipNet)
addr := &netlink.Addr{ipNet, "", 0, 0, nil}
// 等于 ip addr add 192.168.0.1/24 dev testbridge
err = netlink.AddrAdd(iface, addr)
log.Printf("AddrAdd error:%v\n", err)
// 等于 ip link set testbridge up
if err := netlink.LinkSetUp(iface); err != nil {
fmt.Errorf("Error enabling interface for %s: %v", name, err)
}
}
测试, 可以看到
testbridge
的地址为192.168.0.1
, 地址为UNDOWN
.
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# go test -v api_test.go -test.run TestNet002
=== RUN TestNet002
2019/05/05 20:57:44 ipNet:192.168.0.1/24
2019/05/05 20:57:44 AddrAdd error:
--- PASS: TestNet002 (0.00s)
PASS
ok command-line-arguments 0.003s
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:58:9a:c3 brd ff:ff:ff:ff:ff:ff
3: docker0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
32: testbridge: mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/ether e6:e5:e4:62:ee:a8 brd ff:ff:ff:ff:ff:ff
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# ifconfig
docker0 Link encap:Ethernet HWaddr 56:84:7a:fe:97:99
inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:68 errors:0 dropped:0 overruns:0 frame:0
TX packets:39 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3990 (3.9 KB) TX bytes:3599 (3.5 KB)
eth0 Link encap:Ethernet HWaddr 52:54:00:58:9a:c3
inet addr:172.19.16.7 Bcast:172.19.31.255 Mask:255.255.240.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:11304762 errors:0 dropped:0 overruns:0 frame:0
TX packets:9226749 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:5638409305 (5.6 GB) TX bytes:5757777940 (5.7 GB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:66 errors:0 dropped:0 overruns:0 frame:0
TX packets:66 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:6180 (6.1 KB) TX bytes:6180 (6.1 KB)
testbridge Link encap:Ethernet HWaddr e6:e5:e4:62:ee:a8
inet addr:192.168.0.1 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
root@nicktming:~/go/src/github.com/nicktming/mydocker/network#
2.3 往网桥上attach设备
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# bridge link
root@nicktming:~/go/src/github.com/nicktming/mydocker/network#
可以看到网桥testbridge上没有任何设备
func TestNet003(t *testing.T) {
bridgeName := "testbridge"
// 根据设备名找到设备testbridge
br, err := netlink.LinkByName(bridgeName)
if err != nil {
log.Printf("LinkByName err:%v\n", err)
return
}
la := netlink.NewLinkAttrs()
la.Name = "12345"
log.Printf("br.attrs().index:%d\n", br.Attrs().Index)
// 等于 ip link set dev 12345 master testbridge
la.MasterIndex = br.Attrs().Index
myVeth := netlink.Veth{
LinkAttrs: la,
PeerName: "cif-" + la.Name,
}
// 等于 ip link add 12345 type veth peer name cif-12345
if err = netlink.LinkAdd(&myVeth); err != nil {
fmt.Errorf("Error Add Endpoint Device: %v", err)
return
}
// 等于 ip link set 12345 up
if err = netlink.LinkSetUp(&myVeth); err != nil {
fmt.Errorf("Error Add Endpoint Device: %v", err)
return
}
}
测试, 可以看到增加了一对
veth设备
, (12345
和cif-12345
). 并且12345
已经attach
到testbridge
上了.
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# go test -v api_test.go -test.run TestNet003
=== RUN TestNet003
2019/05/05 21:16:35 br.attrs().index:32
--- PASS: TestNet003 (0.00s)
PASS
ok command-line-arguments 0.007s
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:58:9a:c3 brd ff:ff:ff:ff:ff:ff
3: docker0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
32: testbridge: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 86:7c:c1:7e:56:9a brd ff:ff:ff:ff:ff:ff
33: cif-12345: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 7e:0f:42:f5:16:2c brd ff:ff:ff:ff:ff:ff
34: 12345: mtu 1500 qdisc pfifo_fast master testbridge state DOWN mode DEFAULT group default qlen 1000
link/ether 86:7c:c1:7e:56:9a brd ff:ff:ff:ff:ff:ff
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# bridge link
34: 12345 state DOWN : mtu 1500 master testbridge state disabled priority 32 cost 2
root@nicktming:~/go/src/github.com/nicktming/mydocker/network#
2.4 设置iptables
由于iptables没有api, 所以直接用go执行命令行操作
func TestNet005(t *testing.T) {
subnet := "192.168.0.0/24"
iptablesCmd := fmt.Sprintf("-t nat -A POSTROUTING -s %s -o eth0 -j MASQUERADE", subnet)
cmd := exec.Command("iptables", strings.Split(iptablesCmd, " ")...)
//err := cmd.Run()
output, err := cmd.Output()
if err != nil {
log.Printf("iptables Output, %v", output)
}
}
测试
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# iptables -t nat -vnL POSTROUTING --line
Chain POSTROUTING (policy ACCEPT 414 packets, 25497 bytes)
num pkts bytes target prot opt in out source destination
1 14 998 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# go test -v api_test.go -test.run TestNet005
=== RUN TestNet005
--- PASS: TestNet005 (0.00s)
PASS
ok command-line-arguments 0.003s
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# iptables -t nat -vnL POSTROUTING --line
Chain POSTROUTING (policy ACCEPT 1 packets, 60 bytes)
num pkts bytes target prot opt in out source destination
1 14 998 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
2 0 0 MASQUERADE all -- * eth0 192.168.0.0/24 0.0.0.0/0
root@nicktming:~/go/src/github.com/nicktming/mydocker/network#
2.5 将veth设备中的一端加入到某个namespace中
首先先在terminal中启动一个隔离的network namespace
root@nicktming:~# unshare -n sh
# ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# echo $$
16694
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
# readlink /proc/16694/ns/net
net:[4026532167]
#
其次有两个辅助函数,前面已经介绍过只不过做了简单封装.
// 前面已经铺垫过
func SetInterfaceUP(interfaceName string) error {
iface, err := netlink.LinkByName(interfaceName)
if err != nil {
return fmt.Errorf("Error retrieving a link named [ %s ]: %v", iface.Attrs().Name, err)
}
if err := netlink.LinkSetUp(iface); err != nil {
return fmt.Errorf("Error enabling interface for %s: %v", interfaceName, err)
}
return nil
}
// 前面已经铺垫过
// Set the IP addr of a netlink interface
func SetInterfaceIP(name string, rawIP string) error {
retries := 2
var iface netlink.Link
var err error
for i := 0; i < retries; i++ {
iface, err = netlink.LinkByName(name)
if err == nil {
break
}
log.Printf("error retrieving new bridge netlink link [ %s ]... retrying", name)
time.Sleep(2 * time.Second)
}
if err != nil {
return fmt.Errorf("Abandoning retrieving the new bridge link from netlink, Run [ ip link ] to troubleshoot the error: %v", err)
}
ipNet, err := netlink.ParseIPNet(rawIP)
if err != nil {
return err
}
addr := &netlink.Addr{ipNet, "", 0, 0, nil}
return netlink.AddrAdd(iface, addr)
}
正式代码, 整个过程就是进入
Pid
为16694
所在的network namespace
中, 将veth
设备cif-12345
加入到该network namespace
中, 并且配置其地址为192.168.0.8
, 然后添加默认路由, 网关为testbridge
的地址192.168.0.1
.
EnterContainerNetns
: 作用是将当前运行的进程设置到Pid
为16694
所在的network namespace
中运行.
printCurrentNamespace
: 是为了打印当前进程到底在哪个network namespace
下运行.
ConfigEndpointIpAddressAndRoute
: 配置网络.
func TestNet006(t *testing.T) {
PeerName := "cif-12345"
containerIP := "192.168.0.8/24"
gwIP, ipnet, _ := net.ParseCIDR("192.168.0.1/24")
ipnet.IP = gwIP
if err := ConfigEndpointIpAddressAndRoute(PeerName, containerIP, ipnet); err != nil {
log.Printf("ConfigEndpointIpAddressAndRoute error:%v\n", err)
}
}
func EnterContainerNetns(enLink *netlink.Link) func() {
f, err := os.OpenFile(fmt.Sprintf("/proc/%s/ns/net", "16694"), os.O_RDONLY, 0)
if err != nil {
logrus.Errorf("error get container net namespace, %v", err)
}
nsFD := f.Fd()
runtime.LockOSThread()
// 修改veth peer 另外一端移到容器的namespace中
if err = netlink.LinkSetNsFd(*enLink, int(nsFD)); err != nil {
logrus.Errorf("error set link netns , %v", err)
}
// 获取当前的网络namespace
origns, err := netns.Get()
if err != nil {
logrus.Errorf("error get current netns, %v", err)
}
printCurrentNamespace()
log.Printf("before set to new namespace \n")
// 设置当前进程到新的网络namespace,并在函数执行完成之后再恢复到之前的namespace
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
logrus.Errorf("error set netns, %v", err)
}
printCurrentNamespace()
log.Printf("after set to new namespace\n")
return func () {
netns.Set(origns)
printCurrentNamespace()
log.Printf("before close\n")
origns.Close()
runtime.UnlockOSThread()
f.Close()
}
}
func printCurrentNamespace() {
currentNamespace, _ := netns.Get()
log.Printf("currentNamespace:%v\n", currentNamespace)
}
// 类似于 ip netns exec network_namespace sh 然后在该network_namespace namespace中配置网络
func ConfigEndpointIpAddressAndRoute(PeerName, containerIP string, ipnet *net.IPNet) error {
peerLink, err := netlink.LinkByName(PeerName)
if err != nil {
return fmt.Errorf("fail config endpoint: %v", err)
}
defer EnterContainerNetns(&peerLink)()
printCurrentNamespace()
log.Printf("config network namespace start.\n")
if err = SetInterfaceIP(PeerName, containerIP); err != nil {
return fmt.Errorf("set %s up error:%v", PeerName, err)
}
if err = SetInterfaceUP(PeerName); err != nil {
return err
}
if err = SetInterfaceUP("lo"); err != nil {
return err
}
_, cidr, _ := net.ParseCIDR("0.0.0.0/0")
defaultRoute := &netlink.Route{
LinkIndex: peerLink.Attrs().Index,
Gw: ipnet.IP,
Dst: cidr,
}
if err = netlink.RouteAdd(defaultRoute); err != nil {
return err
}
printCurrentNamespace()
log.Printf("config network namespace end.\n")
return nil
}
测试:
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# readlink /proc/$$/ns/net
net:[4026531956]
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# go test -v api_test.go -test.run TestNet006
=== RUN TestNet006
2019/05/05 22:45:12 currentNamespace:NS(5: 3, 4026531956)
2019/05/05 22:45:12 before set to new namespace
2019/05/05 22:45:12 currentNamespace:NS(6: 3, 4026532167)
2019/05/05 22:45:12 after set to new namespace
2019/05/05 22:45:12 currentNamespace:NS(7: 3, 4026532167)
2019/05/05 22:45:12 config network namespace start.
2019/05/05 22:45:12 currentNamespace:NS(8: 3, 4026532167)
2019/05/05 22:45:12 config network namespace end.
2019/05/05 22:45:12 currentNamespace:NS(9: 3, 4026531956)
2019/05/05 22:45:12 before close
--- PASS: TestNet006 (0.02s)
PASS
ok command-line-arguments 0.020s
root@nicktming:~/go/src/github.com/nicktming/mydocker/network#
可以看到先是在默认
network namespace[4026531956]
下工作的, 然后进入到Pid=16694
所在的network namespace[4026532167]
下进行配置网络, 最后又回到默认network namespace[4026531956]
.
可以去
Pid=16694
的terminal中看一下:
# readlink /proc/16694/ns/net
net:[4026532167]
#
# ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
45: cif-12345: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 1a:3f:eb:9a:17:de brd ff:ff:ff:ff:ff:ff
# ifconfig
cif-12345 Link encap:Ethernet HWaddr 1a:3f:eb:9a:17:de
inet addr:192.168.0.8 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fe80::183f:ebff:fe9a:17de/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:648 (648.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 cif-12345
192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cif-12345
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.030 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.030/0.030/0.030/0.000 ms
# ping -c 1 192.168.0.8
PING 192.168.0.8 (192.168.0.8) 56(84) bytes of data.
64 bytes from 192.168.0.8: icmp_seq=1 ttl=64 time=0.025 ms
--- 192.168.0.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.025/0.025/0.025/0.000 ms
# ping -c 1 192.168.0.1
PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
64 bytes from 192.168.0.1: icmp_seq=1 ttl=64 time=0.049 ms
--- 192.168.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.049/0.049/0.049/0.000 ms
# ping -c 1 172.19.16.7
PING 172.19.16.7 (172.19.16.7) 56(84) bytes of data.
64 bytes from 172.19.16.7: icmp_seq=1 ttl=64 time=0.049 ms
--- 172.19.16.7 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.049/0.049/0.049/0.000 ms
# ping -c 1 www.baidu.com
PING www.wshifen.com (119.63.197.139) 56(84) bytes of data.
64 bytes from 119.63.197.139: icmp_seq=1 ttl=51 time=54.0 ms
--- www.wshifen.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 54.087/54.087/54.087/0.000 ms
#
可以看到整个namespace下的网络已经配置好, 并且可以访问外部网络, 从宿主机访问该namespace.
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# ping -c 1 192.168.0.8
PING 192.168.0.8 (192.168.0.8) 56(84) bytes of data.
64 bytes from 192.168.0.8: icmp_seq=1 ttl=64 time=0.036 ms
--- 192.168.0.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.036/0.036/0.036/0.000 ms
root@nicktming:~/go/src/github.com/nicktming/mydocker/network#
2.6 删除设备
func TestNet007(t *testing.T) {
deleteDevice("testbridge")
deleteDevice("12345")
}
func deleteDevice(name string) {
// 根据设备名找到该设备
l, err := netlink.LinkByName(name)
if err != nil {
fmt.Errorf("Getting link with name %s failed: %v", name, err)
return
}
// 删除设备
// 删除网桥就等于 ifconfig testbridge down && ip link delete testbridge type bridge
// 删除veth就等于 ip link delete 12345 type veth
if err := netlink.LinkDel(l); err != nil {
fmt.Errorf("Failed to remove bridge interface %s delete: %v", name, err)
return
}
log.Printf("Delete Device %s\n", name)
}
测试, 可以看到网桥
testbridge
,Veth
设备12345
都已经被删除.
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# go test -v api_test.go -test.run TestNet007
=== RUN TestNet005
2019/05/05 21:31:09 Delete Device testbridge
2019/05/05 21:31:09 Delete Device 12345
--- PASS: TestNet005 (0.02s)
PASS
ok command-line-arguments 0.027s
root@nicktming:~/go/src/github.com/nicktming/mydocker/network# ip link
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:58:9a:c3 brd ff:ff:ff:ff:ff:ff
3: docker0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
root@nicktming:~/go/src/github.com/nicktming/mydocker/network#
3. 参考
1. 自己动手写docker.(基本参考此书,加入一些自己的理解,加深对
docker
的理解)
4. 全部内容
1. [mydocker]---环境说明
2. [mydocker]---urfave cli 理解
3. [mydocker]---Linux Namespace
4. [mydocker]---Linux Cgroup
5. [mydocker]---构造容器01-实现run命令
6. [mydocker]---构造容器02-实现资源限制01
7. [mydocker]---构造容器02-实现资源限制02
8. [mydocker]---构造容器03-实现增加管道
9. [mydocker]---通过例子理解存储驱动AUFS
10. [mydocker]---通过例子理解chroot 和 pivot_root
11. [mydocker]---一步步实现使用busybox创建容器
12. [mydocker]---一步步实现使用AUFS包装busybox
13. [mydocker]---一步步实现volume操作
14. [mydocker]---实现保存镜像
15. [mydocker]---实现容器的后台运行
16. [mydocker]---实现查看运行中容器
17. [mydocker]---实现查看容器日志
18. [mydocker]---实现进入容器Namespace
19. [mydocker]---实现停止容器
20. [mydocker]---实现删除容器
21. [mydocker]---实现容器层隔离
22. [mydocker]---实现通过容器制作镜像
23. [mydocker]---实现cp操作
24. [mydocker]---实现容器指定环境变量
25. [mydocker]---网际协议IP
26. [mydocker]---网络虚拟设备veth bridge iptables
27. [mydocker]---docker的四种网络模型与原理实现(1)
28. [mydocker]---docker的四种网络模型与原理实现(2)
29. [mydocker]---容器地址分配
30. [mydocker]---网络net/netlink api 使用解析
31. [mydocker]---网络实现
32. [mydocker]---网络实现测试