| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64 |
| Applies to | Linux hosts with Podman where you need to change resource limits, health probes, environment, ulimits, or restart policy on an existing container without deleting its object |
| Privilege | Rootful examples on the lab host; rootless cgroup v2 and systemd delegation caveats noted where limits fail |
| Scope | podman update for CPU, memory, swap, PIDs, cpuset, block I/O flags, health-check options, --env and --unsetenv, --ulimit, --restart, immediate versus restart behavior, cgroup v2 verification, unsupported fields, podman container clone as fallback, and update versus clone versus recreate. Does not cover full resource-limit theory, health-check probe design, Quadlet editing, or generic image update workflows. |
| Related guides | Inspect Podman containers Run containers with podman run Podman Quadlet container file |
podman update changes configuration on an existing container object. You keep the same container ID, log history, and name while adjusting resource limits, health probes, environment metadata, ulimits, or restart policy that podman run would have set at create time.
Not every field is updatable. A different image can be supplied with podman container clone, while changing published ports, bind mounts, the container command, or most namespace settings requires recreating the container with podman run or its declarative equivalent. This guide maps what works on Podman 5.8.2, what applies immediately, and what waits for the next container start.
What can podman update change?
Verified on Podman 5.8.2:
| Configuration | Update container object? | Active immediately? |
|---|---|---|
CPU quota (--cpus, --cpu-quota, --cpu-period) |
Yes | Yes — cgroup cpu.max changes while running |
Memory limits (--memory, --memory-swap) |
Yes | Yes — cgroup memory.max changes while running |
PID limit (--pids-limit) |
Yes | Yes — cgroup pids.max changes while running |
CPU affinity (--cpuset-cpus) |
Yes | Yes — cgroup cpuset.cpus changes while running |
| Block I/O weight and per-device rates | Yes | Yes — cgroup blkio fields update |
| Health-check configuration | Yes | Applies to probe scheduling on the existing container |
Restart policy (--restart) |
Yes | New policy is stored immediately and applies to subsequent container exits |
Environment (--env, --unsetenv) |
Yes | Inspect and new exec sessions see changes; PID 1 keeps old environ until restart |
Ulimits (--ulimit) |
Yes | Inspect updates immediately; PID 1 limits apply after restart |
| Image | No | Use podman container clone or recreate |
| Port mappings | No | Cannot be changed by update; clone inherits existing mappings but 5.8.2 cannot override them — recreate to change |
| Bind mounts and volumes | No | Cannot be changed by update; clone can inherit them but not redefine them — recreate to change |
| Network topology | No | Network commands or recreate depending on change |
| User namespace mode | No | Recreate |
For limit semantics and rootless delegation errors, see Set container resource limits. For probe behavior after health changes, see Podman health checks.
Lab container
Create a long-running container with starting limits and environment:
podman run -d --name upd-demo --cpus 1 --memory 256m --pids-limit 100 --env APP_MODE=old --ulimit nofile=1024:1024 registry.access.redhat.com/ubi9/ubi-minimal:latest sleep 3600The lab uses UBI minimal because Docker Hub rate limits blocked alpine:latest on this host. Any small image with a long-running command works.
Baseline inspect values:
podman inspect --format 'NanoCpus={{.HostConfig.NanoCpus}} Memory={{.HostConfig.Memory}} Pids={{.HostConfig.PidsLimit}}' upd-demoSample output:
NanoCpus=1000000000 Memory=268435456 Pids=100Update CPU limit
Lower the CPU cap without recreating the container:
podman update --cpus 0.5 upd-demoPodman prints the container ID on success. Confirm the stored quota:
podman inspect --format '{{.HostConfig.NanoCpus}}' upd-demoSample output:
500000000500000000 nanoseconds of CPU per second is 0.5 CPU. Read the cgroup file the kernel enforces:
cat "/sys/fs/cgroup$(cut -d: -f3 /proc/$(podman inspect --format '{{.State.Pid}}' upd-demo)/cgroup)/cpu.max"Sample output:
50000 100000cpu.max matching inspect proves the running container picked up the new limit immediately.
Update memory limit
Raise the memory ceiling:
podman update --memory 512m upd-demoVerify bytes in inspect:
podman inspect --format '{{.HostConfig.Memory}}' upd-demoSample output:
536870912Read memory.max from the container cgroup:
cat "/sys/fs/cgroup$(cut -d: -f3 /proc/$(podman inspect --format '{{.State.Pid}}' upd-demo)/cgroup)/memory.max"Sample output:
536870912Shrinking memory below current resident usage can fail or behave differently depending on cgroup pressure — test downward changes on disposable containers. Upward changes on an idle sleep container applied cleanly in the lab.
Update memory and swap together
Set combined memory and swap ceilings in one command:
podman update --memory 512m --memory-swap 1g upd-demoInspect stores both totals in bytes:
podman inspect --format '{{.HostConfig.Memory}} {{.HostConfig.MemorySwap}}' upd-demoSample output:
536870912 1073741824Combined swap semantics are documented in Set container resource limits — this section only confirms podman update accepts the pair on an existing container.
Update PID limit
Raise the process cap:
podman update --pids-limit 200 upd-demoConfirm in inspect and cgroup:
podman inspect --format '{{.HostConfig.PidsLimit}}' upd-demoSample output:
200The cgroup pids.max file should match:
cat "/sys/fs/cgroup$(cut -d: -f3 /proc/$(podman inspect --format '{{.State.Pid}}' upd-demo)/cgroup)/pids.max"Sample output:
200Update CPU affinity
Pin the container to one CPU:
podman update --cpuset-cpus 0 upd-demoInspect and cgroup should agree:
podman inspect --format '{{.HostConfig.CpusetCpus}}' upd-demoSample output:
0Read cpuset.cpus under the same cgroup path:
cat "/sys/fs/cgroup$(cut -d: -f3 /proc/$(podman inspect --format '{{.State.Pid}}' upd-demo)/cgroup)/cpuset.cpus"Sample output:
0On a single-NUMA host, --cpuset-mems is rarely needed. Multi-NUMA pinning follows the same inspect-and-cgroup pattern from the limits guide.
Update block I/O limits
podman update can also change block-device weights and per-device throughput or IOPS limits on an existing container.
Limit reads from a block device:
podman update --device-read-bps /dev/sda:10mb upd-demoOr change relative block I/O weight:
podman update --blkio-weight 500 upd-demoPodman 5.8.2 also supports --blkio-weight-device, --device-read-iops, --device-write-bps, and --device-write-iops on update. These options depend on the host cgroup version, controller availability, and storage/device layout. Rootless cgroup v1 does not support them. Use the resource-limits guide for block I/O semantics and controller troubleshooting.
Update health-check configuration
Start a container with a probe:
podman run -d --name upd-health --health-cmd "test -f /tmp/ok || exit 1" --health-interval 30s --health-retries 3 registry.access.redhat.com/ubi9/ubi-minimal:latest sleep 3600Tighten the interval and retries without recreating the object:
podman update --health-interval 10s --health-retries 5 upd-healthReplace the probe command:
podman update --health-cmd "test -f /tmp/ready || exit 1" upd-healthRead the persisted configuration:
podman inspect --format '{{json .Config.Healthcheck}}' upd-healthSample output:
{"Test":["CMD-SHELL","test -f /tmp/ready || exit 1"],"Interval":10000000000,"Timeout":30000000000,"Retries":5}Durations are nanoseconds in JSON (10000000000 = 10s). Scheduling and status fields are covered in Podman health checks.
Update restart policy
Change how Podman restarts the container after exit:
podman update --restart=on-failure:5 upd-demoVerify the stored policy:
podman inspect --format '{{.HostConfig.RestartPolicy.Name}} {{.HostConfig.RestartPolicy.MaximumRetryCount}}' upd-demoPodman 5.8.2 accepts no, never, on-failure[:max_retries], always, and unless-stopped. The new policy is stored on the container object immediately and applies to subsequent container exits — it does not restart a running container by itself.
If systemd or Quadlet owns the container, configure Restart= in [Service] rather than adding a competing Podman restart policy.
Add or change environment variables
Set a new value on the existing container:
podman update --env APP_MODE=new upd-demoInspect shows the updated configuration:
podman inspect --format '{{range .Config.Env}}{{println .}}{{end}}' upd-demo | grep APP_MODESample output:
APP_MODE=newA new exec session also sees the updated value:
podman exec upd-demo printenv APP_MODESample output:
newThat does not mean PID 1 picked up the change. The main process still carries the environment from its original start:
podman exec upd-demo sh -c 'tr "\0" "\n" < /proc/1/environ | grep APP_MODE'Sample output before restart:
APP_MODE=oldRestart the container so PID 1 starts with the new configuration:
podman restart upd-demoAfter restart, check PID 1 again:
podman exec upd-demo sh -c 'tr "\0" "\n" < /proc/1/environ | grep APP_MODE'Sample output:
APP_MODE=newPlan for podman restart when the application reads environment only at startup — podman update --env alone is not enough for PID 1.
Remove an environment variable
Drop a variable from the container definition:
podman update --unsetenv APP_MODE upd-demoInspect no longer lists it:
podman inspect --format '{{range .Config.Env}}{{println .}}{{end}}' upd-demo | grep APP_MODE || echo "APP_MODE not in inspect"Sample output:
APP_MODE not in inspectprintenv inside a running exec may also miss the variable, but PID 1 can still hold the old value until restart — verify with /proc/1/environ when the distinction matters for your workload.
Update ulimits
Raise the open-file limit in container configuration:
podman update --ulimit nofile=4096:4096 upd-demoInspect updates immediately:
podman inspect --format '{{json .HostConfig.Ulimits}}' upd-demoSample output (trimmed):
[{"Name":"RLIMIT_NOFILE","Soft":4096,"Hard":4096}]The running main process keeps the old limit until restart:
podman exec upd-demo sh -c 'grep "open files" /proc/1/limits'Sample output before restart:
Max open files 1024 1024 filesRestart and read again:
podman restart upd-demoAfter restart, read PID 1 limits again:
podman exec upd-demo sh -c 'grep "open files" /proc/1/limits'Sample output after restart:
Max open files 4096 4096 filesTreat ulimit changes as effective on the next main-process start, not as a live patch to PID 1.
Rootless limitations
Resource updates still require cgroup v2 controllers your user session can write. When podman update --cpus fails with cpu controller is not available, the fix is systemd delegation into the user slice — not a different update flag. See Set container resource limits for the delegation pattern; this article only notes that podman update hits the same cgroup walls as podman run.
Which fields cannot be updated?
These changes need podman container clone, a new podman run, or a Quadlet edit — not podman update:
| Field | Why |
|---|---|
| Image | No --image on podman update |
| Published ports | Cannot be changed by update; clone inherits existing mappings but 5.8.2 cannot override them — recreate to change |
| Bind mounts and volumes | Cannot be changed by update; clone can inherit them but not redefine them — recreate to change |
| Container command / entrypoint | Immutable after create |
| Hostname, user namespace, many security options | Create-time only |
Attempting unsupported flags fails clearly:
podman update --publish 8080:80 upd-demoSample error:
Error: unknown flag: --publish
See 'podman update --help'Image swaps are blocked the same way:
podman update --image alpine:latest upd-demoSample error:
Error: unknown flag: --image
See 'podman update --help'Use podman container clone for create-time fields
Clone copies an existing container into a new name and optional new image:
podman container clone upd-demo upd-cloneSyntax on Podman 5.8.2:
podman container clone [options] CONTAINER NAME [IMAGE]--name is an alternative to the positional name argument. The clone inherits limits and image from the source unless you pass a third IMAGE argument.
Clone with a different image reference:
podman container clone upd-demo upd-clone-img registry.access.redhat.com/ubi9/ubi-minimal:latestThat creates a new container ID — it does not mutate upd-demo. Port publishing is not available on clone in 5.8.2 (unknown flag: --publish), so expose ports with a fresh podman run or reconstruct the original command.
podman update versus clone versus recreate
| Need | Best starting point |
|---|---|
| CPU, memory, PID, or cpuset limits | podman update |
| Health-check interval, command, or retries | podman update |
Restart policy on a plain podman run container |
podman update --restart=... |
| Environment for the next main-process start | podman update then podman restart |
| Ulimits for the next main-process start | podman update then podman restart |
| Different image with similar config | podman container clone with IMAGE argument |
| Different ports, mounts, or command | Recreate with podman run / Quadlet |
| Declarative systemd service | Edit Quadlet .container and restart the unit |
Quadlet users should change the unit file and let systemd recreate the container — not hand-patch a generated instance that the next systemctl restart will overwrite.
Cleanup
Remove lab containers when finished:
podman rm -f upd-demo upd-health upd-clone upd-clone-img 2>/dev/nullSummary
podman update adjusts an existing container in place for cgroup limits, health probes, environment metadata, ulimits, and restart policy. CPU, memory, PID, and cpuset changes land in inspect and cgroup v2 files immediately on Podman 5.8.2. Environment and ulimit updates change container configuration right away, but PID 1 keeps its original environ and limits until podman restart — use /proc/1/environ and /proc/1/limits to verify what the main process actually runs with.
Image, ports, mounts, and most namespace settings are out of scope for update. Use podman container clone when you need a new object with a different image, or podman run when publish and mount flags change. For limit theory and rootless delegation errors, read the resource-limits guide; for health state after probe changes, read the healthcheck guide.
References
- podman-update(1) — supported flags and behavior
- podman-container-clone(1) — clone syntax and overrides
- podman-inspect(1) —
HostConfigandConfigfields after update

