Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
| ... | ... |
@@ -1832,6 +1832,21 @@ _docker_run() {
|
| 1832 | 1832 |
esac |
| 1833 | 1833 |
return |
| 1834 | 1834 |
;; |
| 1835 |
+ --pid) |
|
| 1836 |
+ case "$cur" in |
|
| 1837 |
+ *:*) |
|
| 1838 |
+ cur="${cur#*:}"
|
|
| 1839 |
+ __docker_complete_containers_running |
|
| 1840 |
+ ;; |
|
| 1841 |
+ *) |
|
| 1842 |
+ COMPREPLY=( $( compgen -W 'host container:' -- "$cur" ) ) |
|
| 1843 |
+ if [ "$COMPREPLY" = "container:" ]; then |
|
| 1844 |
+ __docker_nospace |
|
| 1845 |
+ fi |
|
| 1846 |
+ ;; |
|
| 1847 |
+ esac |
|
| 1848 |
+ return |
|
| 1849 |
+ ;; |
|
| 1835 | 1850 |
--security-opt) |
| 1836 | 1851 |
COMPREPLY=( $( compgen -W "apparmor= label= no-new-privileges seccomp=" -- "$cur") ) |
| 1837 | 1852 |
if [ "${COMPREPLY[*]}" != "no-new-privileges" ] ; then
|
| ... | ... |
@@ -699,7 +699,7 @@ __docker_subcommand() {
|
| 699 | 699 |
"($help)--pids-limit[Tune container pids limit (set -1 for unlimited)]" |
| 700 | 700 |
"($help -P --publish-all)"{-P,--publish-all}"[Publish all exposed ports]"
|
| 701 | 701 |
"($help)*"{-p=,--publish=}"[Expose a container's port to the host]:port:_ports"
|
| 702 |
- "($help)--pid=[PID namespace to use]:PID: " |
|
| 702 |
+ "($help)--pid=[PID namespace to use]:PID namespace: " |
|
| 703 | 703 |
"($help)--privileged[Give extended privileges to this container]" |
| 704 | 704 |
"($help)--read-only[Mount the container's root filesystem as read only]" |
| 705 | 705 |
"($help)*--security-opt=[Security options]:security option: " |
| ... | ... |
@@ -169,6 +169,21 @@ func (daemon *Daemon) getIpcContainer(container *container.Container) (*containe |
| 169 | 169 |
return c, nil |
| 170 | 170 |
} |
| 171 | 171 |
|
| 172 |
+func (daemon *Daemon) getPidContainer(container *container.Container) (*container.Container, error) {
|
|
| 173 |
+ containerID := container.HostConfig.PidMode.Container() |
|
| 174 |
+ c, err := daemon.GetContainer(containerID) |
|
| 175 |
+ if err != nil {
|
|
| 176 |
+ return nil, err |
|
| 177 |
+ } |
|
| 178 |
+ if !c.IsRunning() {
|
|
| 179 |
+ return nil, fmt.Errorf("cannot join PID of a non running container: %s", containerID)
|
|
| 180 |
+ } |
|
| 181 |
+ if c.IsRestarting() {
|
|
| 182 |
+ return nil, errContainerIsRestarting(container.ID) |
|
| 183 |
+ } |
|
| 184 |
+ return c, nil |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 172 | 187 |
func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
| 173 | 188 |
var err error |
| 174 | 189 |
|
| ... | ... |
@@ -142,13 +142,40 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode containertypes.IpcMode, pidMod |
| 142 | 142 |
if ipcMode.IsHost() || pidMode.IsHost() {
|
| 143 | 143 |
return label.DisableSecOpt(), nil |
| 144 | 144 |
} |
| 145 |
- if ipcContainer := ipcMode.Container(); ipcContainer != "" {
|
|
| 145 |
+ |
|
| 146 |
+ var ipcLabel []string |
|
| 147 |
+ var pidLabel []string |
|
| 148 |
+ ipcContainer := ipcMode.Container() |
|
| 149 |
+ pidContainer := pidMode.Container() |
|
| 150 |
+ if ipcContainer != "" {
|
|
| 146 | 151 |
c, err := daemon.GetContainer(ipcContainer) |
| 147 | 152 |
if err != nil {
|
| 148 | 153 |
return nil, err |
| 149 | 154 |
} |
| 155 |
+ ipcLabel = label.DupSecOpt(c.ProcessLabel) |
|
| 156 |
+ if pidContainer == "" {
|
|
| 157 |
+ return ipcLabel, err |
|
| 158 |
+ } |
|
| 159 |
+ } |
|
| 160 |
+ if pidContainer != "" {
|
|
| 161 |
+ c, err := daemon.GetContainer(pidContainer) |
|
| 162 |
+ if err != nil {
|
|
| 163 |
+ return nil, err |
|
| 164 |
+ } |
|
| 150 | 165 |
|
| 151 |
- return label.DupSecOpt(c.ProcessLabel), nil |
|
| 166 |
+ pidLabel = label.DupSecOpt(c.ProcessLabel) |
|
| 167 |
+ if ipcContainer == "" {
|
|
| 168 |
+ return pidLabel, err |
|
| 169 |
+ } |
|
| 170 |
+ } |
|
| 171 |
+ |
|
| 172 |
+ if pidLabel != nil && ipcLabel != nil {
|
|
| 173 |
+ for i := 0; i < len(pidLabel); i++ {
|
|
| 174 |
+ if pidLabel[i] != ipcLabel[i] {
|
|
| 175 |
+ return nil, fmt.Errorf("--ipc and --pid containers SELinux labels aren't the same")
|
|
| 176 |
+ } |
|
| 177 |
+ } |
|
| 178 |
+ return pidLabel, nil |
|
| 152 | 179 |
} |
| 153 | 180 |
return nil, nil |
| 154 | 181 |
} |
| ... | ... |
@@ -296,8 +296,25 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error |
| 296 | 296 |
setNamespace(s, ns) |
| 297 | 297 |
} |
| 298 | 298 |
// pid |
| 299 |
- if c.HostConfig.PidMode.IsHost() {
|
|
| 299 |
+ if c.HostConfig.PidMode.IsContainer() {
|
|
| 300 |
+ ns := specs.Namespace{Type: "pid"}
|
|
| 301 |
+ pc, err := daemon.getPidContainer(c) |
|
| 302 |
+ if err != nil {
|
|
| 303 |
+ return err |
|
| 304 |
+ } |
|
| 305 |
+ ns.Path = fmt.Sprintf("/proc/%d/ns/pid", pc.State.GetPID())
|
|
| 306 |
+ setNamespace(s, ns) |
|
| 307 |
+ if userNS {
|
|
| 308 |
+ // to share an PID namespace, they must also share a user namespace |
|
| 309 |
+ nsUser := specs.Namespace{Type: "user"}
|
|
| 310 |
+ nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", pc.State.GetPID())
|
|
| 311 |
+ setNamespace(s, nsUser) |
|
| 312 |
+ } |
|
| 313 |
+ } else if c.HostConfig.PidMode.IsHost() {
|
|
| 300 | 314 |
delNamespace(s, specs.NamespaceType("pid"))
|
| 315 |
+ } else {
|
|
| 316 |
+ ns := specs.Namespace{Type: "pid"}
|
|
| 317 |
+ setNamespace(s, ns) |
|
| 301 | 318 |
} |
| 302 | 319 |
// uts |
| 303 | 320 |
if c.HostConfig.UTSMode.IsHost() {
|
| ... | ... |
@@ -193,7 +193,8 @@ the digest value is predictable and referenceable. |
| 193 | 193 |
## PID settings (--pid) |
| 194 | 194 |
|
| 195 | 195 |
--pid="" : Set the PID (Process) Namespace mode for the container, |
| 196 |
- 'host': use the host's PID namespace inside the container |
|
| 196 |
+ 'container:<name|id>': joins another container's PID namespace |
|
| 197 |
+ 'host': use the host's PID namespace inside the container |
|
| 197 | 198 |
|
| 198 | 199 |
By default, all containers have the PID namespace enabled. |
| 199 | 200 |
|
| ... | ... |
@@ -229,6 +230,23 @@ Use the following command to run `htop` inside a container: |
| 229 | 229 |
$ docker run -it --rm --pid=host myhtop |
| 230 | 230 |
``` |
| 231 | 231 |
|
| 232 |
+Joining another container's pid namespace can be used for debugging that container. |
|
| 233 |
+ |
|
| 234 |
+### Example |
|
| 235 |
+ |
|
| 236 |
+Start a container running a redis server: |
|
| 237 |
+ |
|
| 238 |
+```bash |
|
| 239 |
+$ docker run --name my-redis -d redis |
|
| 240 |
+``` |
|
| 241 |
+ |
|
| 242 |
+Debug the redis container by running another container that has strace in it: |
|
| 243 |
+ |
|
| 244 |
+```bash |
|
| 245 |
+$ docker run --it --pid=container:my-redis bash |
|
| 246 |
+$ strace -p 1 |
|
| 247 |
+``` |
|
| 248 |
+ |
|
| 232 | 249 |
## UTS settings (--uts) |
| 233 | 250 |
|
| 234 | 251 |
--uts="" : Set the UTS namespace mode for the container, |
| ... | ... |
@@ -2443,6 +2443,53 @@ func (s *DockerSuite) TestRunModeIpcContainerNotRunning(c *check.C) {
|
| 2443 | 2443 |
} |
| 2444 | 2444 |
} |
| 2445 | 2445 |
|
| 2446 |
+func (s *DockerSuite) TestRunModePidContainer(c *check.C) {
|
|
| 2447 |
+ // Not applicable on Windows as uses Unix-specific capabilities |
|
| 2448 |
+ testRequires(c, SameHostDaemon, DaemonIsLinux) |
|
| 2449 |
+ |
|
| 2450 |
+ out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "top") |
|
| 2451 |
+ |
|
| 2452 |
+ id := strings.TrimSpace(out) |
|
| 2453 |
+ state := inspectField(c, id, "State.Running") |
|
| 2454 |
+ if state != "true" {
|
|
| 2455 |
+ c.Fatal("Container state is 'not running'")
|
|
| 2456 |
+ } |
|
| 2457 |
+ pid1 := inspectField(c, id, "State.Pid") |
|
| 2458 |
+ |
|
| 2459 |
+ parentContainerPid, err := os.Readlink(fmt.Sprintf("/proc/%s/ns/pid", pid1))
|
|
| 2460 |
+ if err != nil {
|
|
| 2461 |
+ c.Fatal(err) |
|
| 2462 |
+ } |
|
| 2463 |
+ |
|
| 2464 |
+ out, _ = dockerCmd(c, "run", fmt.Sprintf("--pid=container:%s", id), "busybox", "readlink", "/proc/self/ns/pid")
|
|
| 2465 |
+ out = strings.Trim(out, "\n") |
|
| 2466 |
+ if parentContainerPid != out {
|
|
| 2467 |
+ c.Fatalf("PID different with --pid=container:%s %s != %s\n", id, parentContainerPid, out)
|
|
| 2468 |
+ } |
|
| 2469 |
+} |
|
| 2470 |
+ |
|
| 2471 |
+func (s *DockerSuite) TestRunModePidContainerNotExists(c *check.C) {
|
|
| 2472 |
+ // Not applicable on Windows as uses Unix-specific capabilities |
|
| 2473 |
+ testRequires(c, DaemonIsLinux) |
|
| 2474 |
+ out, _, err := dockerCmdWithError("run", "-d", "--pid", "container:abcd1234", "busybox", "top")
|
|
| 2475 |
+ if !strings.Contains(out, "abcd1234") || err == nil {
|
|
| 2476 |
+ c.Fatalf("run PID from a non exists container should with correct error out")
|
|
| 2477 |
+ } |
|
| 2478 |
+} |
|
| 2479 |
+ |
|
| 2480 |
+func (s *DockerSuite) TestRunModePidContainerNotRunning(c *check.C) {
|
|
| 2481 |
+ // Not applicable on Windows as uses Unix-specific capabilities |
|
| 2482 |
+ testRequires(c, SameHostDaemon, DaemonIsLinux) |
|
| 2483 |
+ |
|
| 2484 |
+ out, _ := dockerCmd(c, "create", "busybox") |
|
| 2485 |
+ |
|
| 2486 |
+ id := strings.TrimSpace(out) |
|
| 2487 |
+ out, _, err := dockerCmdWithError("run", fmt.Sprintf("--pid=container:%s", id), "busybox")
|
|
| 2488 |
+ if err == nil {
|
|
| 2489 |
+ c.Fatalf("Run container with pid mode container should fail with non running container: %s\n%s", out, err)
|
|
| 2490 |
+ } |
|
| 2491 |
+} |
|
| 2492 |
+ |
|
| 2446 | 2493 |
func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) {
|
| 2447 | 2494 |
// Not applicable on Windows as uses Unix-specific capabilities |
| 2448 | 2495 |
testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace) |
| ... | ... |
@@ -57,7 +57,7 @@ docker-create - Create a new container |
| 57 | 57 |
[**--oom-score-adj**[=*0*]] |
| 58 | 58 |
[**-P**|**--publish-all**] |
| 59 | 59 |
[**-p**|**--publish**[=*[]*]] |
| 60 |
-[**--pid**[=*[]*]] |
|
| 60 |
+[**--pid**[=*[PID]*]] |
|
| 61 | 61 |
[**--userns**[=*[]*]] |
| 62 | 62 |
[**--pids-limit**[=*PIDS_LIMIT*]] |
| 63 | 63 |
[**--privileged**] |
| ... | ... |
@@ -289,10 +289,11 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. |
| 289 | 289 |
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`) |
| 290 | 290 |
(use 'docker port' to see the actual mapping) |
| 291 | 291 |
|
| 292 |
-**--pid**=*host* |
|
| 292 |
+**--pid**="" |
|
| 293 | 293 |
Set the PID mode for the container |
| 294 |
- **host**: use the host's PID namespace inside the container. |
|
| 295 |
- Note: the host mode gives the container full access to local PID and is therefore considered insecure. |
|
| 294 |
+ Default is to create a private PID namespace for the container |
|
| 295 |
+ 'container:<name|id>': join another container's PID namespace |
|
| 296 |
+ '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. |
|
| 296 | 297 |
|
| 297 | 298 |
**--userns**="" |
| 298 | 299 |
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 |
| 59 | 59 |
[**--oom-score-adj**[=*0*]] |
| 60 | 60 |
[**-P**|**--publish-all**] |
| 61 | 61 |
[**-p**|**--publish**[=*[]*]] |
| 62 |
-[**--pid**[=*[]*]] |
|
| 62 |
+[**--pid**[=*[PID]*]] |
|
| 63 | 63 |
[**--userns**[=*[]*]] |
| 64 | 64 |
[**--pids-limit**[=*PIDS_LIMIT*]] |
| 65 | 65 |
[**--privileged**] |
| ... | ... |
@@ -420,10 +420,11 @@ but not `docker run -p 1230-1236:1230-1240 --name RangeContainerPortsBiggerThanR |
| 420 | 420 |
With ip: `docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage` |
| 421 | 421 |
Use `docker port` to see the actual mapping: `docker port CONTAINER $CONTAINERPORT` |
| 422 | 422 |
|
| 423 |
-**--pid**=*host* |
|
| 423 |
+**--pid**="" |
|
| 424 | 424 |
Set the PID mode for the container |
| 425 |
- **host**: use the host's PID namespace inside the container. |
|
| 426 |
- Note: the host mode gives the container full access to local PID and is therefore considered insecure. |
|
| 425 |
+ Default is to create a private PID namespace for the container |
|
| 426 |
+ 'container:<name|id>': join another container's PID namespace |
|
| 427 |
+ '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. |
|
| 427 | 428 |
|
| 428 | 429 |
**--userns**="" |
| 429 | 430 |
Set the usernamespace mode for the container when `userns-remap` option is enabled. |