Skip to content

Commit

Permalink
implement podman update
Browse files Browse the repository at this point in the history
podman update allows users to change the cgroup configuration of an existing container using the already defined resource limits flags
from podman create/run. The supported flags in crun are:

–memory
–cpus
–cpuset-cpus
–cpuset-mems
–memory-swap
–memory-reservation
–cpu-shares
–cpu-quota
–cpu-period
–blkio-weight
–cpu-rt-period
–cpu-rt-runtime

resolves containers#15067

Signed-off-by: Charlie Doern <cdoern@redhat.com>
  • Loading branch information
cdoern committed Aug 10, 2022
1 parent 89ab5c9 commit 37b3d5f
Show file tree
Hide file tree
Showing 19 changed files with 482 additions and 77 deletions.
109 changes: 109 additions & 0 deletions cmd/podman/containers/update.go
@@ -0,0 +1,109 @@
package containers

import (
"context"
"fmt"

"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/specgenutil"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/spf13/cobra"
)

var (
updateDescription = `Updates the cgroup configuration of a given container`

updateCommand = &cobra.Command{
Use: "update [options] CONTAINER",
Short: "update an existing container",
Long: updateDescription,
RunE: update,
Args: cobra.ExactArgs(1),
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman update --cpus=5 foobar_container`,
}

containerUpdateCommand = &cobra.Command{
Args: updateCommand.Args,
Use: updateCommand.Use,
Short: updateCommand.Short,
Long: updateCommand.Long,
RunE: updateCommand.RunE,
ValidArgsFunction: updateCommand.ValidArgsFunction,
Example: `podman container update --cpus=5 foobar_container`,
}
)
var (
updateOpts entities.ContainerCreateOptions
)

func ValidateUpdateOptions(cmd *cobra.Command, opts *entities.ContainerCreateOptions) error {
argsNotSupported := []string{
"device-read-bps",
"device-write-bps",
"device-read-iops",
"device-write-iops",
"memory-swappiness",
"blkio-weight-device",
}
for _, arg := range argsNotSupported {
if cmd.Flag(arg).Changed {
return fmt.Errorf("%s option not yet supported", arg)
}
}
return nil
}

func updateFlags(cmd *cobra.Command) {
common.DefineCreateDefaults(&updateOpts)
common.DefineCreateFlags(cmd, &updateOpts, false, false)
}

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: updateCommand,
})
updateFlags(updateCommand)

registry.Commands = append(registry.Commands, registry.CliCommand{
Command: containerUpdateCommand,
Parent: containerCmd,
})
updateFlags(containerUpdateCommand)
}

func update(cmd *cobra.Command, args []string) error {
var err error

// crun does not yet allow for all resource limits
if err = ValidateUpdateOptions(cmd, &updateOpts); err != nil {
return fmt.Errorf("%w: %s", define.ErrInvalidArg, err.Error())
}

// so here we are going to want to maybe create a new type and/or fill out a
// container resource spec. Might make sense to go specgen -->

s := &specgen.SpecGenerator{}
s.ResourceLimits = &specs.LinuxResources{}

// JUST pass the resource limits. We do not need an entire specgen.
s.ResourceLimits, err = specgenutil.GetResources(s, &updateOpts)
if err != nil {
return err
}

opts := &entities.ContainerUpdateOptions{
NameOrID: args[0],
Resources: s.ResourceLimits,
}
rep, err := registry.ContainerEngine().ContainerUpdate(context.Background(), opts)
if err != nil {
return err
}
fmt.Println(rep)
return nil
}
1 change: 1 addition & 0 deletions docs/source/markdown/.gitignore
Expand Up @@ -6,3 +6,4 @@ podman-pod-clone.1.md
podman-pod-create.1.md
podman-pull.1.md
podman-run.1.md
podman-update.1.md
9 changes: 9 additions & 0 deletions docs/source/markdown/options/cpus.md
@@ -0,0 +1,9 @@
#### **--cpus**=*number*

Number of CPUs. The default is *0.0* which means no limit. This is shorthand
for **--cpu-period** and **--cpu-quota**, so you may only set either
**--cpus** or **--cpu-period** and **--cpu-quota**.

On some systems, changing the CPU limits may not be allowed for non-root
users. For more details, see
https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error
9 changes: 9 additions & 0 deletions docs/source/markdown/options/memory-reservation.md
@@ -0,0 +1,9 @@
#### **--memory-reservation**=*limit*

Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))

After setting memory reservation, when the system detects memory contention
or low memory, containers are forced to restrict their consumption to their
reservation. So you should always set the value below **--memory**, otherwise the
hard limit will take precedence. By default, memory reservation will be the same
as memory limit.
10 changes: 10 additions & 0 deletions docs/source/markdown/options/memory-swap.md
@@ -0,0 +1,10 @@
#### **--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` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
9 changes: 9 additions & 0 deletions docs/source/markdown/options/memory.md
@@ -0,0 +1,9 @@
#### **--memory**, **-m**=*limit*

Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))

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).
47 changes: 8 additions & 39 deletions docs/source/markdown/podman-create.1.md.in
Expand Up @@ -124,21 +124,15 @@ Write the container ID to the file

@@option cpu-quota

@@option cpu-quota

@@option cpu-rt-period

@@option cpu-rt-runtime

@@option cpu-shares

#### **--cpus**=*number*

Number of CPUs. The default is *0.0* which means no limit. This is shorthand
for **--cpu-period** and **--cpu-quota**, so you may only set either
**--cpus** or **--cpu-period** and **--cpu-quota**.

On some systems, changing the CPU limits may not be allowed for non-root
users. For more details, see
https://github.com/containers/podman/blob/main/troubleshooting.md#26-running-containers-with-cpu-limits-fails-with-a-permissions-error
@@option cpus

@@option cpuset-cpus

Expand Down Expand Up @@ -365,36 +359,11 @@ This option is currently supported only by the **journald** log driver.

@@option mac-address

#### **--memory**, **-m**=*limit*

Memory limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))

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-reservation**=*limit*

Memory soft limit (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))

After setting memory reservation, when the system detects memory contention
or low memory, containers are forced to restrict their consumption to their
reservation. So you should always set the value below **--memory**, otherwise the
hard limit will take precedence. By default, memory reservation will be the same
as memory limit.

#### **--memory-swap**=*limit*
@@option memory

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.
@@option memory-reservation

The format of `LIMIT` is `<number>[<unit>]`. Unit can be `b` (bytes),
`k` (kibibytes), `m` (mebibytes), or `g` (gibibytes). If you don't specify a
unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
@@option memory-swap

@@option memory-swappiness

Expand Down Expand Up @@ -477,7 +446,7 @@ Default is to create a private PID namespace for the container

@@option pidfile

@@option pids-limit
#### **--pids-limit**=*limit*

@@option platform

Expand Down Expand Up @@ -720,7 +689,7 @@ standard input.

@@option tz

@@option uidmap.container
#### **--uidmap**=*container_uid:from_uid:amount*

@@option ulimit

Expand Down
46 changes: 46 additions & 0 deletions docs/source/markdown/podman-update.1.md.in
@@ -0,0 +1,46 @@
% podman-update(1)

## NAME
podman\-update - Updates the cgroup configuration of a given container

## SYNOPSIS
**podman update** [*options*] *container*

**podman container update** [*options*] *container*

## DESCRIPTION

Updates the cgroup configuration of an already existing container. The currently supported options are a susbet of the
podman create/run resource limits options. This command takes one argument, a container name or ID, alongside the resource flags to modify the cgroup.

## OPTIONS

@@option blkio-weight

@@option cpu-period

@@option cpu-quota

@@option cpu-rt-period

@@option cpu-rt-runtime

@@option cpu-shares

@@option cpus

@@option cpuset-cpus

@@option cpuset-mems

@@option memory

@@option memory-reservation

@@option memory-swap

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

## HISTORY
August 2022, Originally written by Charlie Doern <cdoern@redhat.com>
7 changes: 7 additions & 0 deletions libpod/container_api.go
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/signal"
"github.com/containers/storage/pkg/archive"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -98,6 +99,12 @@ func (c *Container) Start(ctx context.Context, recursive bool) error {
return c.start()
}

// Update updates the given container.
// only the cgroup config can be updated and therefore only a linux resource spec is passed.
func (c *Container) Update(res *spec.LinuxResources) error {
return c.update(res)
}

// StartAndAttach starts a container and attaches to it.
// This acts as a combination of the Start and Attach APIs, ensuring proper
// ordering of the two such that no output from the container is lost (e.g. the
Expand Down
11 changes: 11 additions & 0 deletions libpod/container_internal.go
Expand Up @@ -1211,6 +1211,7 @@ func (c *Container) start() error {
logrus.Debugf("Starting container %s with command %v", c.ID(), c.config.Spec.Process.Args)
}

// use a function like this
if err := c.ociRuntime.StartContainer(c); err != nil {
return err
}
Expand Down Expand Up @@ -2354,3 +2355,13 @@ func (c *Container) extractSecretToCtrStorage(secr *ContainerSecret) error {
}
return nil
}

// update calls the ociRuntime update function to modify a cgroup config after container creation
func (c *Container) update(resources *spec.LinuxResources) error {
// use a function like this
if err := c.ociRuntime.UpdateContainer(c, resources); err != nil {
return err
}
logrus.Debugf("updated container container %s", c.ID())
return nil
}
5 changes: 5 additions & 0 deletions libpod/oci.go
Expand Up @@ -4,6 +4,8 @@ import (
"net/http"

"github.com/containers/common/pkg/resize"
spec "github.com/opencontainers/runtime-spec/specs-go"

"github.com/containers/podman/v4/libpod/define"
)

Expand Down Expand Up @@ -148,6 +150,9 @@ type OCIRuntime interface {

// RuntimeInfo returns verbose information about the runtime.
RuntimeInfo() (*define.ConmonInfo, *define.OCIRuntimeInfo, error)

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

// AttachOptions are options used when attached to a container or an exec
Expand Down

0 comments on commit 37b3d5f

Please sign in to comment.