Docker integration with libnetwork

- Updated Dockerfile to satisfy libnetwork GOPATH requirements.
    - Reworked daemon to allocate network resources using libnetwork.
    - Reworked remove link code to also update network resources in libnetwork.
    - Adjusted the exec driver command population to reflect libnetwork design.
    - Adjusted the exec driver create command steps.
    - Updated a few test cases to reflect the change in design.
    - Removed the dns setup code from docker as resolv.conf is entirely managed
      in libnetwork.
    - Integrated with lxc exec driver.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan
2015-05-19 22:40:19 +00:00
parent 272f8cd4bc
commit d18919e304
20 changed files with 746 additions and 622 deletions
+1
View File
@@ -72,6 +72,7 @@ type Network struct {
Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled
Mtu int `json:"mtu"`
ContainerID string `json:"container_id"` // id of the container to join network.
NamespacePath string `json:"namespace_path"`
HostNetworking bool `json:"host_networking"`
}
+55 -9
View File
@@ -12,6 +12,7 @@ import (
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
@@ -30,6 +31,7 @@ import (
"github.com/docker/libcontainer/system"
"github.com/docker/libcontainer/user"
"github.com/kr/pty"
"github.com/vishvananda/netns"
)
const DriverName = "lxc"
@@ -80,6 +82,41 @@ func (d *driver) Name() string {
return fmt.Sprintf("%s-%s", DriverName, version)
}
func setupNetNs(nsPath string) (*os.Process, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
origns, err := netns.Get()
if err != nil {
return nil, err
}
defer origns.Close()
f, err := os.OpenFile(nsPath, os.O_RDONLY, 0)
if err != nil {
return nil, fmt.Errorf("failed to get network namespace %q: %v", nsPath, err)
}
defer f.Close()
nsFD := f.Fd()
if err := netns.Set(netns.NsHandle(nsFD)); err != nil {
return nil, fmt.Errorf("failed to set network namespace %q: %v", nsPath, err)
}
defer netns.Set(origns)
cmd := exec.Command("/bin/sh", "-c", "while true; do sleep 1; done")
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("failed to start netns process: %v", err)
}
return cmd.Process, nil
}
func killNetNsProc(proc *os.Process) {
proc.Kill()
proc.Wait()
}
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
var (
term execdriver.Terminal
@@ -87,6 +124,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
dataPath = d.containerDir(c.ID)
)
if c.Network.NamespacePath == "" && c.Network.ContainerID == "" {
return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
}
container, err := d.createContainer(c)
if err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
@@ -136,10 +177,20 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
params = append(params, "-F")
}
proc := &os.Process{}
if c.Network.ContainerID != "" {
params = append(params,
"--share-net", c.Network.ContainerID,
)
} else {
proc, err = setupNetNs(c.Network.NamespacePath)
if err != nil {
return execdriver.ExitStatus{ExitCode: -1}, err
}
pidStr := fmt.Sprintf("%d", proc.Pid)
params = append(params,
"--share-net", pidStr)
}
if c.Ipc != nil {
if c.Ipc.ContainerID != "" {
@@ -157,15 +208,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
"--",
c.InitPath,
)
if c.Network.Interface != nil {
params = append(params,
"-g", c.Network.Interface.Gateway,
"-i", fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
)
}
params = append(params,
"-mtu", strconv.Itoa(c.Network.Mtu),
)
if c.ProcessConfig.User != "" {
params = append(params, "-u", c.ProcessConfig.User)
@@ -214,10 +256,12 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
c.ProcessConfig.Args = append([]string{name}, arg...)
if err := createDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
killNetNsProc(proc)
return execdriver.ExitStatus{ExitCode: -1}, err
}
if err := c.ProcessConfig.Start(); err != nil {
killNetNsProc(proc)
return execdriver.ExitStatus{ExitCode: -1}, err
}
@@ -245,8 +289,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
// Poll lxc for RUNNING status
pid, err := d.waitForStart(c, waitLock)
if err != nil {
killNetNsProc(proc)
return terminate(err)
}
killNetNsProc(proc)
cgroupPaths, err := cgroupPaths(c.ID)
if err != nil {
+5 -4
View File
@@ -15,8 +15,7 @@ import (
"github.com/docker/libcontainer/label"
)
const LxcTemplate = `
{{if .Network.Interface}}
/* {{if .Network.Interface}}
# network configuration
lxc.network.type = veth
lxc.network.link = {{.Network.Interface.Bridge}}
@@ -30,8 +29,10 @@ lxc.network.type = none
lxc.network.type = empty
lxc.network.flags = up
lxc.network.mtu = {{.Network.Mtu}}
{{end}}
{{end}} */
const LxcTemplate = `
lxc.network.type = none
# root filesystem
{{$ROOTFS := .Rootfs}}
lxc.rootfs = {{$ROOTFS}}
@@ -145,6 +146,7 @@ lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}}
{{if .Network.Interface.MacAddress}}
lxc.network.hwaddr = {{.Network.Interface.MacAddress}}
{{end}}
{{end}}
{{if .ProcessConfig.Env}}
lxc.utsname = {{getHostname .ProcessConfig.Env}}
{{end}}
@@ -164,7 +166,6 @@ lxc.cap.drop = {{.}}
{{end}}
{{end}}
{{end}}
{{end}}
`
var LxcTemplateCompiled *template.Template
@@ -264,13 +264,8 @@ func TestCustomLxcConfigMisc(t *testing.T) {
"lxc.cgroup.cpuset.cpus = 0,1",
},
Network: &execdriver.Network{
Mtu: 1500,
Interface: &execdriver.NetworkInterface{
Gateway: "10.10.10.1",
IPAddress: "10.10.10.10",
IPPrefixLen: 24,
Bridge: "docker0",
},
Mtu: 1500,
Interface: nil,
},
ProcessConfig: processConfig,
CapAdd: []string{"net_admin", "syslog"},
@@ -282,13 +277,6 @@ func TestCustomLxcConfigMisc(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// network
grepFile(t, p, "lxc.network.type = veth")
grepFile(t, p, "lxc.network.link = docker0")
grepFile(t, p, "lxc.network.name = eth0")
grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24")
grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
grepFile(t, p, "lxc.network.flags = up")
grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting")
// hostname
grepFile(t, p, "lxc.utsname = testhost")
@@ -329,13 +317,8 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
"lxc.network.ipv4 = 172.0.0.1",
},
Network: &execdriver.Network{
Mtu: 1500,
Interface: &execdriver.NetworkInterface{
Gateway: "10.10.10.1",
IPAddress: "10.10.10.10",
IPPrefixLen: 24,
Bridge: "docker0",
},
Mtu: 1500,
Interface: nil,
},
ProcessConfig: processConfig,
CapAdd: []string{"NET_ADMIN", "SYSLOG"},
@@ -346,13 +329,6 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
if err != nil {
t.Fatal(err)
}
// network
grepFile(t, p, "lxc.network.type = veth")
grepFile(t, p, "lxc.network.link = docker0")
grepFile(t, p, "lxc.network.name = eth0")
grepFile(t, p, "lxc.network.ipv4 = 172.0.0.1")
grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
grepFile(t, p, "lxc.network.flags = up")
// hostname
grepFile(t, p, "lxc.utsname = testhost")
+6 -34
View File
@@ -89,40 +89,6 @@ func generateIfaceName() (string, error) {
}
func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error {
if c.Network.HostNetworking {
container.Namespaces.Remove(configs.NEWNET)
return nil
}
container.Networks = []*configs.Network{
{
Type: "loopback",
},
}
iName, err := generateIfaceName()
if err != nil {
return err
}
if c.Network.Interface != nil {
vethNetwork := configs.Network{
Name: "eth0",
HostInterfaceName: iName,
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
MacAddress: c.Network.Interface.MacAddress,
Gateway: c.Network.Interface.Gateway,
Type: "veth",
Bridge: c.Network.Interface.Bridge,
HairpinMode: c.Network.Interface.HairpinMode,
}
if c.Network.Interface.GlobalIPv6Address != "" {
vethNetwork.IPv6Address = fmt.Sprintf("%s/%d", c.Network.Interface.GlobalIPv6Address, c.Network.Interface.GlobalIPv6PrefixLen)
vethNetwork.IPv6Gateway = c.Network.Interface.IPv6Gateway
}
container.Networks = append(container.Networks, &vethNetwork)
}
if c.Network.ContainerID != "" {
d.Lock()
active := d.activeContainers[c.Network.ContainerID]
@@ -138,8 +104,14 @@ func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command)
}
container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET])
return nil
}
if c.Network.NamespacePath == "" {
return fmt.Errorf("network namespace path is empty")
}
container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath)
return nil
}