Support read-only root filesystems

The only place I could find where libcontainer tries to write to the
container's root FS is when setting up the pivot dir, to be used on
pivot_root(2).

This makes the pivot base dir configurable, so a read-only FS can be
used as root FS of containers. Users can then specify a writeable
subpath to be used as pivot inside the container.

Signed-off-by: Fabio Kung <fabio@heroku.com> (github: fabiokung)
This commit is contained in:
Fabio Kung 2015-01-22 13:58:41 -08:00
parent 1d3b2589d7
commit 2a452c17aa
3 changed files with 16 additions and 4 deletions

View File

@ -79,7 +79,7 @@ func InitializeMountNamespace(rootfs, console string, sysReadonly bool, mountCon
if mountConfig.NoPivotRoot { if mountConfig.NoPivotRoot {
err = MsMoveRoot(rootfs) err = MsMoveRoot(rootfs)
} else { } else {
err = PivotRoot(rootfs) err = PivotRoot(rootfs, mountConfig.PivotDir)
} }
if err != nil { if err != nil {

View File

@ -13,6 +13,11 @@ type MountConfig struct {
// This is a common option when the container is running in ramdisk // This is a common option when the container is running in ramdisk
NoPivotRoot bool `json:"no_pivot_root,omitempty"` NoPivotRoot bool `json:"no_pivot_root,omitempty"`
// PivotDir allows a custom directory inside the container's root filesystem to be used as pivot, when NoPivotRoot is not set.
// When a custom PivotDir not set, a temporary dir inside the root filesystem will be used. The pivot dir needs to be writeable.
// This is required when using read only root filesystems. In these cases, a read/writeable path can be (bind) mounted somewhere inside the root filesystem to act as pivot.
PivotDir string `json:"pivot_dir,omitempty"`
// ReadonlyFs will remount the container's rootfs as readonly where only externally mounted // ReadonlyFs will remount the container's rootfs as readonly where only externally mounted
// bind mounts are writtable // bind mounts are writtable
ReadonlyFs bool `json:"readonly_fs,omitempty"` ReadonlyFs bool `json:"readonly_fs,omitempty"`

View File

@ -10,8 +10,15 @@ import (
"syscall" "syscall"
) )
func PivotRoot(rootfs string) error { func PivotRoot(rootfs, pivotBaseDir string) error {
pivotDir, err := ioutil.TempDir(rootfs, ".pivot_root") if pivotBaseDir == "" {
pivotBaseDir = "/"
}
tmpDir := filepath.Join(rootfs, pivotBaseDir)
if err := os.MkdirAll(tmpDir, 0755); err != nil {
return fmt.Errorf("can't create tmp dir %s, error %v", tmpDir, err)
}
pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root")
if err != nil { if err != nil {
return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err) return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
} }
@ -25,7 +32,7 @@ func PivotRoot(rootfs string) error {
} }
// path to pivot dir now changed, update // path to pivot dir now changed, update
pivotDir = filepath.Join("/", filepath.Base(pivotDir)) pivotDir = filepath.Join(pivotBaseDir, filepath.Base(pivotDir))
if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil { if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
return fmt.Errorf("unmount pivot_root dir %s", err) return fmt.Errorf("unmount pivot_root dir %s", err)
} }