Skip to content

Commit 1fc7510

Browse files
committed
volume: allow a prefix for all bind mounts
Introduce a new config --bind-mount-prefix=PREFIX that adds a prefix to the source for every bind mount. This allows Docker to run inside of a container, and be able to see the host rootfs. As an example: running Docker with --bind-mount-prefix=/host, will convert: docker run -v /var/lib/mariadb:/var/lib/mariadb ... to: docker run -v /host/var/lib/mariadb:/var/lib/mariadb ... Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> (cherry picked from commit 38e1b7d)
1 parent 2d99c6f commit 1fc7510

6 files changed

Lines changed: 28 additions & 14 deletions

File tree

contrib/completion/bash/docker

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,7 @@ _docker_daemon() {
18651865
--add-runtime
18661866
--api-cors-header
18671867
--authorization-plugin
1868+
--bind-mount-prefix
18681869
--bip
18691870
--block-registry
18701871
--bridge -b

daemon/config_unix.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type Config struct {
3838
SeccompProfile string `json:"seccomp-profile,omitempty"`
3939
SigCheck bool `json:"signature-verification"`
4040
EnableSecrets bool `json:"enable-secrets"`
41+
BindMountPrefix string `json:"bind-mount-prefix"`
4142
}
4243

4344
// bridgeConfig stores all the bridge driver specific
@@ -93,6 +94,7 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
9394
flags.StringVar(&config.SeccompProfile, "seccomp-profile", "", "Path to seccomp profile")
9495
flags.BoolVar(&config.SigCheck, "signature-verification", true, "Check image's signatures on pull")
9596
flags.BoolVar(&config.EnableSecrets, "enable-secrets", true, "Enable Secrets")
97+
flags.StringVar(&config.BindMountPrefix, "bind-mount-prefix", "", "Specify a prefix to prepend to the source of a bind mount")
9698

9799
config.attachExperimentalFlags(flags)
98100
}

daemon/volumes_unix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
4343
return nil, err
4444
}
4545
rootUID, rootGID := daemon.GetRemappedUIDGID()
46-
path, err := m.Setup(c.MountLabel, rootUID, rootGID)
46+
path, err := m.Setup(daemon.configStore.BindMountPrefix, c.MountLabel, rootUID, rootGID)
4747
if err != nil {
4848
return nil, err
4949
}

docs/reference/commandline/dockerd.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Options:
2525
--add-runtime value Register an additional OCI compatible runtime (default [])
2626
--api-cors-header string Set CORS headers in the Engine API
2727
--authorization-plugin value Authorization plugins to load (default [])
28+
--bind-mount-prefix Specify a prefix to prepend to the source of a bind mount
2829
--bip string Specify network bridge IP
2930
-b, --bridge string Attach containers to a network bridge
3031
--cgroup-parent string Set parent cgroup for all containers

man/dockerd.8.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dockerd - Enable daemon mode
1111
[**--api-cors-header**=[=*API-CORS-HEADER*]]
1212
[**--authorization-plugin**[=*[]*]]
1313
[**-b**|**--bridge**[=*BRIDGE*]]
14+
[**--bind-mount-prefix[=*PREFIX*]]
1415
[**--bip**[=*BIP*]]
1516
[**--block-registry**[=*[]*]]
1617
[**--cgroup-parent**[=*[]*]]
@@ -133,6 +134,9 @@ $ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-ru
133134
Attach containers to a pre\-existing network bridge; use 'none' to disable
134135
container networking
135136

137+
**--bind-mount-prefix**=""
138+
Specify a prefix to use for the source of the bind mounts.
139+
136140
**--bip**=""
137141
Use the provided CIDR notation address for the dynamically created bridge
138142
(docker0); Mutually exclusive of \-b

volume/volume.go

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
mounttypes "github.com/docker/docker/api/types/mount"
1111
"github.com/docker/docker/pkg/idtools"
12+
"github.com/docker/docker/pkg/symlink"
1213
"github.com/docker/docker/pkg/stringid"
1314
"github.com/opencontainers/runc/libcontainer/label"
1415
"github.com/pkg/errors"
@@ -124,23 +125,28 @@ type MountPoint struct {
124125

125126
// Setup sets up a mount point by either mounting the volume if it is
126127
// configured, or creating the source directory if supplied.
127-
func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (path string, err error) {
128+
func (m *MountPoint) Setup(prefix, mountLabel string, rootUID, rootGID int) (path string, err error) {
129+
symlinkRoot := prefix
130+
if symlinkRoot == "" {
131+
symlinkRoot = "/"
132+
}
133+
sourcePath, err := symlink.FollowSymlinkInScope(filepath.Join(prefix, m.Source), symlinkRoot)
134+
if err != nil {
135+
path = ""
136+
err = errors.Wrapf(err, "error evaluating symlink from mount source '%s'", m.Source)
137+
return
138+
}
139+
128140
defer func() {
129141
if err == nil {
130142
if label.RelabelNeeded(m.Mode) {
131-
sourcePath, err := filepath.EvalSymlinks(m.Source)
132-
if err != nil {
133-
path = ""
134-
err = errors.Wrapf(err, "error evaluating symlink from mount source '%s'", m.Source)
135-
return
136-
}
137143
err = label.Relabel(sourcePath, mountLabel, label.IsShared(m.Mode))
138144
if err == syscall.ENOTSUP {
139145
err = nil
140146
}
141147
if err != nil {
142148
path = ""
143-
err = errors.Wrapf(err, "error setting label on mount source '%s'", m.Source)
149+
err = errors.Wrapf(err, "error setting label on mount source '%s'", sourcePath)
144150
return
145151
}
146152
}
@@ -162,19 +168,19 @@ func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (path string
162168
if len(m.Source) == 0 {
163169
return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined")
164170
}
165-
// system.MkdirAll() produces an error if m.Source exists and is a file (not a directory),
171+
// system.MkdirAll() produces an error if source exists and is a file (not a directory),
166172
if m.Type == mounttypes.TypeBind {
167-
// idtools.MkdirAllNewAs() produces an error if m.Source exists and is a file (not a directory)
173+
// idtools.MkdirAllNewAs() produces an error if source exists and is a file (not a directory)
168174
// also, makes sure that if the directory is created, the correct remapped rootUID/rootGID will own it
169-
if err := idtools.MkdirAllNewAs(m.Source, 0755, rootUID, rootGID); err != nil {
175+
if err := idtools.MkdirAllNewAs(sourcePath, 0755, rootUID, rootGID); err != nil {
170176
if perr, ok := err.(*os.PathError); ok {
171177
if perr.Err != syscall.ENOTDIR {
172-
return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source)
178+
return "", errors.Wrapf(err, "error while creating mount source path '%s'", sourcePath)
173179
}
174180
}
175181
}
176182
}
177-
return m.Source, nil
183+
return sourcePath, nil
178184
}
179185

180186
// Path returns the path of a volume in a mount point.

0 commit comments

Comments
 (0)