mirror of https://github.com/docker/docs.git
				
				
				
			Add support for --pid=container:<id>
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
		
							parent
							
								
									28a436af36
								
							
						
					
					
						commit
						fb43ef649b
					
				|  | @ -1832,6 +1832,21 @@ _docker_run() { | |||
| 			esac | ||||
| 			return | ||||
| 			;; | ||||
| 		--pid) | ||||
| 			case "$cur" in | ||||
| 				*:*) | ||||
| 					cur="${cur#*:}" | ||||
| 					__docker_complete_containers_running | ||||
| 					;; | ||||
| 				*) | ||||
| 					COMPREPLY=( $( compgen -W 'host container:' -- "$cur" ) ) | ||||
| 					if [ "$COMPREPLY" = "container:" ]; then | ||||
| 						__docker_nospace | ||||
| 					fi | ||||
| 					;; | ||||
| 			esac | ||||
| 			return | ||||
| 			;; | ||||
| 		--security-opt) | ||||
| 			COMPREPLY=( $( compgen -W "apparmor= label= no-new-privileges seccomp=" -- "$cur") ) | ||||
| 			if [ "${COMPREPLY[*]}" != "no-new-privileges" ] ; then | ||||
|  |  | |||
|  | @ -699,7 +699,7 @@ __docker_subcommand() { | |||
|         "($help)--pids-limit[Tune container pids limit (set -1 for unlimited)]" | ||||
|         "($help -P --publish-all)"{-P,--publish-all}"[Publish all exposed ports]" | ||||
|         "($help)*"{-p=,--publish=}"[Expose a container's port to the host]:port:_ports" | ||||
|         "($help)--pid=[PID namespace to use]:PID: " | ||||
|         "($help)--pid=[PID namespace to use]:PID namespace: " | ||||
|         "($help)--privileged[Give extended privileges to this container]" | ||||
|         "($help)--read-only[Mount the container's root filesystem as read only]" | ||||
|         "($help)*--security-opt=[Security options]:security option: " | ||||
|  |  | |||
|  | @ -169,6 +169,21 @@ func (daemon *Daemon) getIpcContainer(container *container.Container) (*containe | |||
| 	return c, nil | ||||
| } | ||||
| 
 | ||||
| func (daemon *Daemon) getPidContainer(container *container.Container) (*container.Container, error) { | ||||
| 	containerID := container.HostConfig.PidMode.Container() | ||||
| 	c, err := daemon.GetContainer(containerID) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if !c.IsRunning() { | ||||
| 		return nil, fmt.Errorf("cannot join PID of a non running container: %s", containerID) | ||||
| 	} | ||||
| 	if c.IsRestarting() { | ||||
| 		return nil, errContainerIsRestarting(container.ID) | ||||
| 	} | ||||
| 	return c, nil | ||||
| } | ||||
| 
 | ||||
| func (daemon *Daemon) setupIpcDirs(c *container.Container) error { | ||||
| 	var err error | ||||
| 
 | ||||
|  |  | |||
|  | @ -142,13 +142,40 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode containertypes.IpcMode, pidMod | |||
| 	if ipcMode.IsHost() || pidMode.IsHost() { | ||||
| 		return label.DisableSecOpt(), nil | ||||
| 	} | ||||
| 	if ipcContainer := ipcMode.Container(); ipcContainer != "" { | ||||
| 
 | ||||
| 	var ipcLabel []string | ||||
| 	var pidLabel []string | ||||
| 	ipcContainer := ipcMode.Container() | ||||
| 	pidContainer := pidMode.Container() | ||||
| 	if ipcContainer != "" { | ||||
| 		c, err := daemon.GetContainer(ipcContainer) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		ipcLabel = label.DupSecOpt(c.ProcessLabel) | ||||
| 		if pidContainer == "" { | ||||
| 			return ipcLabel, err | ||||
| 		} | ||||
| 	} | ||||
| 	if pidContainer != "" { | ||||
| 		c, err := daemon.GetContainer(pidContainer) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		return label.DupSecOpt(c.ProcessLabel), nil | ||||
| 		pidLabel = label.DupSecOpt(c.ProcessLabel) | ||||
| 		if ipcContainer == "" { | ||||
| 			return pidLabel, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if pidLabel != nil && ipcLabel != nil { | ||||
| 		for i := 0; i < len(pidLabel); i++ { | ||||
| 			if pidLabel[i] != ipcLabel[i] { | ||||
| 				return nil, fmt.Errorf("--ipc and --pid containers SELinux labels aren't the same") | ||||
| 			} | ||||
| 		} | ||||
| 		return pidLabel, nil | ||||
| 	} | ||||
| 	return nil, nil | ||||
| } | ||||
|  |  | |||
|  | @ -296,8 +296,25 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error | |||
| 		setNamespace(s, ns) | ||||
| 	} | ||||
| 	// pid
 | ||||
| 	if c.HostConfig.PidMode.IsHost() { | ||||
| 	if c.HostConfig.PidMode.IsContainer() { | ||||
| 		ns := specs.Namespace{Type: "pid"} | ||||
| 		pc, err := daemon.getPidContainer(c) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		ns.Path = fmt.Sprintf("/proc/%d/ns/pid", pc.State.GetPID()) | ||||
| 		setNamespace(s, ns) | ||||
| 		if userNS { | ||||
| 			// to share an PID namespace, they must also share a user namespace
 | ||||
| 			nsUser := specs.Namespace{Type: "user"} | ||||
| 			nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", pc.State.GetPID()) | ||||
| 			setNamespace(s, nsUser) | ||||
| 		} | ||||
| 	} else if c.HostConfig.PidMode.IsHost() { | ||||
| 		delNamespace(s, specs.NamespaceType("pid")) | ||||
| 	} else { | ||||
| 		ns := specs.Namespace{Type: "pid"} | ||||
| 		setNamespace(s, ns) | ||||
| 	} | ||||
| 	// uts
 | ||||
| 	if c.HostConfig.UTSMode.IsHost() { | ||||
|  |  | |||
|  | @ -193,7 +193,8 @@ the digest value is predictable and referenceable. | |||
| ## PID settings (--pid) | ||||
| 
 | ||||
|     --pid=""  : Set the PID (Process) Namespace mode for the container, | ||||
|            'host': use the host's PID namespace inside the container | ||||
|                  'container:<name|id>': joins another container's PID namespace | ||||
|                  'host': use the host's PID namespace inside the container | ||||
| 
 | ||||
| By default, all containers have the PID namespace enabled. | ||||
| 
 | ||||
|  | @ -229,6 +230,23 @@ Use the following command to run `htop` inside a container: | |||
| $ docker run -it --rm --pid=host myhtop | ||||
| ``` | ||||
| 
 | ||||
| Joining another container's pid namespace can be used for debugging that container. | ||||
| 
 | ||||
| ### Example | ||||
| 
 | ||||
| Start a container running a redis server: | ||||
| 
 | ||||
| ```bash | ||||
| $ docker run --name my-redis -d redis | ||||
| ``` | ||||
| 
 | ||||
| Debug the redis container by running another container that has strace in it: | ||||
| 
 | ||||
| ```bash | ||||
| $ docker run --it --pid=container:my-redis bash | ||||
| $ strace -p 1 | ||||
| ``` | ||||
| 
 | ||||
| ## UTS settings (--uts) | ||||
| 
 | ||||
|     --uts=""  : Set the UTS namespace mode for the container, | ||||
|  |  | |||
|  | @ -2443,6 +2443,53 @@ func (s *DockerSuite) TestRunModeIpcContainerNotRunning(c *check.C) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *DockerSuite) TestRunModePidContainer(c *check.C) { | ||||
| 	// Not applicable on Windows as uses Unix-specific capabilities
 | ||||
| 	testRequires(c, SameHostDaemon, DaemonIsLinux) | ||||
| 
 | ||||
| 	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "top") | ||||
| 
 | ||||
| 	id := strings.TrimSpace(out) | ||||
| 	state := inspectField(c, id, "State.Running") | ||||
| 	if state != "true" { | ||||
| 		c.Fatal("Container state is 'not running'") | ||||
| 	} | ||||
| 	pid1 := inspectField(c, id, "State.Pid") | ||||
| 
 | ||||
| 	parentContainerPid, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/pid", pid1)) | ||||
| 	if err != nil { | ||||
| 		c.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	out, _ = dockerCmd(c, "run", fmt.Sprintf("--pid=container:%s", id), "busybox", "readlink", "/proc/self/ns/pid") | ||||
| 	out = strings.Trim(out, "\n") | ||||
| 	if parentContainerPid != out { | ||||
| 		c.Fatalf("PID different with --pid=container:%s %s != %s\n", id, parentContainerPid, out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *DockerSuite) TestRunModePidContainerNotExists(c *check.C) { | ||||
| 	// Not applicable on Windows as uses Unix-specific capabilities
 | ||||
| 	testRequires(c, DaemonIsLinux) | ||||
| 	out, _, err := dockerCmdWithError("run", "-d", "--pid", "container:abcd1234", "busybox", "top") | ||||
| 	if !strings.Contains(out, "abcd1234") || err == nil { | ||||
| 		c.Fatalf("run PID from a non exists container should with correct error out") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *DockerSuite) TestRunModePidContainerNotRunning(c *check.C) { | ||||
| 	// Not applicable on Windows as uses Unix-specific capabilities
 | ||||
| 	testRequires(c, SameHostDaemon, DaemonIsLinux) | ||||
| 
 | ||||
| 	out, _ := dockerCmd(c, "create", "busybox") | ||||
| 
 | ||||
| 	id := strings.TrimSpace(out) | ||||
| 	out, _, err := dockerCmdWithError("run", fmt.Sprintf("--pid=container:%s", id), "busybox") | ||||
| 	if err == nil { | ||||
| 		c.Fatalf("Run container with pid mode container should fail with non running container: %s\n%s", out, err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) { | ||||
| 	// Not applicable on Windows as uses Unix-specific capabilities
 | ||||
| 	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ docker-create - Create a new container | |||
| [**--oom-score-adj**[=*0*]] | ||||
| [**-P**|**--publish-all**] | ||||
| [**-p**|**--publish**[=*[]*]] | ||||
| [**--pid**[=*[]*]] | ||||
| [**--pid**[=*[PID]*]] | ||||
| [**--userns**[=*[]*]] | ||||
| [**--pids-limit**[=*PIDS_LIMIT*]] | ||||
| [**--privileged**] | ||||
|  | @ -289,10 +289,11 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. | |||
|                                When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range. (e.g., `-p 1234-1236:1234-1236/tcp`) | ||||
|                                (use 'docker port' to see the actual mapping) | ||||
| 
 | ||||
| **--pid**=*host* | ||||
| **--pid**="" | ||||
|    Set the PID mode for the container | ||||
|      **host**: use the host's PID namespace inside the container. | ||||
|      Note: the host mode gives the container full access to local PID and is therefore considered insecure. | ||||
|    Default is to create a private PID namespace for the container | ||||
|                                'container:<name|id>': join another container's PID namespace | ||||
|                                'host': use the host's PID namespace for the container. Note: the host mode gives the container full access to local PID and is therefore considered insecure. | ||||
| 
 | ||||
| **--userns**="" | ||||
|    Set the usernamespace mode for the container when `userns-remap` option is enabled. | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ docker-run - Run a command in a new container | |||
| [**--oom-score-adj**[=*0*]] | ||||
| [**-P**|**--publish-all**] | ||||
| [**-p**|**--publish**[=*[]*]] | ||||
| [**--pid**[=*[]*]] | ||||
| [**--pid**[=*[PID]*]] | ||||
| [**--userns**[=*[]*]] | ||||
| [**--pids-limit**[=*PIDS_LIMIT*]] | ||||
| [**--privileged**] | ||||
|  | @ -420,10 +420,11 @@ but not `docker run -p 1230-1236:1230-1240 --name RangeContainerPortsBiggerThanR | |||
| With ip: `docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage` | ||||
| Use `docker port` to see the actual mapping: `docker port CONTAINER $CONTAINERPORT` | ||||
| 
 | ||||
| **--pid**=*host* | ||||
| **--pid**="" | ||||
|    Set the PID mode for the container | ||||
|      **host**: use the host's PID namespace inside the container. | ||||
|      Note: the host mode gives the container full access to local PID and is therefore considered insecure. | ||||
|    Default is to create a private PID namespace for the container | ||||
|                                'container:<name|id>': join another container's PID namespace | ||||
|                                'host': use the host's PID namespace for the container. Note: the host mode gives the container full access to local PID and is therefore considered insecure. | ||||
| 
 | ||||
| **--userns**="" | ||||
|    Set the usernamespace mode for the container when `userns-remap` option is enabled. | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue