Implement --volume and --shm-size for bud and from
Add the remaining --volume and --shm-size flags to buildah bud and from --volume supports the following options: rw, ro, z, Z, private, slave, shared Signed-off-by: umohnani8 <umohnani@redhat.com> Closes: #491 Approved by: rhatdan
This commit is contained in:
parent
669ffddd99
commit
4bbe6e7cc0
|
@ -161,8 +161,12 @@ type CommonBuildOptions struct {
|
|||
LabelOpts []string
|
||||
SeccompProfilePath string
|
||||
ApparmorProfile string
|
||||
//ShmSize is the shared memory size
|
||||
ShmSize string
|
||||
//Ulimit options
|
||||
Ulimit []string
|
||||
//Volumes to bind mount into the container
|
||||
Volumes []string
|
||||
}
|
||||
|
||||
// BuilderOptions are used to initialize a new Builder.
|
||||
|
|
|
@ -268,10 +268,19 @@ var fromAndBudFlags = []cli.Flag{
|
|||
Name: "security-opt",
|
||||
Usage: "security Options (default [])",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "shm-size",
|
||||
Usage: "size of `/dev/shm`. The format is `<number><unit>`.",
|
||||
Value: "65536k",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "ulimit",
|
||||
Usage: "ulimit options (default [])",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "volume, v",
|
||||
Usage: "bind mount a volume into the container (default [])",
|
||||
},
|
||||
}
|
||||
|
||||
func parseCommonBuildOptions(c *cli.Context) (*buildah.CommonBuildOptions, error) {
|
||||
|
@ -299,6 +308,12 @@ func parseCommonBuildOptions(c *cli.Context) (*buildah.CommonBuildOptions, error
|
|||
}
|
||||
}
|
||||
}
|
||||
if _, err := units.FromHumanSize(c.String("shm-size")); err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid --shm-size")
|
||||
}
|
||||
if err := parseVolumes(c.StringSlice("volume")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commonOpts := &buildah.CommonBuildOptions{
|
||||
AddHost: c.StringSlice("add-host"),
|
||||
|
@ -310,7 +325,9 @@ func parseCommonBuildOptions(c *cli.Context) (*buildah.CommonBuildOptions, error
|
|||
CPUShares: c.Uint64("cpu-shares"),
|
||||
Memory: memoryLimit,
|
||||
MemorySwap: memorySwap,
|
||||
ShmSize: c.String("shm-size"),
|
||||
Ulimit: c.StringSlice("ulimit"),
|
||||
Volumes: c.StringSlice("volume"),
|
||||
}
|
||||
if err := parseSecurityOpts(c.StringSlice("security-opt"), commonOpts); err != nil {
|
||||
return nil, err
|
||||
|
@ -360,6 +377,71 @@ func parseSecurityOpts(securityOpts []string, commonOpts *buildah.CommonBuildOpt
|
|||
return nil
|
||||
}
|
||||
|
||||
func parseVolumes(volumes []string) error {
|
||||
if len(volumes) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, volume := range volumes {
|
||||
arr := strings.SplitN(volume, ":", 3)
|
||||
if len(arr) < 2 {
|
||||
return errors.Errorf("incorrect volume format %q, should be host-dir:ctr-dir[:option]", volume)
|
||||
}
|
||||
if err := validateVolumeHostDir(arr[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateVolumeCtrDir(arr[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(arr) > 2 {
|
||||
if err := validateVolumeOpts(arr[2]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateVolumeHostDir(hostDir string) error {
|
||||
if _, err := os.Stat(hostDir); err != nil {
|
||||
return errors.Wrapf(err, "error checking path %q", hostDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateVolumeCtrDir(ctrDir string) error {
|
||||
if ctrDir[0] != '/' {
|
||||
return errors.Errorf("invalid container directory path %q", ctrDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateVolumeOpts(option string) error {
|
||||
var foundRootPropagation, foundRWRO, foundLabelChange int
|
||||
options := strings.Split(option, ",")
|
||||
for _, opt := range options {
|
||||
switch opt {
|
||||
case "rw", "ro":
|
||||
if foundRWRO > 1 {
|
||||
return errors.Errorf("invalid options %q, can only specify 1 'rw' or 'ro' option", option)
|
||||
}
|
||||
foundRWRO++
|
||||
case "z", "Z":
|
||||
if foundLabelChange > 1 {
|
||||
return errors.Errorf("invalid options %q, can only specify 1 'z' or 'Z' option", option)
|
||||
}
|
||||
foundLabelChange++
|
||||
case "private", "rprivate", "shared", "rshared", "slave", "rslave":
|
||||
if foundRootPropagation > 1 {
|
||||
return errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private' or '[r]slave' option", option)
|
||||
}
|
||||
foundRootPropagation++
|
||||
default:
|
||||
return errors.Errorf("invalid option type %q", option)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateExtraHost validates that the specified string is a valid extrahost and returns it.
|
||||
// ExtraHost is in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6).
|
||||
// for add-host flag
|
||||
|
|
|
@ -194,6 +194,12 @@ Security Options
|
|||
"apparmor=unconfined" : Turn off apparmor confinement for the container
|
||||
"apparmor=your-profile" : Set the apparmor confinement profile for the container
|
||||
|
||||
**--shm-size**=""
|
||||
|
||||
Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`.
|
||||
Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or `g` (gigabytes).
|
||||
If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
|
||||
|
||||
**--signature-policy** *signaturepolicy*
|
||||
|
||||
Pathname of a signature policy file to use. It is not recommended that this
|
||||
|
@ -213,6 +219,71 @@ Require HTTPS and verify certificates when talking to container registries (defa
|
|||
|
||||
Ulimit options
|
||||
|
||||
**-v**|**--volume**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*]
|
||||
|
||||
Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, podman
|
||||
bind mounts `/HOST-DIR` in the host to `/CONTAINER-DIR` in the podman
|
||||
container. The `OPTIONS` are a comma delimited list and can be:
|
||||
|
||||
* [rw|ro]
|
||||
* [z|Z]
|
||||
* [`[r]shared`|`[r]slave`|`[r]private`]
|
||||
|
||||
The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The `HOST-DIR`
|
||||
must be an absolute path as well. podman bind-mounts the `HOST-DIR` to the
|
||||
path you specify. For example, if you supply the `/foo` value, podman creates a bind-mount.
|
||||
|
||||
You can specify multiple **-v** options to mount one or more mounts to a
|
||||
container.
|
||||
|
||||
You can add `:ro` or `:rw` suffix to a volume to mount it read-only or
|
||||
read-write mode, respectively. By default, the volumes are mounted read-write.
|
||||
See examples.
|
||||
|
||||
Labeling systems like SELinux require that proper labels are placed on volume
|
||||
content mounted into a container. Without a label, the security system might
|
||||
prevent the processes running inside the container from using the content. By
|
||||
default, podman does not change the labels set by the OS.
|
||||
|
||||
To change a label in the container context, you can add either of two suffixes
|
||||
`:z` or `:Z` to the volume mount. These suffixes tell podman to relabel file
|
||||
objects on the shared volumes. The `z` option tells podman that two containers
|
||||
share the volume content. As a result, podman labels the content with a shared
|
||||
content label. Shared volume labels allow all containers to read/write content.
|
||||
The `Z` option tells podman to label the content with a private unshared label.
|
||||
Only the current container can use a private volume.
|
||||
|
||||
By default bind mounted volumes are `private`. That means any mounts done
|
||||
inside container will not be visible on the host and vice versa. This behavior can
|
||||
be changed by specifying a volume mount propagation property.
|
||||
|
||||
When the mount propagation policy is set to `shared`, any mounts completed inside
|
||||
the container on that volume will be visible to both the host and container. When
|
||||
the mount propagation policy is set to `slave`, one way mount propagation is enabled
|
||||
and any mounts completed on the host for that volume will be visible only inside of the container.
|
||||
To control the mount propagation property of volume use the `:[r]shared`,
|
||||
`:[r]slave` or `:[r]private` propagation flag. The propagation property can
|
||||
be specified only for bind mounted volumes and not for internal volumes or
|
||||
named volumes. For mount propagation to work on the source mount point (mount point
|
||||
where source dir is mounted on) has to have the right propagation properties. For
|
||||
shared volumes, the source mount point has to be shared. And for slave volumes,
|
||||
the source mount has to be either shared or slave.
|
||||
|
||||
Use `df <source-dir>` to determine the source mount and then use
|
||||
`findmnt -o TARGET,PROPAGATION <source-mount-dir>` to determine propagation
|
||||
properties of source mount, if `findmnt` utility is not available, the source mount point
|
||||
can be determined by looking at the mount entry in `/proc/self/mountinfo`. Look
|
||||
at `optional fields` and see if any propagaion properties are specified.
|
||||
`shared:X` means the mount is `shared`, `master:X` means the mount is `slave` and if
|
||||
nothing is there that means the mount is `private`.
|
||||
|
||||
To change propagation properties of a mount point use the `mount` command. For
|
||||
example, to bind mount the source directory `/foo` do
|
||||
`mount --bind /foo /foo` and `mount --make-private --make-shared /foo`. This
|
||||
will convert /foo into a `shared` mount point. The propagation properties of the source
|
||||
mount can be changed directly. For instance if `/` is the source mount for
|
||||
`/foo`, then use `mount --make-shared /` to convert `/` into a `shared` mount.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
buildah bud .
|
||||
|
@ -237,5 +308,7 @@ buildah bud --memory 40m --cpu-period 10000 --cpu-quota 50000 --ulimit nofile=10
|
|||
|
||||
buildah bud --security-opt label=level:s0:c100,c200 --cgroup-parent /path/to/cgroup/parent -t imageName .
|
||||
|
||||
buildah bud --volume /home/test:/myvol:ro,Z -t imageName .
|
||||
|
||||
## SEE ALSO
|
||||
buildah(1), podman-login(1), docker-login(1)
|
||||
|
|
|
@ -181,6 +181,12 @@ Security Options
|
|||
"apparmor=unconfined" : Turn off apparmor confinement for the container
|
||||
"apparmor=your-profile" : Set the apparmor confinement profile for the container
|
||||
|
||||
**--shm-size**=""
|
||||
|
||||
Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`.
|
||||
Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or `g` (gigabytes).
|
||||
If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`.
|
||||
|
||||
**--signature-policy** *signaturepolicy*
|
||||
|
||||
Pathname of a signature policy file to use. It is not recommended that this
|
||||
|
@ -195,6 +201,71 @@ Require HTTPS and verify certificates when talking to container registries (defa
|
|||
|
||||
Ulimit options
|
||||
|
||||
**-v**|**--volume**[=*[HOST-DIR:CONTAINER-DIR[:OPTIONS]]*]
|
||||
|
||||
Create a bind mount. If you specify, ` -v /HOST-DIR:/CONTAINER-DIR`, podman
|
||||
bind mounts `/HOST-DIR` in the host to `/CONTAINER-DIR` in the podman
|
||||
container. The `OPTIONS` are a comma delimited list and can be:
|
||||
|
||||
* [rw|ro]
|
||||
* [z|Z]
|
||||
* [`[r]shared`|`[r]slave`|`[r]private`]
|
||||
|
||||
The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The `HOST-DIR`
|
||||
must be an absolute path as well. podman bind-mounts the `HOST-DIR` to the
|
||||
path you specify. For example, if you supply the `/foo` value, podman creates a bind-mount.
|
||||
|
||||
You can specify multiple **-v** options to mount one or more mounts to a
|
||||
container.
|
||||
|
||||
You can add `:ro` or `:rw` suffix to a volume to mount it read-only or
|
||||
read-write mode, respectively. By default, the volumes are mounted read-write.
|
||||
See examples.
|
||||
|
||||
Labeling systems like SELinux require that proper labels are placed on volume
|
||||
content mounted into a container. Without a label, the security system might
|
||||
prevent the processes running inside the container from using the content. By
|
||||
default, podman does not change the labels set by the OS.
|
||||
|
||||
To change a label in the container context, you can add either of two suffixes
|
||||
`:z` or `:Z` to the volume mount. These suffixes tell podman to relabel file
|
||||
objects on the shared volumes. The `z` option tells podman that two containers
|
||||
share the volume content. As a result, podman labels the content with a shared
|
||||
content label. Shared volume labels allow all containers to read/write content.
|
||||
The `Z` option tells podman to label the content with a private unshared label.
|
||||
Only the current container can use a private volume.
|
||||
|
||||
By default bind mounted volumes are `private`. That means any mounts done
|
||||
inside container will not be visible on the host and vice versa. This behavior can
|
||||
be changed by specifying a volume mount propagation property.
|
||||
|
||||
When the mount propagation policy is set to `shared`, any mounts completed inside
|
||||
the container on that volume will be visible to both the host and container. When
|
||||
the mount propagation policy is set to `slave`, one way mount propagation is enabled
|
||||
and any mounts completed on the host for that volume will be visible only inside of the container.
|
||||
To control the mount propagation property of volume use the `:[r]shared`,
|
||||
`:[r]slave` or `:[r]private` propagation flag. The propagation property can
|
||||
be specified only for bind mounted volumes and not for internal volumes or
|
||||
named volumes. For mount propagation to work on the source mount point (mount point
|
||||
where source dir is mounted on) has to have the right propagation properties. For
|
||||
shared volumes, the source mount point has to be shared. And for slave volumes,
|
||||
the source mount has to be either shared or slave.
|
||||
|
||||
Use `df <source-dir>` to determine the source mount and then use
|
||||
`findmnt -o TARGET,PROPAGATION <source-mount-dir>` to determine propagation
|
||||
properties of source mount, if `findmnt` utility is not available, the source mount point
|
||||
can be determined by looking at the mount entry in `/proc/self/mountinfo`. Look
|
||||
at `optional fields` and see if any propagaion properties are specified.
|
||||
`shared:X` means the mount is `shared`, `master:X` means the mount is `slave` and if
|
||||
nothing is there that means the mount is `private`.
|
||||
|
||||
To change propagation properties of a mount point use the `mount` command. For
|
||||
example, to bind mount the source directory `/foo` do
|
||||
`mount --bind /foo /foo` and `mount --make-private --make-shared /foo`. This
|
||||
will convert /foo into a `shared` mount point. The propagation properties of the source
|
||||
mount can be changed directly. For instance if `/` is the source mount for
|
||||
`/foo`, then use `mount --make-shared /` to convert `/` into a `shared` mount.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
buildah from imagename --pull
|
||||
|
@ -215,5 +286,7 @@ buildah from --memory 40m --cpu-shares 2 --cpuset-cpus 0,2 --security-opt label=
|
|||
|
||||
buildah from --ulimit nofile=1024:1028 --cgroup-parent /path/to/cgroup/parent myregistry/myrepository/imagename:imagetag
|
||||
|
||||
buildah from --volume /home/test:/myvol:ro,Z myregistry/myrepository/imagename:imagetag
|
||||
|
||||
## SEE ALSO
|
||||
buildah(1), podman-login(1), docker-login(1)
|
||||
|
|
60
run.go
60
run.go
|
@ -147,7 +147,7 @@ func addCommonOptsToSpec(commonOpts *CommonBuildOptions, g *generate.Generator)
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts []specs.Mount, bindFiles, volumes []string) error {
|
||||
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts []specs.Mount, bindFiles, builtinVolumes, volumeMounts []string, shmSize string) error {
|
||||
// The passed-in mounts matter the most to us.
|
||||
mounts := make([]specs.Mount, len(optionMounts))
|
||||
copy(mounts, optionMounts)
|
||||
|
@ -162,6 +162,9 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts
|
|||
}
|
||||
// Add mounts from the generated list, unless they conflict.
|
||||
for _, specMount := range spec.Mounts {
|
||||
if specMount.Destination == "/dev/shm" {
|
||||
specMount.Options = []string{"nosuid", "noexec", "nodev", "mode=1777", "size=" + shmSize}
|
||||
}
|
||||
if haveMount(specMount.Destination) {
|
||||
// Already have something to mount there, so skip this one.
|
||||
continue
|
||||
|
@ -204,7 +207,7 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts
|
|||
}
|
||||
// Add temporary copies of the contents of volume locations at the
|
||||
// volume locations, unless we already have something there.
|
||||
for _, volume := range volumes {
|
||||
for _, volume := range builtinVolumes {
|
||||
if haveMount(volume) {
|
||||
// Already mounting something there, no need to bother.
|
||||
continue
|
||||
|
@ -233,6 +236,57 @@ func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts
|
|||
Options: []string{"bind"},
|
||||
})
|
||||
}
|
||||
// Bind mount volumes given by the user at execution
|
||||
var options []string
|
||||
for _, i := range volumeMounts {
|
||||
spliti := strings.Split(i, ":")
|
||||
if len(spliti) > 2 {
|
||||
options = strings.Split(spliti[2], ",")
|
||||
}
|
||||
if haveMount(spliti[1]) {
|
||||
continue
|
||||
}
|
||||
options = append(options, "rbind")
|
||||
var foundrw, foundro, foundz, foundZ bool
|
||||
var rootProp string
|
||||
for _, opt := range options {
|
||||
switch opt {
|
||||
case "rw":
|
||||
foundrw = true
|
||||
case "ro":
|
||||
foundro = true
|
||||
case "z":
|
||||
foundz = true
|
||||
case "Z":
|
||||
foundZ = true
|
||||
case "private", "rprivate", "slave", "rslave", "shared", "rshared":
|
||||
rootProp = opt
|
||||
}
|
||||
}
|
||||
if !foundrw && !foundro {
|
||||
options = append(options, "rw")
|
||||
}
|
||||
if foundz {
|
||||
if err := label.Relabel(spliti[0], spec.Linux.MountLabel, true); err != nil {
|
||||
return errors.Wrapf(err, "relabel failed %q", spliti[0])
|
||||
}
|
||||
}
|
||||
if foundZ {
|
||||
if err := label.Relabel(spliti[0], spec.Linux.MountLabel, false); err != nil {
|
||||
return errors.Wrapf(err, "relabel failed %q", spliti[0])
|
||||
}
|
||||
}
|
||||
if rootProp == "" {
|
||||
options = append(options, "private")
|
||||
}
|
||||
|
||||
mounts = append(mounts, specs.Mount{
|
||||
Destination: spliti[1],
|
||||
Type: "bind",
|
||||
Source: spliti[0],
|
||||
Options: options,
|
||||
})
|
||||
}
|
||||
// Set the list in the spec.
|
||||
spec.Mounts = mounts
|
||||
return nil
|
||||
|
@ -381,7 +435,7 @@ func (b *Builder) Run(command []string, options RunOptions) error {
|
|||
g.AddMount(cgroupMnt)
|
||||
|
||||
bindFiles := []string{"/etc/hosts", "/etc/resolv.conf"}
|
||||
err = b.setupMounts(mountPoint, spec, options.Mounts, bindFiles, b.Volumes())
|
||||
err = b.setupMounts(mountPoint, spec, options.Mounts, bindFiles, b.Volumes(), b.CommonBuildOpts.Volumes, b.CommonBuildOpts.ShmSize)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error resolving mountpoints for container")
|
||||
}
|
||||
|
|
|
@ -182,3 +182,30 @@ load helpers
|
|||
[[ "$output" =~ 41943040 ]]
|
||||
buildah rm $cid
|
||||
}
|
||||
|
||||
@test "from volume test" {
|
||||
cid=$(buildah from --volume=${TESTDIR}:/myvol --pull --signature-policy ${TESTSDIR}/policy.json alpine)
|
||||
run buildah run $cid -- cat /proc/mounts
|
||||
echo $output
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ /myvol ]]
|
||||
buildah rm $cid
|
||||
}
|
||||
|
||||
@test "from volume ro test" {
|
||||
cid=$(buildah from --volume=${TESTDIR}:/myvol:ro --pull --signature-policy ${TESTSDIR}/policy.json alpine)
|
||||
run buildah run $cid -- cat /proc/mounts
|
||||
echo $output
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ /myvol ]]
|
||||
buildah rm $cid
|
||||
}
|
||||
|
||||
@test "from shm-size test" {
|
||||
cid=$(buildah from --shm-size=80m --pull --signature-policy ${TESTSDIR}/policy.json alpine)
|
||||
run buildah run $cid -- df -h
|
||||
echo $output
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ 80 ]]
|
||||
buildah rm $cid
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue