Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions cmd/podman/containers/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ var (
execDetach bool
execCidFile string
execNoSession bool
// Resource limit CLI variables
execCPUs string
execMemory string
execCPUShares uint64
execCPUSetCPUs string
execCPUSetMems string
execMemorySwap string
)

func execFlags(cmd *cobra.Command) {
Expand Down Expand Up @@ -108,6 +115,31 @@ func execFlags(cmd *cobra.Command) {
if registry.IsRemote() {
_ = flags.MarkHidden("preserve-fds")
}

// Resource limit flags
cpusFlagName := "cpus"
flags.StringVar(&execCPUs, cpusFlagName, "", "Number of CPUs for the exec session")
_ = cmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone)

memoryFlagName := "memory"
flags.StringVarP(&execMemory, memoryFlagName, "m", "", "Memory limit for the exec session (format: <number>[<unit>], where unit = b, k, m or g)")
_ = cmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)

cpuSharesFlagName := "cpu-shares"
flags.Uint64Var(&execCPUShares, cpuSharesFlagName, 0, "CPU shares (relative weight) for the exec session")
_ = cmd.RegisterFlagCompletionFunc(cpuSharesFlagName, completion.AutocompleteNone)

cpusetCpusFlagName := "cpuset-cpus"
flags.StringVar(&execCPUSetCPUs, cpusetCpusFlagName, "", "CPUs in which to allow execution (0-3, 0,1)")
_ = cmd.RegisterFlagCompletionFunc(cpusetCpusFlagName, completion.AutocompleteNone)

cpusetMemsFlagName := "cpuset-mems"
flags.StringVar(&execCPUSetMems, cpusetMemsFlagName, "", "Memory nodes (MEMs) in which to allow execution (0-3, 0,1)")
_ = cmd.RegisterFlagCompletionFunc(cpusetMemsFlagName, completion.AutocompleteNone)

memorySwapFlagName := "memory-swap"
flags.StringVar(&execMemorySwap, memorySwapFlagName, "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap")
_ = cmd.RegisterFlagCompletionFunc(memorySwapFlagName, completion.AutocompleteNone)
}

func init() {
Expand Down Expand Up @@ -155,6 +187,14 @@ func exec(cmd *cobra.Command, args []string) error {

execOpts.Envs = envLib.Join(execOpts.Envs, cliEnv)

// Set resource limits from CLI flags
execOpts.CPUs = execCPUs
execOpts.Memory = execMemory
execOpts.CPUShares = execCPUShares
execOpts.CPUSetCPUs = execCPUSetCPUs
execOpts.CPUSetMems = execCPUSetMems
execOpts.MemorySwap = execMemorySwap

for _, fd := range execOpts.PreserveFD {
if !rootless.IsFdInherited(int(fd)) {
return fmt.Errorf("file descriptor %d is not available - the preserve-fd option requires that file descriptors must be passed", fd)
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/cpu-shares.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman build, container clone, create, farm build, pod clone, pod create, run, update
####> podman build, container clone, create, exec, farm build, pod clone, pod create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--cpu-shares**, **-c**=*shares*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/cpus.container.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run, update
####> podman create, exec, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--cpus**=*number*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/cpuset-cpus.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman build, container clone, create, farm build, pod clone, pod create, run, update
####> podman build, container clone, create, exec, farm build, pod clone, pod create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--cpuset-cpus**=*number*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/cpuset-mems.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman build, container clone, create, farm build, pod clone, pod create, run, update
####> podman build, container clone, create, exec, farm build, pod clone, pod create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--cpuset-mems**=*nodes*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/memory-swap.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman build, container clone, create, farm build, pod clone, pod create, run, update
####> podman build, container clone, create, exec, farm build, pod clone, pod create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--memory-swap**=*number[unit]*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/memory.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman build, container clone, create, farm build, pod clone, pod create, run, update
####> podman build, container clone, create, exec, farm build, pod clone, pod create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--memory**, **-m**=*number[unit]*
Expand Down
24 changes: 24 additions & 0 deletions docs/source/markdown/podman-exec.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ podman\-exec - Execute a command in a running container

Read the ID of the target container from the specified *file*.

@@option cpus.container

@@option cpu-shares

@@option cpuset-cpus

@@option cpuset-mems

#### **--detach**, **-d**

Start the exec session, but do not attach to it. The command runs in the background, and the exec session is automatically removed when it completes. The **podman exec** command prints the ID of the exec session and exits immediately after it starts.
Expand All @@ -31,6 +39,10 @@ Start the exec session, but do not attach to it. The command runs in the backgro

@@option latest

@@option memory

@@option memory-swap

@@option no-session

@@option preserve-fd
Expand Down Expand Up @@ -95,6 +107,18 @@ Execute command but do not attach to the exec session leaving the command runnin
$ podman exec -d ctrID find /path/to/search -name yourfile
```

Execute command with resource limits (requires crun >= 1.9 or runc >= 1.2):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the OCI runtimes do not have any support for exec and cgroups limits, so this is wrong

```
$ podman exec --cpus=0.5 --memory=256m ctrID stress-ng --vm 1 --vm-bytes 200M
```

## NOTES

Resource limit options (--cpus, --memory, --cpu-shares, --cpuset-cpus,
--cpuset-mems, --memory-swap) require OCI runtime support. These options
create a temporary sub-cgroup for the exec session with the specified
resource limits. Supported by crun >= 1.9 and runc >= 1.2.

## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-run(1)](podman-run.1.md)**

Expand Down
13 changes: 13 additions & 0 deletions libpod/container_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/containers/podman/v6/libpod/define"
"github.com/containers/podman/v6/libpod/events"
"github.com/containers/podman/v6/pkg/pidhandle"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"go.podman.io/common/pkg/resize"
"go.podman.io/common/pkg/util"
Expand Down Expand Up @@ -80,6 +81,12 @@ type ExecConfig struct {
// exiting, and the exit command being executed. If set to 0, there is
// no delay. If set, ExitCommand must also be set.
ExitCommandDelay uint `json:"exitCommandDelay,omitempty"`
// CgroupPath is a relative path to a sub-cgroup to create for the exec session.
// If empty, no cgroup will be created. The path is relative to the container's cgroup.
CgroupPath string `json:"cgroupPath,omitempty"`
// Resources are the resource limits to apply to the exec session's cgroup.
// Only used if CgroupPath is set.
Resources *spec.LinuxResources `json:"resources,omitempty"`
}

// ExecSession contains information on a single exec session attached to a given
Expand Down Expand Up @@ -1188,6 +1195,12 @@ func prepareForExec(c *Container, session *ExecSession) (*ExecOptions, error) {
opts.ExitCommandDelay = session.Config.ExitCommandDelay
opts.Privileged = session.Config.Privileged

// Set resource limits and cgroup path for exec session
if session.Config.CgroupPath != "" && session.Config.Resources != nil {
opts.CgroupPath = session.Config.CgroupPath
opts.Resources = session.Config.Resources
}

return opts, nil
}

Expand Down
10 changes: 8 additions & 2 deletions libpod/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http"

"github.com/containers/podman/v6/libpod/define"
"github.com/opencontainers/runtime-spec/specs-go"
spec "github.com/opencontainers/runtime-spec/specs-go"
"go.podman.io/common/pkg/resize"
)

Expand Down Expand Up @@ -165,7 +165,7 @@ type OCIRuntime interface { //nolint:interfacebloat
RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error)

// UpdateContainer updates the given container's cgroup configuration.
UpdateContainer(ctr *Container, res *specs.LinuxResources) error
UpdateContainer(ctr *Container, res *spec.LinuxResources) error
}

// AttachOptions are options used when attached to a container or an exec
Expand Down Expand Up @@ -230,6 +230,12 @@ type ExecOptions struct {
ExitCommandDelay uint
// Privileged indicates the execed process will be launched in Privileged mode
Privileged bool
// CgroupPath is the path to a sub-cgroup to create for the exec session.
// If empty, no cgroup will be created.
CgroupPath string
// Resources are the resource limits to apply to the exec session's cgroup.
// Only used if CgroupPath is set.
Resources *spec.LinuxResources
}

// HTTPAttachStreams informs the HTTPAttach endpoint which of the container's
Expand Down
9 changes: 9 additions & 0 deletions libpod/oci_conmon_exec_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,15 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
args = append(args, "--exec-attach")
args = append(args, "--exec-process-spec", processFile.Name())

// If a cgroup path is specified for resource limits, pass it to the runtime.
// The value of options.CgroupPath is interpreted as relative to the
// container's existing cgroup, not as an absolute cgroup path. The OCI
// runtime is expected to resolve this by joining the provided value with
// the container's cgroup path in the cgroup hierarchy.
if options.CgroupPath != "" && options.Resources != nil {
args = append(args, "--cgroup", options.CgroupPath)
}

if len(options.ExitCommand) > 0 {
args = append(args, "--exit-command", options.ExitCommand[0])
for _, arg := range options.ExitCommand[1:] {
Expand Down
7 changes: 7 additions & 0 deletions pkg/domain/entities/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,13 @@ type ExecOptions struct {
Tty bool
User string
WorkDir string
// Resource limits for the exec session
CPUs string // Number of CPUs (e.g., "0.5", "2")
Memory string // Memory limit (e.g., "256m", "1g")
CPUShares uint64 // CPU shares (relative weight)
CPUSetCPUs string // CPUs in which to allow execution (0-3, 0,1)
CPUSetMems string // Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
MemorySwap string // Total memory (memory + swap)
}

// ContainerExistsOptions describes the cli values to check if a container exists
Expand Down
Loading