mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Merge branch 'main' of github.com:containers/podman into man
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -99,8 +99,7 @@ jobs:
|
||||
update_release: false
|
||||
packages: [podman-fedora]
|
||||
dist_git_branches:
|
||||
- fedora-development
|
||||
- fedora-latest
|
||||
- fedora-all
|
||||
|
||||
- job: propose_downstream
|
||||
trigger: release
|
||||
|
@ -211,6 +211,11 @@ func run(cmd *cobra.Command, args []string) error {
|
||||
s.ImageArch = cliVals.Arch
|
||||
s.ImageVariant = cliVals.Variant
|
||||
s.Passwd = &runOpts.Passwd
|
||||
|
||||
if runRmi {
|
||||
s.RemoveImage = &runRmi
|
||||
}
|
||||
|
||||
runOpts.Spec = s
|
||||
|
||||
if err := createPodIfNecessary(cmd, s, cliVals.Net); err != nil {
|
||||
|
@ -82,13 +82,14 @@ 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|pod>> can use a private
|
||||
volume. Note: all containers within a `pod` share the same SELinux label. This
|
||||
means all containers within said pod can read/write volumes create with the
|
||||
`:Z`. Relabeling walks the file system under the volume and changes the label
|
||||
on each file, if the volume has thousands of inodes, this process takes a
|
||||
long time, delaying the start of the <<container|pod>>. If the volume
|
||||
was previously relabeled with the `z` option, Podman is optimized to not relabel
|
||||
a second time. If files are moved into the volume, then the labels can be
|
||||
manually change with the `chcon -Rt container_file_t PATH` command.
|
||||
means all containers within said pod can read/write volumes shared into the
|
||||
container created with the `:Z` on any of one the containers. Relabeling walks
|
||||
the file system under the volume and changes the label on each file, if the
|
||||
volume has thousands of inodes, this process takes a long time, delaying the
|
||||
start of the <<container|pod>>. If the volume was previously relabeled with the
|
||||
`z` option, Podman is optimized to not relabel a second time. If files are
|
||||
moved into the volume, then the labels can be manually change with the
|
||||
`chcon -Rt container_file_t PATH` command.
|
||||
|
||||
Note: Do not relabel system files and directories. Relabeling system content
|
||||
might cause other confined services on the machine to fail. For these types
|
||||
|
@ -259,6 +259,7 @@ Valid options for `[Container]` are listed below:
|
||||
| AddDevice=/dev/foo | --device /dev/foo |
|
||||
| Annotation="XYZ" | --annotation "XYZ" |
|
||||
| AutoUpdate=registry | --label "io.containers.autoupdate=registry" |
|
||||
| CgroupsMode=no-conmon | --cgroups=no-conmon |
|
||||
| ContainerName=name | --name name |
|
||||
| ContainersConfModule=/etc/nvd\.conf | --module=/etc/nvd\.conf |
|
||||
| DNS=192.168.55.1 | --dns=192.168.55.1 |
|
||||
@ -370,6 +371,16 @@ Indicates whether the container will be auto-updated ([podman-auto-update(1)](po
|
||||
|
||||
* `local`: Tells Podman to compare the image a container is using to the image with its raw name in local storage. If an image is updated locally, Podman simply restarts the systemd unit executing the container.
|
||||
|
||||
### `CgroupsMode=`
|
||||
|
||||
The cgroups mode of the Podman container. Equivalent to the Podman `--cgroups` option.
|
||||
|
||||
By default, the cgroups mode of the container created by Quadlet is `split`,
|
||||
which differs from the default (`enabled`) used by the Podman CLI.
|
||||
|
||||
If the container joins a pod (i.e. `Pod=` is specified), you may want to change this to
|
||||
`no-conmon` or `enabled` so that pod level cgroup resource limits can take effect.
|
||||
|
||||
### `ContainerName=`
|
||||
|
||||
The (optional) name of the Podman container. If this is not specified, the default value
|
||||
|
@ -1261,6 +1261,17 @@ func (c *Container) AutoRemove() bool {
|
||||
return spec.Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue
|
||||
}
|
||||
|
||||
// AutoRemoveImage indicates that the container will automatically remove the
|
||||
// image it is using after it exits and is removed.
|
||||
// Only allowed if AutoRemove is true.
|
||||
func (c *Container) AutoRemoveImage() bool {
|
||||
spec := c.config.Spec
|
||||
if spec.Annotations == nil {
|
||||
return false
|
||||
}
|
||||
return spec.Annotations[define.InspectAnnotationAutoremoveImage] == define.InspectResponseTrue
|
||||
}
|
||||
|
||||
// Timezone returns the timezone configured inside the container.
|
||||
// Local means it has the same timezone as the host machine
|
||||
func (c *Container) Timezone() string {
|
||||
|
@ -517,6 +517,9 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
|
||||
if ctrSpec.Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue {
|
||||
hostConfig.AutoRemove = true
|
||||
}
|
||||
if ctrSpec.Annotations[define.InspectAnnotationAutoremoveImage] == define.InspectResponseTrue {
|
||||
hostConfig.AutoRemoveImage = true
|
||||
}
|
||||
if ctrs, ok := ctrSpec.Annotations[define.VolumesFromAnnotation]; ok {
|
||||
hostConfig.VolumesFrom = strings.Split(ctrs, ";")
|
||||
}
|
||||
|
@ -158,6 +158,18 @@ func (c *Container) validate() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Autoremoving image requires autoremoving the associated container
|
||||
if c.config.Spec.Annotations != nil {
|
||||
if c.config.Spec.Annotations[define.InspectAnnotationAutoremoveImage] == define.InspectResponseTrue {
|
||||
if c.config.Spec.Annotations[define.InspectAnnotationAutoremove] != define.InspectResponseTrue {
|
||||
return fmt.Errorf("autoremoving image requires autoremoving the container: %w", define.ErrInvalidArg)
|
||||
}
|
||||
if c.config.Rootfs != "" {
|
||||
return fmt.Errorf("autoremoving image is not possible when a rootfs is in use: %w", define.ErrInvalidArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot set startup HC without a healthcheck
|
||||
if c.config.HealthCheckConfig == nil && c.config.StartupHealthCheckConfig != nil {
|
||||
return fmt.Errorf("cannot set a startup healthcheck when there is no regular healthcheck: %w", define.ErrInvalidArg)
|
||||
|
@ -18,6 +18,12 @@ const (
|
||||
// the two supported boolean values (InspectResponseTrue and
|
||||
// InspectResponseFalse) it will be used in the output of Inspect().
|
||||
InspectAnnotationAutoremove = "io.podman.annotations.autoremove"
|
||||
// InspectAnnotationAutoremoveImage is used by Inspect to identify
|
||||
// containers which will automatically remove the image used by the
|
||||
// container. If an annotation with this key is found in the OCI spec and
|
||||
// is one of the two supported boolean values (InspectResponseTrue and
|
||||
// InspectResponseFalse) it will be used in the output of Inspect().
|
||||
InspectAnnotationAutoremoveImage = "io.podman.annotations.autoremove-image"
|
||||
// InspectAnnotationPrivileged is used by Inspect to identify containers
|
||||
// which are privileged (IE, running with elevated privileges).
|
||||
// It is expected to be a boolean, populated by one of
|
||||
|
@ -390,6 +390,11 @@ type InspectContainerHostConfig struct {
|
||||
// It is not handled directly within libpod and is stored in an
|
||||
// annotation.
|
||||
AutoRemove bool `json:"AutoRemove"`
|
||||
// AutoRemoveImage is whether the container's image will be
|
||||
// automatically removed on exiting.
|
||||
// It is not handled directly within libpod and is stored in an
|
||||
// annotation.
|
||||
AutoRemoveImage bool `json:"AutoRemoveImage"`
|
||||
// Annotations are provided to the runtime when the container is
|
||||
// started.
|
||||
Annotations map[string]string `json:"Annotations"`
|
||||
|
@ -1035,7 +1035,7 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
|
||||
args = append(args, "--no-pivot")
|
||||
}
|
||||
|
||||
exitCommand, err := specgenutil.CreateExitCommandArgs(ctr.runtime.storageConfig, ctr.runtime.config, ctr.runtime.syslog || logrus.IsLevelEnabled(logrus.DebugLevel), ctr.AutoRemove(), false)
|
||||
exitCommand, err := specgenutil.CreateExitCommandArgs(ctr.runtime.storageConfig, ctr.runtime.config, ctr.runtime.syslog || logrus.IsLevelEnabled(logrus.DebugLevel), ctr.AutoRemove(), ctr.AutoRemoveImage(), false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
// Automatically log to syslog if the server has log-level=debug set
|
||||
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), true, true)
|
||||
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), true, false, true)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
|
@ -36,6 +36,7 @@ import (
|
||||
"github.com/containers/podman/v5/pkg/util"
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/types"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@ -291,16 +292,36 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = c.Cleanup(ctx)
|
||||
if err != nil {
|
||||
if c.AutoRemove() {
|
||||
_, imageName := c.Image()
|
||||
|
||||
if err := ic.Libpod.RemoveContainer(ctx, c, false, true, nil); err != nil {
|
||||
// Issue #7384 and #11384: If the container is configured for
|
||||
// auto-removal, it might already have been removed at this point.
|
||||
// We still need to clean up since we do not know if the other cleanup process is successful
|
||||
if c.AutoRemove() && (errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved)) {
|
||||
if !(errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved)) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.AutoRemoveImage() {
|
||||
imageEngine := ImageEngine{Libpod: ic.Libpod}
|
||||
_, rmErrors := imageEngine.Remove(ctx, []string{imageName}, entities.ImageRemoveOptions{Ignore: true})
|
||||
if len(rmErrors) > 0 {
|
||||
mErr := multierror.Append(nil, rmErrors...)
|
||||
return fmt.Errorf("removing container %s image %s: %w", c.ID(), imageName, mErr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err = c.Cleanup(ctx); err != nil {
|
||||
// The container could still have been removed, as we unlocked
|
||||
// after we stopped it.
|
||||
if errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@ -827,7 +848,7 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.E
|
||||
return nil, fmt.Errorf("retrieving Libpod configuration to build exec exit command: %w", err)
|
||||
}
|
||||
// TODO: Add some ability to toggle syslog
|
||||
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, true)
|
||||
exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, false, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("constructing exit command for exec session: %w", err)
|
||||
}
|
||||
|
@ -83,7 +83,9 @@ func (vf *Helper) stateChange(newState rest.StateChange) error {
|
||||
}
|
||||
payload := bytes.NewReader(b)
|
||||
serverResponse, err := vf.post(vf.Endpoint+state, payload)
|
||||
if err == nil {
|
||||
_ = serverResponse.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -318,6 +318,10 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
|
||||
configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
|
||||
}
|
||||
|
||||
if s.RemoveImage != nil && *s.RemoveImage {
|
||||
configSpec.Annotations[define.InspectAnnotationAutoremoveImage] = define.InspectResponseTrue
|
||||
}
|
||||
|
||||
if len(s.VolumesFrom) > 0 {
|
||||
configSpec.Annotations[define.VolumesFromAnnotation] = strings.Join(s.VolumesFrom, ";")
|
||||
}
|
||||
|
@ -159,6 +159,12 @@ type ContainerBasicConfig struct {
|
||||
// and exits.
|
||||
// Optional.
|
||||
Remove *bool `json:"remove,omitempty"`
|
||||
// RemoveImage indicates that the container should remove the image it
|
||||
// was created from after it exits.
|
||||
// Only allowed if Remove is set to true and Image, not Rootfs, is in
|
||||
// use.
|
||||
// Optional.
|
||||
RemoveImage *bool `json:"removeImage,omitempty"`
|
||||
// ContainerCreateCommand is the command that was used to create this
|
||||
// container.
|
||||
// This will be shown in the output of Inspect() on the container, and
|
||||
|
@ -261,7 +261,7 @@ func parseAndValidatePort(port string) (uint16, error) {
|
||||
return uint16(num), nil
|
||||
}
|
||||
|
||||
func CreateExitCommandArgs(storageConfig storageTypes.StoreOptions, config *config.Config, syslog, rm, exec bool) ([]string, error) {
|
||||
func CreateExitCommandArgs(storageConfig storageTypes.StoreOptions, config *config.Config, syslog, rm, rmi, exec bool) ([]string, error) {
|
||||
// We need a cleanup process for containers in the current model.
|
||||
// But we can't assume that the caller is Podman - it could be another
|
||||
// user of the API.
|
||||
@ -317,6 +317,10 @@ func CreateExitCommandArgs(storageConfig storageTypes.StoreOptions, config *conf
|
||||
command = append(command, "--rm")
|
||||
}
|
||||
|
||||
if rmi {
|
||||
command = append(command, "--rmi")
|
||||
}
|
||||
|
||||
// This has to be absolutely last, to ensure that the exec session ID
|
||||
// will be added after it by Libpod.
|
||||
if exec {
|
||||
|
@ -62,6 +62,7 @@ const (
|
||||
KeyAuthFile = "AuthFile"
|
||||
KeyAutoUpdate = "AutoUpdate"
|
||||
KeyCertDir = "CertDir"
|
||||
KeyCgroupsMode = "CgroupsMode"
|
||||
KeyConfigMap = "ConfigMap"
|
||||
KeyContainerName = "ContainerName"
|
||||
KeyContainersConfModule = "ContainersConfModule"
|
||||
@ -191,6 +192,7 @@ var (
|
||||
KeyAddDevice: true,
|
||||
KeyAnnotation: true,
|
||||
KeyAutoUpdate: true,
|
||||
KeyCgroupsMode: true,
|
||||
KeyContainerName: true,
|
||||
KeyContainersConfModule: true,
|
||||
KeyDNS: true,
|
||||
@ -581,7 +583,12 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[
|
||||
|
||||
// We delegate groups to the runtime
|
||||
service.Add(ServiceGroup, "Delegate", "yes")
|
||||
|
||||
if cgroupsMode, ok := container.Lookup(ContainerGroup, KeyCgroupsMode); ok && len(cgroupsMode) > 0 {
|
||||
podman.addf("--cgroups=%s", cgroupsMode)
|
||||
} else {
|
||||
podman.add("--cgroups=split")
|
||||
}
|
||||
|
||||
timezone, ok := container.Lookup(ContainerGroup, KeyTimezone)
|
||||
if ok && len(timezone) > 0 {
|
||||
@ -1656,6 +1663,7 @@ func ConvertPod(podUnit *parser.UnitFile, name string, unitsInfoMap map[string]*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
execStartPre.addf("--infra-name=%s-infra", podName)
|
||||
execStartPre.addf("--name=%s", podName)
|
||||
|
||||
handlePodmanArgs(podUnit, PodGroup, execStartPre)
|
||||
|
@ -1,7 +1,7 @@
|
||||
## assert-key-is Unit RequiresMountsFor "%t/containers"
|
||||
## assert-key-is Service Type forking
|
||||
## assert-key-is Service SyslogIdentifier "%N"
|
||||
## assert-key-is-regex Service ExecStartPre ".*/podman pod create --infra-conmon-pidfile=%t/%N.pid --pod-id-file=%t/%N.pod-id --exit-policy=stop --replace --name=systemd-basic"
|
||||
## assert-key-is-regex Service ExecStartPre ".*/podman pod create --infra-conmon-pidfile=%t/%N.pid --pod-id-file=%t/%N.pod-id --exit-policy=stop --replace --infra-name=systemd-basic-infra --name=systemd-basic"
|
||||
## assert-key-is-regex Service ExecStart ".*/podman pod start --pod-id-file=%t/%N.pod-id"
|
||||
## assert-key-is-regex Service ExecStop ".*/podman pod stop --pod-id-file=%t/%N.pod-id --ignore --time=10"
|
||||
## assert-key-is-regex Service ExecStopPost ".*/podman pod rm --pod-id-file=%t/%N.pod-id --ignore --force"
|
||||
|
5
test/e2e/quadlet/cgroups-mode.container
Normal file
5
test/e2e/quadlet/cgroups-mode.container
Normal file
@ -0,0 +1,5 @@
|
||||
## assert-podman-args --cgroups=no-conmon
|
||||
|
||||
[Container]
|
||||
Image=localhost/imagename
|
||||
CgroupsMode=no-conmon
|
@ -1,4 +1,5 @@
|
||||
## assert-podman-pre-args "--name=test-pod"
|
||||
## assert-podman-pre-args "--infra-name=test-pod-infra"
|
||||
|
||||
[Pod]
|
||||
PodName=test-pod
|
||||
|
@ -897,6 +897,7 @@ BOGUS=foo
|
||||
Entry("template@instance.container", "template@instance.container"),
|
||||
Entry("Unit After Override", "unit-after-override.container"),
|
||||
Entry("NetworkAlias", "network-alias.container"),
|
||||
Entry("CgroupMode", "cgroups-mode.container"),
|
||||
|
||||
Entry("basic.volume", "basic.volume"),
|
||||
Entry("device-copy.volume", "device-copy.volume"),
|
||||
|
@ -209,6 +209,27 @@ echo $rand | 0 | $rand
|
||||
|
||||
run_podman 125 run --rmi --rm=false $NONLOCAL_IMAGE /bin/true
|
||||
is "$output" "Error: the --rmi option does not work without --rm" "--rmi should refuse to remove images when --rm=false set by user"
|
||||
|
||||
# Try again with a detached container and verify it works
|
||||
cname=c_$(safename)
|
||||
run_podman run -d --name $cname --rmi $NONLOCAL_IMAGE /bin/true
|
||||
# 10 chances for the image to disappear
|
||||
for i in `seq 1 10`; do
|
||||
sleep 0.5
|
||||
run_podman '?' image exists $NONLOCAL_IMAGE
|
||||
if [[ $status == 1 ]]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
# Final check will error if image still exists
|
||||
run_podman 1 image exists $NONLOCAL_IMAGE
|
||||
|
||||
# Verify that the inspect annotation is set correctly
|
||||
run_podman run -d --name $cname --rmi $NONLOCAL_IMAGE sleep 10
|
||||
run_podman inspect --format '{{ .HostConfig.AutoRemoveImage }} {{ .HostConfig.AutoRemove }}' $cname
|
||||
is "$output" "true true" "Inspect correctly shows image autoremove and normal autoremove"
|
||||
run_podman stop -t0 $cname
|
||||
run_podman 1 image exists $NONLOCAL_IMAGE
|
||||
}
|
||||
|
||||
# 'run --conmon-pidfile --cid-file' makes sure we don't regress on these flags.
|
||||
|
Reference in New Issue
Block a user