mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #10093 from crosbymichael/readonly-containers
Add --read-only for read only container rootfs
This commit is contained in:
commit
95c0f07966
11 changed files with 62 additions and 1 deletions
|
@ -294,6 +294,7 @@ func populateCommand(c *Container, env []string) error {
|
||||||
c.command = &execdriver.Command{
|
c.command = &execdriver.Command{
|
||||||
ID: c.ID,
|
ID: c.ID,
|
||||||
Rootfs: c.RootfsPath(),
|
Rootfs: c.RootfsPath(),
|
||||||
|
ReadonlyRootfs: c.hostConfig.ReadonlyRootfs,
|
||||||
InitPath: "/.dockerinit",
|
InitPath: "/.dockerinit",
|
||||||
WorkingDir: c.Config.WorkingDir,
|
WorkingDir: c.Config.WorkingDir,
|
||||||
Network: en,
|
Network: en,
|
||||||
|
|
|
@ -125,7 +125,8 @@ type ProcessConfig struct {
|
||||||
// Process wrapps an os/exec.Cmd to add more metadata
|
// Process wrapps an os/exec.Cmd to add more metadata
|
||||||
type Command struct {
|
type Command struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Rootfs string `json:"rootfs"` // root fs of the container
|
Rootfs string `json:"rootfs"` // root fs of the container
|
||||||
|
ReadonlyRootfs bool `json:"readonly_rootfs"`
|
||||||
InitPath string `json:"initpath"` // dockerinit
|
InitPath string `json:"initpath"` // dockerinit
|
||||||
WorkingDir string `json:"working_dir"`
|
WorkingDir string `json:"working_dir"`
|
||||||
ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
|
ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
|
||||||
|
|
|
@ -31,6 +31,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e
|
||||||
container.Cgroups.AllowedDevices = c.AllowedDevices
|
container.Cgroups.AllowedDevices = c.AllowedDevices
|
||||||
container.MountConfig.DeviceNodes = c.AutoCreatedDevices
|
container.MountConfig.DeviceNodes = c.AutoCreatedDevices
|
||||||
container.RootFs = c.Rootfs
|
container.RootFs = c.Rootfs
|
||||||
|
container.MountConfig.ReadonlyFs = c.ReadonlyRootfs
|
||||||
|
|
||||||
// check to see if we are running in ramdisk to disable pivot root
|
// check to see if we are running in ramdisk to disable pivot root
|
||||||
container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
|
||||||
|
|
|
@ -34,6 +34,7 @@ docker-create - Create a new container
|
||||||
[**-p**|**--publish**[=*[]*]]
|
[**-p**|**--publish**[=*[]*]]
|
||||||
[**--pid**[=*[]*]]
|
[**--pid**[=*[]*]]
|
||||||
[**--privileged**[=*false*]]
|
[**--privileged**[=*false*]]
|
||||||
|
[**--read-only**[=*false*]]
|
||||||
[**--restart**[=*RESTART*]]
|
[**--restart**[=*RESTART*]]
|
||||||
[**--security-opt**[=*[]*]]
|
[**--security-opt**[=*[]*]]
|
||||||
[**-t**|**--tty**[=*false*]]
|
[**-t**|**--tty**[=*false*]]
|
||||||
|
@ -140,6 +141,9 @@ IMAGE [COMMAND] [ARG...]
|
||||||
**--privileged**=*true*|*false*
|
**--privileged**=*true*|*false*
|
||||||
Give extended privileges to this container. The default is *false*.
|
Give extended privileges to this container. The default is *false*.
|
||||||
|
|
||||||
|
**--read-only**=*true*|*false*
|
||||||
|
Mount the container's root filesystem as read only.
|
||||||
|
|
||||||
**--restart**=""
|
**--restart**=""
|
||||||
Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ docker-run - Run a command in a new container
|
||||||
[**-p**|**--publish**[=*[]*]]
|
[**-p**|**--publish**[=*[]*]]
|
||||||
[**--pid**[=*[]*]]
|
[**--pid**[=*[]*]]
|
||||||
[**--privileged**[=*false*]]
|
[**--privileged**[=*false*]]
|
||||||
|
[**--read-only**[=*false*]]
|
||||||
[**--restart**[=*RESTART*]]
|
[**--restart**[=*RESTART*]]
|
||||||
[**--rm**[=*false*]]
|
[**--rm**[=*false*]]
|
||||||
[**--security-opt**[=*[]*]]
|
[**--security-opt**[=*[]*]]
|
||||||
|
@ -253,6 +254,13 @@ to all devices on the host as well as set some configuration in AppArmor to
|
||||||
allow the container nearly all the same access to the host as processes running
|
allow the container nearly all the same access to the host as processes running
|
||||||
outside of a container on the host.
|
outside of a container on the host.
|
||||||
|
|
||||||
|
**--read-only**=*true*|*false*
|
||||||
|
Mount the container's root filesystem as read only.
|
||||||
|
|
||||||
|
By default a container will have its root filesystem writable allowing processes
|
||||||
|
to write files anywhere. By specifying the `--read-only` flag the container will have
|
||||||
|
its root filesystem mounted as read only prohibiting any writes.
|
||||||
|
|
||||||
**--restart**=""
|
**--restart**=""
|
||||||
Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,13 @@ This endpoint now returns the list current execs associated with the container (
|
||||||
**New!**
|
**New!**
|
||||||
New endpoint to rename a container `id` to a new name.
|
New endpoint to rename a container `id` to a new name.
|
||||||
|
|
||||||
|
`POST /containers/create`
|
||||||
|
`POST /containers/(id)/start`
|
||||||
|
|
||||||
|
**New!**
|
||||||
|
(`ReadonlyRootfs`) can be passed in the host config to mount the container's
|
||||||
|
root filesystem as read only.
|
||||||
|
|
||||||
## v1.16
|
## v1.16
|
||||||
|
|
||||||
### Full Documentation
|
### Full Documentation
|
||||||
|
|
|
@ -146,6 +146,7 @@ Create a container
|
||||||
"PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
|
"PortBindings": { "22/tcp": [{ "HostPort": "11022" }] },
|
||||||
"PublishAllPorts": false,
|
"PublishAllPorts": false,
|
||||||
"Privileged": false,
|
"Privileged": false,
|
||||||
|
"ReadonlyRootfs": false,
|
||||||
"Dns": ["8.8.8.8"],
|
"Dns": ["8.8.8.8"],
|
||||||
"DnsSearch": [""],
|
"DnsSearch": [""],
|
||||||
"VolumesFrom": ["parent", "other:ro"],
|
"VolumesFrom": ["parent", "other:ro"],
|
||||||
|
@ -218,6 +219,8 @@ Json Parameters:
|
||||||
exposed ports. Specified as a boolean value.
|
exposed ports. Specified as a boolean value.
|
||||||
- **Privileged** - Gives the container full access to the host. Specified as
|
- **Privileged** - Gives the container full access to the host. Specified as
|
||||||
a boolean value.
|
a boolean value.
|
||||||
|
- **ReadonlyRootfs** - Mount the container's root filesystem as read only.
|
||||||
|
Specified as a boolean value.
|
||||||
- **Dns** - A list of dns servers for the container to use.
|
- **Dns** - A list of dns servers for the container to use.
|
||||||
- **DnsSearch** - A list of DNS search domains
|
- **DnsSearch** - A list of DNS search domains
|
||||||
- **VolumesFrom** - A list of volumes to inherit from another container.
|
- **VolumesFrom** - A list of volumes to inherit from another container.
|
||||||
|
@ -323,6 +326,7 @@ Return low-level information on the container `id`
|
||||||
"NetworkMode": "bridge",
|
"NetworkMode": "bridge",
|
||||||
"PortBindings": {},
|
"PortBindings": {},
|
||||||
"Privileged": false,
|
"Privileged": false,
|
||||||
|
"ReadonlyRootfs": false,
|
||||||
"PublishAllPorts": false,
|
"PublishAllPorts": false,
|
||||||
"RestartPolicy": {
|
"RestartPolicy": {
|
||||||
"MaximumRetryCount": 2,
|
"MaximumRetryCount": 2,
|
||||||
|
|
|
@ -755,6 +755,7 @@ Creates a new container.
|
||||||
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`)
|
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)
|
(use 'docker port' to see the actual mapping)
|
||||||
--privileged=false Give extended privileges to this container
|
--privileged=false Give extended privileges to this container
|
||||||
|
--read-only=false Mount the container's root filesystem as read only
|
||||||
--restart="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
--restart="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
||||||
--security-opt=[] Security Options
|
--security-opt=[] Security Options
|
||||||
-t, --tty=false Allocate a pseudo-TTY
|
-t, --tty=false Allocate a pseudo-TTY
|
||||||
|
@ -1608,6 +1609,7 @@ removed before the image is removed.
|
||||||
(use 'docker port' to see the actual mapping)
|
(use 'docker port' to see the actual mapping)
|
||||||
--pid=host 'host': use the host PID namespace inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.
|
--pid=host 'host': use the host PID namespace inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.
|
||||||
--privileged=false Give extended privileges to this container
|
--privileged=false Give extended privileges to this container
|
||||||
|
--read-only=false Mount the container's root filesystem as read only
|
||||||
--restart="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
--restart="" Restart policy to apply when a container exits (no, on-failure[:max-retry], always)
|
||||||
--rm=false Automatically remove the container when it exits (incompatible with -d)
|
--rm=false Automatically remove the container when it exits (incompatible with -d)
|
||||||
--security-opt=[] Security Options
|
--security-opt=[] Security Options
|
||||||
|
@ -1683,6 +1685,13 @@ will automatically create this directory on the host for you. In the
|
||||||
example above, Docker will create the `/doesnt/exist`
|
example above, Docker will create the `/doesnt/exist`
|
||||||
folder before starting your container.
|
folder before starting your container.
|
||||||
|
|
||||||
|
$ sudo docker run --read-only -v /icanwrite busybox touch /icanwrite here
|
||||||
|
|
||||||
|
Volumes can be used in combination with `--read-only` to control where
|
||||||
|
a container writes files. The `--read only` flag mounts the container's root
|
||||||
|
filesystem as read only prohibiting writes to locations other than the
|
||||||
|
specified volumes for the container.
|
||||||
|
|
||||||
$ sudo docker run -t -i -v /var/run/docker.sock:/var/run/docker.sock -v ./static-docker:/usr/bin/docker busybox sh
|
$ sudo docker run -t -i -v /var/run/docker.sock:/var/run/docker.sock -v ./static-docker:/usr/bin/docker busybox sh
|
||||||
|
|
||||||
By bind-mounting the docker unix socket and statically linked docker
|
By bind-mounting the docker unix socket and statically linked docker
|
||||||
|
|
|
@ -3036,3 +3036,25 @@ func TestRunRestartMaxRetries(t *testing.T) {
|
||||||
}
|
}
|
||||||
logDone("run - test max-retries for --restart")
|
logDone("run - test max-retries for --restart")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunContainerWithWritableRootfs(t *testing.T) {
|
||||||
|
defer deleteAllContainers()
|
||||||
|
out, err := exec.Command(dockerBinary, "run", "--rm", "busybox", "touch", "/file").CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(string(out), err)
|
||||||
|
}
|
||||||
|
logDone("run - writable rootfs")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunContainerWithReadonlyRootfs(t *testing.T) {
|
||||||
|
defer deleteAllContainers()
|
||||||
|
out, err := exec.Command(dockerBinary, "run", "--read-only", "--rm", "busybox", "touch", "/file").CombinedOutput()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected container to error on run with read only error")
|
||||||
|
}
|
||||||
|
expected := "Read-only file system"
|
||||||
|
if !strings.Contains(string(out), expected) {
|
||||||
|
t.Fatalf("expected output from failure to contain %s but contains %s", expected, out)
|
||||||
|
}
|
||||||
|
logDone("run - read only rootfs")
|
||||||
|
}
|
||||||
|
|
|
@ -118,6 +118,7 @@ type HostConfig struct {
|
||||||
CapDrop []string
|
CapDrop []string
|
||||||
RestartPolicy RestartPolicy
|
RestartPolicy RestartPolicy
|
||||||
SecurityOpt []string
|
SecurityOpt []string
|
||||||
|
ReadonlyRootfs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used by the create command when you want to set both the
|
// This is used by the create command when you want to set both the
|
||||||
|
@ -148,6 +149,7 @@ func ContainerHostConfigFromJob(job *engine.Job) *HostConfig {
|
||||||
NetworkMode: NetworkMode(job.Getenv("NetworkMode")),
|
NetworkMode: NetworkMode(job.Getenv("NetworkMode")),
|
||||||
IpcMode: IpcMode(job.Getenv("IpcMode")),
|
IpcMode: IpcMode(job.Getenv("IpcMode")),
|
||||||
PidMode: PidMode(job.Getenv("PidMode")),
|
PidMode: PidMode(job.Getenv("PidMode")),
|
||||||
|
ReadonlyRootfs: job.GetenvBool("ReadonlyRootfs"),
|
||||||
}
|
}
|
||||||
|
|
||||||
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
job.GetenvJson("LxcConf", &hostConfig.LxcConf)
|
||||||
|
|
|
@ -63,6 +63,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
|
flMacAddress = cmd.String([]string{"-mac-address"}, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)")
|
||||||
flIpcMode = cmd.String([]string{"-ipc"}, "", "Default is to create a private IPC namespace (POSIX SysV IPC) for the container\n'container:<name|id>': reuses another container shared memory, semaphores and message queues\n'host': use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure.")
|
flIpcMode = cmd.String([]string{"-ipc"}, "", "Default is to create a private IPC namespace (POSIX SysV IPC) for the container\n'container:<name|id>': reuses another container shared memory, semaphores and message queues\n'host': use the host shared memory,semaphores and message queues inside the container. Note: the host mode gives the container full access to local shared memory and is therefore considered insecure.")
|
||||||
flRestartPolicy = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)")
|
flRestartPolicy = cmd.String([]string{"-restart"}, "", "Restart policy to apply when a container exits (no, on-failure[:max-retry], always)")
|
||||||
|
flReadonlyRootfs = cmd.Bool([]string{"-read-only"}, false, "Mount the container's root filesystem as read only")
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR.")
|
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR.")
|
||||||
|
@ -312,6 +313,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
CapDrop: flCapDrop.GetAll(),
|
CapDrop: flCapDrop.GetAll(),
|
||||||
RestartPolicy: restartPolicy,
|
RestartPolicy: restartPolicy,
|
||||||
SecurityOpt: flSecurityOpt.GetAll(),
|
SecurityOpt: flSecurityOpt.GetAll(),
|
||||||
|
ReadonlyRootfs: *flReadonlyRootfs,
|
||||||
}
|
}
|
||||||
|
|
||||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||||
|
|
Loading…
Reference in a new issue