Add the following flags to buildah bud and from

--add-host
	--cgroup-parent
	--cpu-period
	--cpu-quota
	--cpu-shares
	--cpuset-cpus
	--cpuset-mems
	--memory
	--memory-swap
	--security-opt
	--ulimit

Signed-off-by: umohnani8 <umohnani@redhat.com>

Closes: #477
Approved by: rhatdan
This commit is contained in:
umohnani8 2018-02-13 14:58:56 -05:00 committed by Atomic Bot
parent b23f145416
commit 93a3c89943
13 changed files with 652 additions and 4 deletions

View File

@ -94,6 +94,7 @@ type Builder struct {
Docker docker.V2Image `json:"docker,omitempty"`
// DefaultMountsFilePath is the file path holding the mounts to be mounted in "host-path:container-path" format
DefaultMountsFilePath string `json:"defaultMountsFilePath,omitempty"`
CommonBuildOpts *CommonBuildOptions
}
// BuilderInfo are used as objects to display container information
@ -136,6 +137,34 @@ func GetBuildInfo(b *Builder) BuilderInfo {
}
}
// CommonBuildOptions are reseources that can be defined by flags for both buildah from and bud
type CommonBuildOptions struct {
// AddHost is the list of hostnames to add to the resolv.conf
AddHost []string
//CgroupParent it the path to cgroups under which the cgroup for the container will be created.
CgroupParent string
//CPUPeriod limits the CPU CFS (Completely Fair Scheduler) period
CPUPeriod uint64
//CPUQuota limits the CPU CFS (Completely Fair Scheduler) quota
CPUQuota int64
//CPUShares (relative weight
CPUShares uint64
//CPUSetCPUs in which to allow execution (0-3, 0,1)
CPUSetCPUs string
//CPUSetMems memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
CPUSetMems string
//Memory limit
Memory int64
//MemorySwap limit value equal to memory plus swap.
MemorySwap int64
//SecruityOpts modify the way container security is running
LabelOpts []string
SeccompProfilePath string
ApparmorProfile string
//Ulimit options
Ulimit []string
}
// BuilderOptions are used to initialize a new Builder.
type BuilderOptions struct {
// FromImage is the name of the image which should be used as the
@ -175,6 +204,7 @@ type BuilderOptions struct {
SystemContext *types.SystemContext
// DefaultMountsFilePath is the file path holding the mounts to be mounted in "host-path:container-path" format
DefaultMountsFilePath string
CommonBuildOpts *CommonBuildOptions
}
// ImportOptions are used to initialize a Builder from an existing container

View File

@ -80,7 +80,7 @@ var (
Aliases: []string{"bud"},
Usage: "Build an image using instructions in a Dockerfile",
Description: budDescription,
Flags: budFlags,
Flags: append(budFlags, fromAndBudFlags...),
Action: budCmd,
ArgsUsage: "CONTEXT-DIRECTORY | URL",
}
@ -201,6 +201,11 @@ func budCmd(c *cli.Context) error {
runtimeFlags = append(runtimeFlags, "--"+arg)
}
commonOpts, err := parseCommonBuildOptions(c)
if err != nil {
return err
}
options := imagebuildah.BuildOptions{
ContextDirectory: contextDir,
PullPolicy: pullPolicy,
@ -214,7 +219,9 @@ func budCmd(c *cli.Context) error {
RuntimeArgs: runtimeFlags,
OutputFormat: format,
SystemContext: systemContext,
CommonBuildOpts: commonOpts,
}
if !c.Bool("quiet") {
options.ReportWriter = os.Stderr
}

View File

@ -2,6 +2,7 @@ package main
import (
"fmt"
"net"
"os"
"reflect"
"regexp"
@ -11,6 +12,7 @@ import (
is "github.com/containers/image/storage"
"github.com/containers/image/types"
"github.com/containers/storage"
units "github.com/docker/go-units"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/projectatomic/buildah"
@ -18,6 +20,13 @@ import (
"golang.org/x/crypto/ssh/terminal"
)
const (
// SeccompDefaultPath defines the default seccomp path
SeccompDefaultPath = "/usr/share/containers/seccomp.json"
// SeccompOverridePath if this exists it overrides the default seccomp path
SeccompOverridePath = "/etc/crio/seccomp.json"
)
var needToShutdownStore = false
func getStore(c *cli.Context) (storage.Store, error) {
@ -217,3 +226,161 @@ func validateFlags(c *cli.Context, flags []cli.Flag) error {
}
return nil
}
var fromAndBudFlags = []cli.Flag{
cli.StringSliceFlag{
Name: "add-host",
Usage: "add a custom host-to-IP mapping (host:ip) (default [])",
},
cli.StringFlag{
Name: "cgroup-parent",
Usage: "optional parent cgroup for the container",
},
cli.Uint64Flag{
Name: "cpu-period",
Usage: "limit the CPU CFS (Completely Fair Scheduler) period",
},
cli.Int64Flag{
Name: "cpu-quota",
Usage: "limit the CPU CFS (Completely Fair Scheduler) quota",
},
cli.Uint64Flag{
Name: "cpu-shares",
Usage: "CPU shares (relative weight)",
},
cli.StringFlag{
Name: "cpuset-cpus",
Usage: "CPUs in which to allow execution (0-3, 0,1)",
},
cli.StringFlag{
Name: "cpuset-mems",
Usage: "memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.",
},
cli.StringFlag{
Name: "memory, m",
Usage: "memory limit (format: <number>[<unit>], where unit = b, k, m or g)",
},
cli.StringFlag{
Name: "memory-swap",
Usage: "swap limit equal to memory plus swap: '-1' to enable unlimited swap",
},
cli.StringSliceFlag{
Name: "security-opt",
Usage: "security Options (default [])",
},
cli.StringSliceFlag{
Name: "ulimit",
Usage: "ulimit options (default [])",
},
}
func parseCommonBuildOptions(c *cli.Context) (*buildah.CommonBuildOptions, error) {
var (
memoryLimit int64
memorySwap int64
err error
)
if c.String("memory") != "" {
memoryLimit, err = units.RAMInBytes(c.String("memory"))
if err != nil {
return nil, errors.Wrapf(err, "invalid value for memory")
}
}
if c.String("memory-swap") != "" {
memorySwap, err = units.RAMInBytes(c.String("memory-swap"))
if err != nil {
return nil, errors.Wrapf(err, "invalid value for memory-swap")
}
}
if len(c.StringSlice("add-host")) > 0 {
for _, host := range c.StringSlice("add-host") {
if err := validateExtraHost(host); err != nil {
return nil, errors.Wrapf(err, "invalid value for add-host")
}
}
}
commonOpts := &buildah.CommonBuildOptions{
AddHost: c.StringSlice("add-host"),
CgroupParent: c.String("cgroup-parent"),
CPUPeriod: c.Uint64("cpu-period"),
CPUQuota: c.Int64("cpu-quota"),
CPUSetCPUs: c.String("cpuset-cpus"),
CPUSetMems: c.String("cpuset-mems"),
CPUShares: c.Uint64("cpu-shares"),
Memory: memoryLimit,
MemorySwap: memorySwap,
Ulimit: c.StringSlice("ulimit"),
}
if err := parseSecurityOpts(c.StringSlice("security-opt"), commonOpts); err != nil {
return nil, err
}
return commonOpts, nil
}
func parseSecurityOpts(securityOpts []string, commonOpts *buildah.CommonBuildOptions) error {
for _, opt := range securityOpts {
if opt == "no-new-privileges" {
return errors.Errorf("no-new-privileges is not supported")
}
con := strings.SplitN(opt, "=", 2)
if len(con) != 2 {
return errors.Errorf("Invalid --security-opt 1: %q", opt)
}
switch con[0] {
case "label":
commonOpts.LabelOpts = append(commonOpts.LabelOpts, con[1])
case "apparmor":
commonOpts.ApparmorProfile = con[1]
case "seccomp":
commonOpts.SeccompProfilePath = con[1]
default:
return errors.Errorf("Invalid --security-opt 2: %q", opt)
}
}
if commonOpts.SeccompProfilePath == "" {
if _, err := os.Stat(SeccompOverridePath); err == nil {
commonOpts.SeccompProfilePath = SeccompOverridePath
} else {
if !os.IsNotExist(err) {
return errors.Wrapf(err, "can't check if %q exists", SeccompOverridePath)
}
if _, err := os.Stat(SeccompDefaultPath); err != nil {
if !os.IsNotExist(err) {
return errors.Wrapf(err, "can't check if %q exists", SeccompDefaultPath)
}
} else {
commonOpts.SeccompProfilePath = SeccompDefaultPath
}
}
}
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
func validateExtraHost(val string) error {
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
arr := strings.SplitN(val, ":", 2)
if len(arr) != 2 || len(arr[0]) == 0 {
return fmt.Errorf("bad format for add-host: %q", val)
}
if _, err := validateIPAddress(arr[1]); err != nil {
return fmt.Errorf("invalid IP address in add-host: %q", arr[1])
}
return nil
}
// validateIPAddress validates an Ip address.
// for dns, ip, and ip6 flags also
func validateIPAddress(val string) (string, error) {
var ip = net.ParseIP(strings.TrimSpace(val))
if ip != nil {
return ip.String(), nil
}
return "", fmt.Errorf("%s is not an ip address", val)
}

View File

@ -105,9 +105,13 @@ func pullTestImage(t *testing.T, imageName string) (string, error) {
if err != nil {
t.Fatal(err)
}
commonOpts := &buildah.CommonBuildOptions{
LabelOpts: nil,
}
options := buildah.BuilderOptions{
FromImage: imageName,
SignaturePolicyPath: signaturePolicyPath,
CommonBuildOpts: commonOpts,
}
b, err := buildah.NewBuilder(store, options)

View File

@ -56,7 +56,7 @@ var (
Name: "from",
Usage: "Create a working container based on an image",
Description: fromDescription,
Flags: fromFlags,
Flags: append(fromFlags, fromAndBudFlags...),
Action: fromCmd,
ArgsUsage: "IMAGE",
}
@ -94,6 +94,11 @@ func fromCmd(c *cli.Context) error {
return err
}
commonOpts, err := parseCommonBuildOptions(c)
if err != nil {
return err
}
options := buildah.BuilderOptions{
FromImage: args[0],
Container: c.String("name"),
@ -101,7 +106,9 @@ func fromCmd(c *cli.Context) error {
SignaturePolicyPath: signaturePolicy,
SystemContext: systemContext,
DefaultMountsFilePath: c.GlobalString("default-mounts-file"),
CommonBuildOpts: commonOpts,
}
if !c.Bool("quiet") {
options.ReportWriter = os.Stderr
}

View File

@ -352,20 +352,31 @@ return 1
"
local options_with_args="
--add-host
--authfile
--build-arg
--cert-dir
--cgroup-parent
--cpu-period
--cpu-quota
--cpu-shares
--cpuset-cpus
--cpuset-mems
--creds
-f
--file
--format
--label
-m
--memory
--memory-swap
--runtime
--runtime-flag
--security-opt
--signature-policy
-t
--tag
--ulimit
"
local all_options="$options_with_args $boolean_options"
@ -646,11 +657,23 @@ return 1
"
local options_with_args="
--add-host
--authfile
--cert-dir
--cgroup-parent
--cpu-period
--cpu-quota
--cpu-shares
--cpuset-cpus
--cpuset-mems
--creds
-m
--memory
--memory-swap
--name
--signature-policy
--security-opt
--ulimit
"

View File

@ -42,6 +42,7 @@ BuildRequires: gpgme-devel
BuildRequires: device-mapper-devel
BuildRequires: btrfs-progs-devel
BuildRequires: libassuan-devel
BuildRequires: libseccomp-devel
BuildRequires: glib2-devel
BuildRequires: ostree-devel
BuildRequires: make

View File

@ -13,6 +13,13 @@ build context directory. The build context directory can be specified as the
to a temporary location.
## OPTIONS
**--add-host**=[]
Add a custom host-to-IP mapping (host:ip)
Add a line to /etc/hosts. The format is hostname:ip. The **--add-host** option can be set multiple times.
**--authfile** *path*
Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
@ -30,6 +37,73 @@ resulting image's configuration.
Use certificates at *path* (*.crt, *.cert, *.key) to connect to the registry.
Default certificates directory is _/etc/containers/certs.d_.
**--cgroup-parent**=""
Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
**--cpu-period**=*0*
Limit the CPU CFS (Completely Fair Scheduler) period
Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
**--cpu-quota**=*0*
Limit the CPU CFS (Completely Fair Scheduler) quota
Limit the container's CPU usage. By default, containers run with the full
CPU resource. This flag tell the kernel to restrict the container's CPU usage
to the quota you specify.
**--cpu-shares**=*0*
CPU shares (relative weight)
By default, all containers get the same proportion of CPU cycles. This proportion
can be modified by changing the container's CPU share weighting relative
to the weighting of all other running containers.
To modify the proportion from the default of 1024, use the **--cpu-shares**
flag to set the weighting to 2 or higher.
The proportion will only apply when CPU-intensive processes are running.
When tasks in one container are idle, other containers can use the
left-over CPU time. The actual amount of CPU time will vary depending on
the number of containers running on the system.
For example, consider three containers, one has a cpu-share of 1024 and
two others have a cpu-share setting of 512. When processes in all three
containers attempt to use 100% of CPU, the first container would receive
50% of the total CPU time. If you add a fourth container with a cpu-share
of 1024, the first container only gets 33% of the CPU. The remaining containers
receive 16.5%, 16.5% and 33% of the CPU.
On a multi-core system, the shares of CPU time are distributed over all CPU
cores. Even if a container is limited to less than 100% of CPU time, it can
use 100% of each individual CPU core.
For example, consider a system with more than three cores. If you start one
container **{C0}** with **-c=512** running one process, and another container
**{C1}** with **-c=1024** running two processes, this can result in the following
division of CPU shares:
PID container CPU CPU share
100 {C0} 0 100% of CPU0
101 {C1} 1 100% of CPU1
102 {C1} 2 100% of CPU2
**--cpuset-cpus**=""
CPUs in which to allow execution (0-3, 0,1)
**--cpuset-mems**=""
Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
If you have four memory nodes on your system (0-3), use `--cpuset-mems=0,1`
then processes in your container will only use memory from the first
two memory nodes.
**--creds** *creds*
The [username[:password]] to use to authenticate with the registry if required.
@ -53,6 +127,27 @@ Control the format for the built image's manifest and configuration data.
Recognized formats include *oci* (OCI image-spec v1.0, the default) and
*docker* (version 2, using schema format 2 for the manifest).
**-m**, **--memory**=""
Memory limit (format: <number>[<unit>], where unit = b, k, m or g)
Allows you to constrain the memory available to a container. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
RAM. If a limit of 0 is specified (not using **-m**), the container's memory is
not limited. The actual limit may be rounded up to a multiple of the operating
system's page size (the value would be very large, that's millions of trillions).
**--memory-swap**="LIMIT"
A limit value equal to memory plus swap. Must be used with the **-m**
(**--memory**) flag. The swap `LIMIT` should always be larger than **-m**
(**--memory**) value. By default, the swap `LIMIT` will be set to double
the value of --memory.
The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes),
`k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
**--pull**
Pull the image if it is not present. If this flag is disabled (with
@ -82,6 +177,23 @@ runtime, the manpage to consult is `runc(8)`).
Note: Do not pass the leading `--` to the flag. To pass the runc flag `--log-format json`
to buildah bud, the option given would be `--runtime-flag log-format=json`.
**--security-opt**=[]
Security Options
"label=user:USER" : Set the label user for the container
"label=role:ROLE" : Set the label role for the container
"label=type:TYPE" : Set the label type for the container
"label=level:LEVEL" : Set the label level for the container
"label=disable" : Turn off label confinement for the container
"no-new-privileges" : Not supported
"seccomp=unconfined" : Turn off seccomp confinement for the container
"seccomp=profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
"apparmor=unconfined" : Turn off apparmor confinement for the container
"apparmor=your-profile" : Set the apparmor confinement profile for the container
**--signature-policy** *signaturepolicy*
Pathname of a signature policy file to use. It is not recommended that this
@ -97,6 +209,10 @@ process completes successfully.
Require HTTPS and verify certificates when talking to container registries (defaults to true).
**--ulimit**=[]
Ulimit options
## EXAMPLE
buildah bud .
@ -117,5 +233,9 @@ buildah bud --runtime-flag debug .
buildah bud --authfile /tmp/auths/myauths.json --cert-dir ~/auth --tls-verify=true --creds=username:password -t imageName -f Dockerfile.simple
buildah bud --memory 40m --cpu-period 10000 --cpu-quota 50000 --ulimit nofile=1024:1028 -t imageName .
buildah bud --security-opt label=level:s0:c100,c200 --cgroup-parent /path/to/cgroup/parent -t imageName .
## SEE ALSO
buildah(1), podman-login(1), docker-login(1)

View File

@ -36,6 +36,12 @@ The container ID of the container that was created. On error, -1 is returned an
## OPTIONS
**--add-host**=[]
Add a custom host-to-IP mapping (host:ip)
Add a line to /etc/hosts. The format is hostname:ip. The **--add-host** option can be set multiple times.
**--authfile** *path*
Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`.
@ -46,12 +52,100 @@ If the authorization state is not found there, $HOME/.docker/config.json is chec
Use certificates at *path* (*.crt, *.cert, *.key) to connect to the registry.
Default certificates directory is _/etc/containers/certs.d_.
**--cgroup-parent**=""
Path to cgroups under which the cgroup for the container will be created. If the path is not absolute, the path is considered to be relative to the cgroups path of the init process. Cgroups will be created if they do not already exist.
**--cpu-period**=*0*
Limit the CPU CFS (Completely Fair Scheduler) period
Limit the container's CPU usage. This flag tell the kernel to restrict the container's CPU usage to the period you specify.
**--cpu-quota**=*0*
Limit the CPU CFS (Completely Fair Scheduler) quota
Limit the container's CPU usage. By default, containers run with the full
CPU resource. This flag tell the kernel to restrict the container's CPU usage
to the quota you specify.
**--cpu-shares**=*0*
CPU shares (relative weight)
By default, all containers get the same proportion of CPU cycles. This proportion
can be modified by changing the container's CPU share weighting relative
to the weighting of all other running containers.
To modify the proportion from the default of 1024, use the **--cpu-shares**
flag to set the weighting to 2 or higher.
The proportion will only apply when CPU-intensive processes are running.
When tasks in one container are idle, other containers can use the
left-over CPU time. The actual amount of CPU time will vary depending on
the number of containers running on the system.
For example, consider three containers, one has a cpu-share of 1024 and
two others have a cpu-share setting of 512. When processes in all three
containers attempt to use 100% of CPU, the first container would receive
50% of the total CPU time. If you add a fourth container with a cpu-share
of 1024, the first container only gets 33% of the CPU. The remaining containers
receive 16.5%, 16.5% and 33% of the CPU.
On a multi-core system, the shares of CPU time are distributed over all CPU
cores. Even if a container is limited to less than 100% of CPU time, it can
use 100% of each individual CPU core.
For example, consider a system with more than three cores. If you start one
container **{C0}** with **-c=512** running one process, and another container
**{C1}** with **-c=1024** running two processes, this can result in the following
division of CPU shares:
PID container CPU CPU share
100 {C0} 0 100% of CPU0
101 {C1} 1 100% of CPU1
102 {C1} 2 100% of CPU2
**--cpuset-cpus**=""
CPUs in which to allow execution (0-3, 0,1)
**--cpuset-mems**=""
Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
If you have four memory nodes on your system (0-3), use `--cpuset-mems=0,1`
then processes in your container will only use memory from the first
two memory nodes.
**--creds** *creds*
The [username[:password]] to use to authenticate with the registry if required.
If one or both values are not supplied, a command line prompt will appear and the
value can be entered. The password is entered without echo.
**-m**, **--memory**=""
Memory limit (format: <number>[<unit>], where unit = b, k, m or g)
Allows you to constrain the memory available to a container. If the host
supports swap memory, then the **-m** memory setting can be larger than physical
RAM. If a limit of 0 is specified (not using **-m**), the container's memory is
not limited. The actual limit may be rounded up to a multiple of the operating
system's page size (the value would be very large, that's millions of trillions).
**--memory-swap**="LIMIT"
A limit value equal to memory plus swap. Must be used with the **-m**
(**--memory**) flag. The swap `LIMIT` should always be larger than **-m**
(**--memory**) value. By default, the swap `LIMIT` will be set to double
the value of --memory.
The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes),
`k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
**--name** *name*
A *name* for the working container
@ -70,6 +164,23 @@ Pull the image even if a version of the image is already present.
If an image needs to be pulled from the registry, suppress progress output.
**--security-opt**=[]
Security Options
"label=user:USER" : Set the label user for the container
"label=role:ROLE" : Set the label role for the container
"label=type:TYPE" : Set the label type for the container
"label=level:LEVEL" : Set the label level for the container
"label=disable" : Turn off label confinement for the container
"no-new-privileges" : Not supported
"seccomp=unconfined" : Turn off seccomp confinement for the container
"seccomp=profile.json : White listed syscalls seccomp Json file to be used as a seccomp filter
"apparmor=unconfined" : Turn off apparmor confinement for the container
"apparmor=your-profile" : Set the apparmor confinement profile for the container
**--signature-policy** *signaturepolicy*
Pathname of a signature policy file to use. It is not recommended that this
@ -80,6 +191,10 @@ option be used, as the default behavior of using the system-wide default policy
Require HTTPS and verify certificates when talking to container registries (defaults to true)
**--ulimit**=[]
Ulimit options
## EXAMPLE
buildah from imagename --pull
@ -96,5 +211,9 @@ buildah from myregistry/myrepository/imagename:imagetag --creds=myusername:mypas
buildah from myregistry/myrepository/imagename:imagetag --authfile=/tmp/auths/myauths.json
buildah from --memory 40m --cpu-shares 2 --cpuset-cpus 0,2 --security-opt label=level:s0:c100,c200 myregistry/myrepository/imagename:imagetag
buildah from --ulimit nofile=1024:1028 --cgroup-parent /path/to/cgroup/parent myregistry/myrepository/imagename:imagetag
## SEE ALSO
buildah(1), podman-login(1), docker-login(1)

View File

@ -104,7 +104,8 @@ type BuildOptions struct {
// Accepted values are OCIv1ImageFormat and Dockerv2ImageFormat.
OutputFormat string
// SystemContext holds parameters used for authentication.
SystemContext *types.SystemContext
SystemContext *types.SystemContext
CommonBuildOpts *buildah.CommonBuildOptions
}
// Executor is a buildah-based implementation of the imagebuilder.Executor
@ -136,6 +137,7 @@ type Executor struct {
volumeCache map[string]string
volumeCacheInfo map[string]os.FileInfo
reportWriter io.Writer
commonBuildOptions *buildah.CommonBuildOptions
}
// Preserve informs the executor that from this point on, it needs to ensure
@ -433,6 +435,7 @@ func NewExecutor(store storage.Store, options BuildOptions) (*Executor, error) {
out: options.Out,
err: options.Err,
reportWriter: options.ReportWriter,
commonBuildOptions: options.CommonBuildOpts,
}
if exec.err == nil {
exec.err = os.Stderr
@ -475,6 +478,7 @@ func (b *Executor) Prepare(ib *imagebuilder.Builder, node *parser.Node, from str
SignaturePolicyPath: b.signaturePolicyPath,
ReportWriter: b.reportWriter,
SystemContext: b.systemContext,
CommonBuildOpts: b.commonBuildOptions,
}
builder, err := buildah.NewBuilder(b.store, builderOptions)
if err != nil {

3
new.go
View File

@ -269,7 +269,7 @@ func newBuilder(store storage.Store, options BuilderOptions) (*Builder, error) {
if err = reserveSELinuxLabels(store, container.ID); err != nil {
return nil, err
}
processLabel, mountLabel, err := label.InitLabels(nil)
processLabel, mountLabel, err := label.InitLabels(options.CommonBuildOpts.LabelOpts)
if err != nil {
return nil, err
}
@ -288,6 +288,7 @@ func newBuilder(store storage.Store, options BuilderOptions) (*Builder, error) {
ProcessLabel: processLabel,
MountLabel: mountLabel,
DefaultMountsFilePath: options.DefaultMountsFilePath,
CommonBuildOpts: options.CommonBuildOpts,
}
if options.Mount {

111
run.go
View File

@ -1,7 +1,9 @@
package buildah
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
@ -9,6 +11,8 @@ import (
"strings"
"github.com/containers/storage/pkg/ioutils"
"github.com/docker/docker/profiles/seccomp"
units "github.com/docker/go-units"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
@ -69,6 +73,76 @@ type RunOptions struct {
Quiet bool
}
func addRlimits(ulimit []string, g *generate.Generator) error {
var (
ul *units.Ulimit
err error
)
for _, u := range ulimit {
if ul, err = units.ParseUlimit(u); err != nil {
return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u)
}
g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Hard), uint64(ul.Soft))
}
return nil
}
func addHostsToFile(hosts []string) error {
file, err := os.OpenFile("/etc/hosts", os.O_APPEND|os.O_WRONLY, os.ModeAppend)
if err != nil {
return err
}
defer file.Close()
w := bufio.NewWriter(file)
for _, host := range hosts {
fmt.Fprintln(w, host)
}
return w.Flush()
}
func addCommonOptsToSpec(commonOpts *CommonBuildOptions, g *generate.Generator) error {
// RESOURCES - CPU
if commonOpts.CPUPeriod != 0 {
g.SetLinuxResourcesCPUPeriod(commonOpts.CPUPeriod)
}
if commonOpts.CPUQuota != 0 {
g.SetLinuxResourcesCPUQuota(commonOpts.CPUQuota)
}
if commonOpts.CPUShares != 0 {
g.SetLinuxResourcesCPUShares(commonOpts.CPUShares)
}
if commonOpts.CPUSetCPUs != "" {
g.SetLinuxResourcesCPUCpus(commonOpts.CPUSetCPUs)
}
if commonOpts.CPUSetMems != "" {
g.SetLinuxResourcesCPUMems(commonOpts.CPUSetMems)
}
// RESOURCES - MEMORY
if commonOpts.Memory != 0 {
g.SetLinuxResourcesMemoryLimit(commonOpts.Memory)
}
if commonOpts.MemorySwap != 0 {
g.SetLinuxResourcesMemorySwap(commonOpts.MemorySwap)
}
if commonOpts.CgroupParent != "" {
g.SetLinuxCgroupsPath(commonOpts.CgroupParent)
}
if err := addRlimits(commonOpts.Ulimit, g); err != nil {
return err
}
if err := addHostsToFile(commonOpts.AddHost); err != nil {
return err
}
logrus.Debugln("Resources:", commonOpts)
return nil
}
func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts []specs.Mount, bindFiles, volumes []string) error {
// The passed-in mounts matter the most to us.
mounts := make([]specs.Mount, len(optionMounts))
@ -181,6 +255,11 @@ func (b *Builder) Run(command []string, options RunOptions) error {
g.AddProcessEnv(env[0], env[1])
}
}
if err := addCommonOptsToSpec(b.CommonBuildOpts, &g); err != nil {
return err
}
if len(command) > 0 {
g.SetProcessArgs(command)
} else {
@ -265,6 +344,38 @@ func (b *Builder) Run(command []string, options RunOptions) error {
return errors.Wrapf(err, "error ensuring working directory %q exists", spec.Process.Cwd)
}
//Security Opts
g.SetProcessApparmorProfile(b.CommonBuildOpts.ApparmorProfile)
// HANDLE SECCOMP
if b.CommonBuildOpts.SeccompProfilePath != "unconfined" {
if b.CommonBuildOpts.SeccompProfilePath != "" {
seccompProfile, err := ioutil.ReadFile(b.CommonBuildOpts.SeccompProfilePath)
if err != nil {
return errors.Wrapf(err, "opening seccomp profile (%s) failed", b.CommonBuildOpts.SeccompProfilePath)
}
seccompConfig, err := seccomp.LoadProfile(string(seccompProfile), spec)
if err != nil {
return errors.Wrapf(err, "loading seccomp profile (%s) failed", b.CommonBuildOpts.SeccompProfilePath)
}
spec.Linux.Seccomp = seccompConfig
} else {
seccompConfig, err := seccomp.GetDefaultProfile(spec)
if err != nil {
return errors.Wrapf(err, "loading seccomp profile (%s) failed", b.CommonBuildOpts.SeccompProfilePath)
}
spec.Linux.Seccomp = seccompConfig
}
}
cgroupMnt := specs.Mount{
Destination: "/sys/fs/cgroup",
Type: "cgroup",
Source: "cgroup",
Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"},
}
g.AddMount(cgroupMnt)
bindFiles := []string{"/etc/hosts", "/etc/resolv.conf"}
err = b.setupMounts(mountPoint, spec, options.Mounts, bindFiles, b.Volumes())
if err != nil {

View File

@ -128,3 +128,57 @@ load helpers
buildah rm ${cid}
buildah rmi alpine alpine2
}
@test "from cpu-period test" {
cid=$(buildah from --cpu-period=5000 --pull --signature-policy ${TESTSDIR}/policy.json alpine)
run buildah run $cid cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
echo $output
[ "$status" -eq 0 ]
[[ "$output" =~ "5000" ]]
buildah rm $cid
}
@test "from cpu-quota test" {
cid=$(buildah from --cpu-quota=5000 --pull --signature-policy ${TESTSDIR}/policy.json alpine)
run buildah run $cid cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
echo "$output"
[ "$status" -eq 0 ]
[[ "$output" =~ 5000 ]]
buildah rm $cid
}
@test "from cpu-shares test" {
cid=$(buildah from --cpu-shares=2 --pull --signature-policy ${TESTSDIR}/policy.json alpine)
run buildah run $cid cat /sys/fs/cgroup/cpu/cpu.shares
echo "$output"
[ "$status" -eq 0 ]
[[ "$output" =~ 2 ]]
buildah rm $cid
}
@test "from cpuset-cpus test" {
cid=$(buildah from --cpuset-cpus=0 --pull --signature-policy ${TESTSDIR}/policy.json alpine)
run buildah run $cid cat /sys/fs/cgroup/cpuset/cpuset.cpus
echo "$output"
[ "$status" -eq 0 ]
[[ "$output" =~ 0 ]]
buildah rm $cid
}
@test "from cpuset-mems test" {
cid=$(buildah from --cpuset-mems=0 --pull --signature-policy ${TESTSDIR}/policy.json alpine)
run buildah run $cid cat /sys/fs/cgroup/cpuset/cpuset.mems
echo "$output"
[ "$status" -eq 0 ]
[[ "$output" =~ 0 ]]
buildah rm $cid
}
@test "from memory test" {
cid=$(buildah from --memory=40m --pull --signature-policy ${TESTSDIR}/policy.json alpine)
run buildah run $cid cat /sys/fs/cgroup/memory/memory.limit_in_bytes
echo $output
[ "$status" -eq 0 ]
[[ "$output" =~ 41943040 ]]
buildah rm $cid
}