Add --net flag to docker run and allow host network stack
| ... | ... |
@@ -325,7 +325,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s |
| 325 | 325 |
}) |
| 326 | 326 |
} |
| 327 | 327 |
|
| 328 |
-func populateCommand(c *Container, env []string) {
|
|
| 328 |
+func populateCommand(c *Container, env []string) error {
|
|
| 329 | 329 |
var ( |
| 330 | 330 |
en *execdriver.Network |
| 331 | 331 |
context = make(map[string][]string) |
| ... | ... |
@@ -338,14 +338,29 @@ func populateCommand(c *Container, env []string) {
|
| 338 | 338 |
Interface: nil, |
| 339 | 339 |
} |
| 340 | 340 |
|
| 341 |
- if !c.Config.NetworkDisabled {
|
|
| 342 |
- network := c.NetworkSettings |
|
| 343 |
- en.Interface = &execdriver.NetworkInterface{
|
|
| 344 |
- Gateway: network.Gateway, |
|
| 345 |
- Bridge: network.Bridge, |
|
| 346 |
- IPAddress: network.IPAddress, |
|
| 347 |
- IPPrefixLen: network.IPPrefixLen, |
|
| 341 |
+ parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) |
|
| 342 |
+ switch parts[0] {
|
|
| 343 |
+ case "none": |
|
| 344 |
+ case "host": |
|
| 345 |
+ en.HostNetworking = true |
|
| 346 |
+ case "bridge", "": // empty string to support existing containers |
|
| 347 |
+ if !c.Config.NetworkDisabled {
|
|
| 348 |
+ network := c.NetworkSettings |
|
| 349 |
+ en.Interface = &execdriver.NetworkInterface{
|
|
| 350 |
+ Gateway: network.Gateway, |
|
| 351 |
+ Bridge: network.Bridge, |
|
| 352 |
+ IPAddress: network.IPAddress, |
|
| 353 |
+ IPPrefixLen: network.IPPrefixLen, |
|
| 354 |
+ } |
|
| 348 | 355 |
} |
| 356 |
+ case "container": |
|
| 357 |
+ nc, err := c.getNetworkedContainer() |
|
| 358 |
+ if err != nil {
|
|
| 359 |
+ return err |
|
| 360 |
+ } |
|
| 361 |
+ en.ContainerID = nc.ID |
|
| 362 |
+ default: |
|
| 363 |
+ return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)
|
|
| 349 | 364 |
} |
| 350 | 365 |
|
| 351 | 366 |
// TODO: this can be removed after lxc-conf is fully deprecated |
| ... | ... |
@@ -372,6 +387,7 @@ func populateCommand(c *Container, env []string) {
|
| 372 | 372 |
} |
| 373 | 373 |
c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
| 374 | 374 |
c.command.Env = env |
| 375 |
+ return nil |
|
| 375 | 376 |
} |
| 376 | 377 |
|
| 377 | 378 |
func (container *Container) Start() (err error) {
|
| ... | ... |
@@ -415,7 +431,9 @@ func (container *Container) Start() (err error) {
|
| 415 | 415 |
if err := container.setupWorkingDirectory(); err != nil {
|
| 416 | 416 |
return err |
| 417 | 417 |
} |
| 418 |
- populateCommand(container, env) |
|
| 418 |
+ if err := populateCommand(container, env); err != nil {
|
|
| 419 |
+ return err |
|
| 420 |
+ } |
|
| 419 | 421 |
if err := setupMountsForContainer(container); err != nil {
|
| 420 | 422 |
return err |
| 421 | 423 |
} |
| ... | ... |
@@ -485,9 +503,18 @@ func (container *Container) StderrLogPipe() io.ReadCloser {
|
| 485 | 485 |
return utils.NewBufReader(reader) |
| 486 | 486 |
} |
| 487 | 487 |
|
| 488 |
-func (container *Container) buildHostnameAndHostsFiles(IP string) {
|
|
| 488 |
+func (container *Container) buildHostname() {
|
|
| 489 | 489 |
container.HostnamePath = path.Join(container.root, "hostname") |
| 490 |
- ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) |
|
| 490 |
+ |
|
| 491 |
+ if container.Config.Domainname != "" {
|
|
| 492 |
+ ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
|
|
| 493 |
+ } else {
|
|
| 494 |
+ ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) |
|
| 495 |
+ } |
|
| 496 |
+} |
|
| 497 |
+ |
|
| 498 |
+func (container *Container) buildHostnameAndHostsFiles(IP string) {
|
|
| 499 |
+ container.buildHostname() |
|
| 491 | 500 |
|
| 492 | 501 |
hostsContent := []byte(` |
| 493 | 502 |
127.0.0.1 localhost |
| ... | ... |
@@ -505,12 +532,12 @@ ff02::2 ip6-allrouters |
| 505 | 505 |
} else if !container.Config.NetworkDisabled {
|
| 506 | 506 |
hostsContent = append([]byte(fmt.Sprintf("%s\t%s\n", IP, container.Config.Hostname)), hostsContent...)
|
| 507 | 507 |
} |
| 508 |
- |
|
| 509 | 508 |
ioutil.WriteFile(container.HostsPath, hostsContent, 0644) |
| 510 | 509 |
} |
| 511 | 510 |
|
| 512 | 511 |
func (container *Container) allocateNetwork() error {
|
| 513 |
- if container.Config.NetworkDisabled {
|
|
| 512 |
+ mode := container.hostConfig.NetworkMode |
|
| 513 |
+ if container.Config.NetworkDisabled || mode.IsContainer() || mode.IsHost() {
|
|
| 514 | 514 |
return nil |
| 515 | 515 |
} |
| 516 | 516 |
|
| ... | ... |
@@ -963,14 +990,22 @@ func (container *Container) setupContainerDns() error {
|
| 963 | 963 |
if container.ResolvConfPath != "" {
|
| 964 | 964 |
return nil |
| 965 | 965 |
} |
| 966 |
+ |
|
| 966 | 967 |
var ( |
| 967 | 968 |
config = container.hostConfig |
| 968 | 969 |
daemon = container.daemon |
| 969 | 970 |
) |
| 971 |
+ |
|
| 972 |
+ if config.NetworkMode == "host" {
|
|
| 973 |
+ container.ResolvConfPath = "/etc/resolv.conf" |
|
| 974 |
+ return nil |
|
| 975 |
+ } |
|
| 976 |
+ |
|
| 970 | 977 |
resolvConf, err := utils.GetResolvConf() |
| 971 | 978 |
if err != nil {
|
| 972 | 979 |
return err |
| 973 | 980 |
} |
| 981 |
+ |
|
| 974 | 982 |
// If custom dns exists, then create a resolv.conf for the container |
| 975 | 983 |
if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 {
|
| 976 | 984 |
var ( |
| ... | ... |
@@ -1010,7 +1045,32 @@ func (container *Container) setupContainerDns() error {
|
| 1010 | 1010 |
} |
| 1011 | 1011 |
|
| 1012 | 1012 |
func (container *Container) initializeNetworking() error {
|
| 1013 |
- if container.daemon.config.DisableNetwork {
|
|
| 1013 |
+ var err error |
|
| 1014 |
+ if container.hostConfig.NetworkMode.IsHost() {
|
|
| 1015 |
+ container.Config.Hostname, err = os.Hostname() |
|
| 1016 |
+ if err != nil {
|
|
| 1017 |
+ return err |
|
| 1018 |
+ } |
|
| 1019 |
+ |
|
| 1020 |
+ parts := strings.SplitN(container.Config.Hostname, ".", 2) |
|
| 1021 |
+ if len(parts) > 1 {
|
|
| 1022 |
+ container.Config.Hostname = parts[0] |
|
| 1023 |
+ container.Config.Domainname = parts[1] |
|
| 1024 |
+ } |
|
| 1025 |
+ container.HostsPath = "/etc/hosts" |
|
| 1026 |
+ |
|
| 1027 |
+ container.buildHostname() |
|
| 1028 |
+ } else if container.hostConfig.NetworkMode.IsContainer() {
|
|
| 1029 |
+ // we need to get the hosts files from the container to join |
|
| 1030 |
+ nc, err := container.getNetworkedContainer() |
|
| 1031 |
+ if err != nil {
|
|
| 1032 |
+ return err |
|
| 1033 |
+ } |
|
| 1034 |
+ container.HostsPath = nc.HostsPath |
|
| 1035 |
+ container.ResolvConfPath = nc.ResolvConfPath |
|
| 1036 |
+ container.Config.Hostname = nc.Config.Hostname |
|
| 1037 |
+ container.Config.Domainname = nc.Config.Domainname |
|
| 1038 |
+ } else if container.daemon.config.DisableNetwork {
|
|
| 1014 | 1039 |
container.Config.NetworkDisabled = true |
| 1015 | 1040 |
container.buildHostnameAndHostsFiles("127.0.1.1")
|
| 1016 | 1041 |
} else {
|
| ... | ... |
@@ -1219,3 +1279,20 @@ func (container *Container) GetMountLabel() string {
|
| 1219 | 1219 |
} |
| 1220 | 1220 |
return container.MountLabel |
| 1221 | 1221 |
} |
| 1222 |
+ |
|
| 1223 |
+func (container *Container) getNetworkedContainer() (*Container, error) {
|
|
| 1224 |
+ parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2) |
|
| 1225 |
+ switch parts[0] {
|
|
| 1226 |
+ case "container": |
|
| 1227 |
+ nc := container.daemon.Get(parts[1]) |
|
| 1228 |
+ if nc == nil {
|
|
| 1229 |
+ return nil, fmt.Errorf("no such container to join network: %s", parts[1])
|
|
| 1230 |
+ } |
|
| 1231 |
+ if !nc.State.IsRunning() {
|
|
| 1232 |
+ return nil, fmt.Errorf("cannot join network of a non running container: %s", parts[1])
|
|
| 1233 |
+ } |
|
| 1234 |
+ return nc, nil |
|
| 1235 |
+ default: |
|
| 1236 |
+ return nil, fmt.Errorf("network mode not set to container")
|
|
| 1237 |
+ } |
|
| 1238 |
+} |
| ... | ... |
@@ -89,8 +89,10 @@ type Driver interface {
|
| 89 | 89 |
|
| 90 | 90 |
// Network settings of the container |
| 91 | 91 |
type Network struct {
|
| 92 |
- Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled |
|
| 93 |
- Mtu int `json:"mtu"` |
|
| 92 |
+ Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled |
|
| 93 |
+ Mtu int `json:"mtu"` |
|
| 94 |
+ ContainerID string `json:"container_id"` // id of the container to join network. |
|
| 95 |
+ HostNetworking bool `json:"host_networking"` |
|
| 94 | 96 |
} |
| 95 | 97 |
|
| 96 | 98 |
type NetworkInterface struct {
|
| ... | ... |
@@ -3,15 +3,16 @@ package lxc |
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
"fmt" |
| 6 |
- "github.com/dotcloud/docker/daemon/execdriver" |
|
| 7 |
- "github.com/dotcloud/docker/pkg/netlink" |
|
| 8 |
- "github.com/dotcloud/docker/pkg/user" |
|
| 9 |
- "github.com/syndtr/gocapability/capability" |
|
| 10 | 6 |
"io/ioutil" |
| 11 | 7 |
"net" |
| 12 | 8 |
"os" |
| 13 | 9 |
"strings" |
| 14 | 10 |
"syscall" |
| 11 |
+ |
|
| 12 |
+ "github.com/dotcloud/docker/daemon/execdriver" |
|
| 13 |
+ "github.com/dotcloud/docker/pkg/netlink" |
|
| 14 |
+ "github.com/dotcloud/docker/pkg/user" |
|
| 15 |
+ "github.com/syndtr/gocapability/capability" |
|
| 15 | 16 |
) |
| 16 | 17 |
|
| 17 | 18 |
// Clear environment pollution introduced by lxc-start |
| ... | ... |
@@ -14,12 +14,13 @@ const LxcTemplate = ` |
| 14 | 14 |
lxc.network.type = veth |
| 15 | 15 |
lxc.network.link = {{.Network.Interface.Bridge}}
|
| 16 | 16 |
lxc.network.name = eth0 |
| 17 |
-{{else}}
|
|
| 17 |
+lxc.network.mtu = {{.Network.Mtu}}
|
|
| 18 |
+{{else if not .Network.HostNetworking}}
|
|
| 18 | 19 |
# network is disabled (-n=false) |
| 19 | 20 |
lxc.network.type = empty |
| 20 | 21 |
lxc.network.flags = up |
| 21 |
-{{end}}
|
|
| 22 | 22 |
lxc.network.mtu = {{.Network.Mtu}}
|
| 23 |
+{{end}}
|
|
| 23 | 24 |
|
| 24 | 25 |
# root filesystem |
| 25 | 26 |
{{$ROOTFS := .Rootfs}}
|
| ... | ... |
@@ -3,6 +3,7 @@ package native |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"os" |
| 6 |
+ "path/filepath" |
|
| 6 | 7 |
|
| 7 | 8 |
"github.com/dotcloud/docker/daemon/execdriver" |
| 8 | 9 |
"github.com/dotcloud/docker/daemon/execdriver/native/configuration" |
| ... | ... |
@@ -52,6 +53,10 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Container |
| 52 | 52 |
} |
| 53 | 53 |
|
| 54 | 54 |
func (d *driver) createNetwork(container *libcontainer.Container, c *execdriver.Command) error {
|
| 55 |
+ if c.Network.HostNetworking {
|
|
| 56 |
+ container.Namespaces.Get("NEWNET").Enabled = false
|
|
| 57 |
+ return nil |
|
| 58 |
+ } |
|
| 55 | 59 |
container.Networks = []*libcontainer.Network{
|
| 56 | 60 |
{
|
| 57 | 61 |
Mtu: c.Network.Mtu, |
| ... | ... |
@@ -75,6 +80,20 @@ func (d *driver) createNetwork(container *libcontainer.Container, c *execdriver. |
| 75 | 75 |
} |
| 76 | 76 |
container.Networks = append(container.Networks, &vethNetwork) |
| 77 | 77 |
} |
| 78 |
+ |
|
| 79 |
+ if c.Network.ContainerID != "" {
|
|
| 80 |
+ cmd := d.activeContainers[c.Network.ContainerID] |
|
| 81 |
+ if cmd == nil || cmd.Process == nil {
|
|
| 82 |
+ return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
|
|
| 83 |
+ } |
|
| 84 |
+ nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
|
|
| 85 |
+ container.Networks = append(container.Networks, &libcontainer.Network{
|
|
| 86 |
+ Type: "netns", |
|
| 87 |
+ Context: libcontainer.Context{
|
|
| 88 |
+ "nspath": nspath, |
|
| 89 |
+ }, |
|
| 90 |
+ }) |
|
| 91 |
+ } |
|
| 78 | 92 |
return nil |
| 79 | 93 |
} |
| 80 | 94 |
|
| ... | ... |
@@ -136,8 +136,8 @@ PID files): |
| 136 | 136 |
|
| 137 | 137 |
## Network Settings |
| 138 | 138 |
|
| 139 |
- -n=true : Enable networking for this container |
|
| 140 |
- --dns=[] : Set custom dns servers for the container |
|
| 139 |
+ --dns=[] : Set custom dns servers for the container |
|
| 140 |
+ --net=bridge : Set the network mode |
|
| 141 | 141 |
|
| 142 | 142 |
By default, all containers have networking enabled and they can make any |
| 143 | 143 |
outgoing connections. The operator can completely disable networking |
| ... | ... |
@@ -148,6 +148,48 @@ files or STDIN/STDOUT only. |
| 148 | 148 |
Your container will use the same DNS servers as the host by default, but |
| 149 | 149 |
you can override this with `--dns`. |
| 150 | 150 |
|
| 151 |
+Supported networking modes are: |
|
| 152 |
+ |
|
| 153 |
+* none - no networking in the container |
|
| 154 |
+* bridge - (default) connect the container to the bridge via veth interfaces |
|
| 155 |
+* host - use the host's network stack inside the container |
|
| 156 |
+* container - use another container's network stack |
|
| 157 |
+ |
|
| 158 |
+#### Mode: none |
|
| 159 |
+With the networking mode set to `none` a container will not have a access to |
|
| 160 |
+any external routes. The container will still have a `loopback` interface |
|
| 161 |
+enabled in the container but it does not have any routes to external traffic. |
|
| 162 |
+ |
|
| 163 |
+#### Mode: bridge |
|
| 164 |
+With the networking mode set to `bridge` a container will use docker's default |
|
| 165 |
+networking setup. A bridge is setup on the host, commonly named `docker0`, |
|
| 166 |
+and a pair of veth interfaces will be created for the container. One side of |
|
| 167 |
+the veth pair will remain on the host attached to the bridge while the other |
|
| 168 |
+side of the pair will be placed inside the container's namespaces in addition |
|
| 169 |
+to the `loopback` interface. An IP address will be allocated for containers |
|
| 170 |
+on the bridge's network and trafic will be routed though this bridge to the |
|
| 171 |
+container. |
|
| 172 |
+ |
|
| 173 |
+#### Mode: host |
|
| 174 |
+With the networking mode set to `host` a container will share the host's |
|
| 175 |
+network stack and all interfaces from the host will be available to the |
|
| 176 |
+container. The container's hostname will match the hostname on the host |
|
| 177 |
+system. Publishing ports and linking to other containers will not work |
|
| 178 |
+when sharing the host's network stack. |
|
| 179 |
+ |
|
| 180 |
+#### Mode: container |
|
| 181 |
+With the networking mode set to `container` a container will share the |
|
| 182 |
+network stack of another container. The other container's name must be |
|
| 183 |
+provided in the format of `--net container:<name|id>`. |
|
| 184 |
+ |
|
| 185 |
+Example running a redis container with redis binding to localhost then |
|
| 186 |
+running the redis-cli and connecting to the redis server over the |
|
| 187 |
+localhost interface. |
|
| 188 |
+ |
|
| 189 |
+ $ docker run -d --name redis example/redis --bind 127.0.0.1 |
|
| 190 |
+ $ # use the redis container's network stack to access localhost |
|
| 191 |
+ $ docker run --rm -ti --net container:redis example/redis-cli -h 127.0.0.1 |
|
| 192 |
+ |
|
| 151 | 193 |
## Clean Up (–rm) |
| 152 | 194 |
|
| 153 | 195 |
By default a container's file system persists even after the container |
| ... | ... |
@@ -1,11 +1,24 @@ |
| 1 | 1 |
package runconfig |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 4 | 6 |
"github.com/dotcloud/docker/engine" |
| 5 | 7 |
"github.com/dotcloud/docker/nat" |
| 6 | 8 |
"github.com/dotcloud/docker/utils" |
| 7 | 9 |
) |
| 8 | 10 |
|
| 11 |
+type NetworkMode string |
|
| 12 |
+ |
|
| 13 |
+func (n NetworkMode) IsHost() bool {
|
|
| 14 |
+ return n == "host" |
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+func (n NetworkMode) IsContainer() bool {
|
|
| 18 |
+ parts := strings.SplitN(string(n), ":", 2) |
|
| 19 |
+ return len(parts) > 1 && parts[0] == "container" |
|
| 20 |
+} |
|
| 21 |
+ |
|
| 9 | 22 |
type HostConfig struct {
|
| 10 | 23 |
Binds []string |
| 11 | 24 |
ContainerIDFile string |
| ... | ... |
@@ -17,6 +30,7 @@ type HostConfig struct {
|
| 17 | 17 |
Dns []string |
| 18 | 18 |
DnsSearch []string |
| 19 | 19 |
VolumesFrom []string |
| 20 |
+ NetworkMode NetworkMode |
|
| 20 | 21 |
} |
| 21 | 22 |
|
| 22 | 23 |
func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| ... | ... |
@@ -24,6 +38,7 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
| 24 | 24 |
ContainerIDFile: job.Getenv("ContainerIDFile"),
|
| 25 | 25 |
Privileged: job.GetenvBool("Privileged"),
|
| 26 | 26 |
PublishAllPorts: job.GetenvBool("PublishAllPorts"),
|
| 27 |
+ NetworkMode: NetworkMode(job.Getenv("NetworkMode")),
|
|
| 27 | 28 |
} |
| 28 | 29 |
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
| 29 | 30 |
job.GetenvJson("PortBindings", &hostConfig.PortBindings)
|
| ... | ... |
@@ -2,14 +2,15 @@ package runconfig |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "io/ioutil" |
|
| 6 |
+ "path" |
|
| 7 |
+ "strings" |
|
| 8 |
+ |
|
| 5 | 9 |
"github.com/dotcloud/docker/nat" |
| 6 | 10 |
"github.com/dotcloud/docker/opts" |
| 7 | 11 |
flag "github.com/dotcloud/docker/pkg/mflag" |
| 8 | 12 |
"github.com/dotcloud/docker/pkg/sysinfo" |
| 9 | 13 |
"github.com/dotcloud/docker/utils" |
| 10 |
- "io/ioutil" |
|
| 11 |
- "path" |
|
| 12 |
- "strings" |
|
| 13 | 14 |
) |
| 14 | 15 |
|
| 15 | 16 |
var ( |
| ... | ... |
@@ -49,7 +50,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 49 | 49 |
|
| 50 | 50 |
flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)")
|
| 51 | 51 |
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: Run container in the background, print new container id")
|
| 52 |
- flNetwork = cmd.Bool([]string{"n", "-networking"}, true, "Enable networking for this container")
|
|
| 52 |
+ flNetwork = cmd.Bool([]string{"#n", "#-networking"}, true, "Enable networking for this container")
|
|
| 53 | 53 |
flPrivileged = cmd.Bool([]string{"#privileged", "-privileged"}, false, "Give extended privileges to this container")
|
| 54 | 54 |
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to the host interfaces")
|
| 55 | 55 |
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep stdin open even if not attached")
|
| ... | ... |
@@ -61,7 +62,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 61 | 61 |
flUser = cmd.String([]string{"u", "-user"}, "", "Username or UID")
|
| 62 | 62 |
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
| 63 | 63 |
flCpuShares = cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
| 64 |
- |
|
| 64 |
+ flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container ('bridge': creates a new network stack for the container on the docker bridge, 'none': no networking for this container, 'container:<name|id>': reuses another container network stack)")
|
|
| 65 | 65 |
// For documentation purpose |
| 66 | 66 |
_ = cmd.Bool([]string{"#sig-proxy", "-sig-proxy"}, true, "Proxify all received signal to the process (even in non-tty mode)")
|
| 67 | 67 |
_ = cmd.String([]string{"#name", "-name"}, "", "Assign a name to the container")
|
| ... | ... |
@@ -197,6 +198,11 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 197 | 197 |
// boo, there's no debug output for docker run |
| 198 | 198 |
//utils.Debugf("Environment variables for the container: %#v", envVariables)
|
| 199 | 199 |
|
| 200 |
+ netMode, err := parseNetMode(*flNetMode) |
|
| 201 |
+ if err != nil {
|
|
| 202 |
+ return nil, nil, cmd, fmt.Errorf("--net: invalid net mode: %v", err)
|
|
| 203 |
+ } |
|
| 204 |
+ |
|
| 200 | 205 |
config := &Config{
|
| 201 | 206 |
Hostname: hostname, |
| 202 | 207 |
Domainname: domainname, |
| ... | ... |
@@ -230,6 +236,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf |
| 230 | 230 |
Dns: flDns.GetAll(), |
| 231 | 231 |
DnsSearch: flDnsSearch.GetAll(), |
| 232 | 232 |
VolumesFrom: flVolumesFrom.GetAll(), |
| 233 |
+ NetworkMode: netMode, |
|
| 233 | 234 |
} |
| 234 | 235 |
|
| 235 | 236 |
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
|
| ... | ... |
@@ -274,3 +281,17 @@ func parseKeyValueOpts(opts opts.ListOpts) ([]utils.KeyValuePair, error) {
|
| 274 | 274 |
} |
| 275 | 275 |
return out, nil |
| 276 | 276 |
} |
| 277 |
+ |
|
| 278 |
+func parseNetMode(netMode string) (NetworkMode, error) {
|
|
| 279 |
+ parts := strings.Split(netMode, ":") |
|
| 280 |
+ switch mode := parts[0]; mode {
|
|
| 281 |
+ case "bridge", "none", "host": |
|
| 282 |
+ case "container": |
|
| 283 |
+ if len(parts) < 2 || parts[1] == "" {
|
|
| 284 |
+ return "", fmt.Errorf("invalid container format container:<name|id>")
|
|
| 285 |
+ } |
|
| 286 |
+ default: |
|
| 287 |
+ return "", fmt.Errorf("invalid --net: %s", netMode)
|
|
| 288 |
+ } |
|
| 289 |
+ return NetworkMode(netMode), nil |
|
| 290 |
+} |