container update no longer fails on Podman for containers using userns_mode: keep-id
This commit is contained in:
2 files changed
+49
-1
No files matched your search
@@ -18,7 +18,7 @@ import { computeRequestTimeoutMs } from './backups/request-timeout';
|
||||
import type { Environment } from './db';
|
||||
import { getSetting } from './db';
|
||||
import { getAdditionalVolumeBinds, dedupeVolumesForRecreate } from './mount-dedupe';
|
||||
import { resolveNanoCpusConflict } from './hostconfig-recreate';
|
||||
import { resolveNanoCpusConflict, resolvePodmanUsernsMode } from './hostconfig-recreate';
|
||||
import { rebaseEnvOntoImage, rebaseLabelsOntoImage, rebaseCommand, describeEnvRebase, describeLabelRebase, type ImageEnvLabels } from './container-env-merge';
|
||||
import { encodeRegistryAuth } from './registry-auth';
|
||||
import { isSystemContainer, classifyEmptyDigestImage, localDigestIsIndexChild } from './scheduler/tasks/update-utils';
|
||||
@@ -2093,6 +2093,20 @@ export async function recreateContainerFromInspect(
|
||||
log?.('Dropped CpuPeriod/CpuQuota — they conflict with NanoCpus at create time (kept NanoCpus)');
|
||||
}
|
||||
|
||||
// Podman lowers `--userns keep-id` to UsernsMode:"private" in inspect, which create then
|
||||
// rejects without inline mappings (#1409). Restore the original intent from the annotation
|
||||
// so keep-id survives the recreate; Docker (UsernsMode != "private") is untouched.
|
||||
const usernsFix = resolvePodmanUsernsMode(createConfig.HostConfig?.UsernsMode, config.Annotations);
|
||||
if (usernsFix && createConfig.HostConfig) {
|
||||
if ('mode' in usernsFix) {
|
||||
createConfig.HostConfig.UsernsMode = usernsFix.mode;
|
||||
log?.(`Restored UsernsMode "${usernsFix.mode}" from Podman annotation (was "private")`);
|
||||
} else {
|
||||
delete createConfig.HostConfig.UsernsMode;
|
||||
log?.('Dropped UsernsMode "private" — Podman rejects it without inline UID/GID mappings');
|
||||
}
|
||||
}
|
||||
|
||||
// container:<name> mode shares the network namespace — Docker rejects
|
||||
// networking-related fields on the dependent container since they're
|
||||
// owned by the network provider container
|
||||
@@ -2305,6 +2319,14 @@ export async function createContainerFromMetadata(
|
||||
delete createConfig.HostConfig.MemorySwappiness;
|
||||
}
|
||||
|
||||
// Podman keep-id -> UsernsMode:"private" in inspect, rejected on create (#1409).
|
||||
// Restore the intent from the annotation; Docker (UsernsMode != "private") untouched.
|
||||
const usernsFix = resolvePodmanUsernsMode(createConfig.HostConfig?.UsernsMode, config.Annotations);
|
||||
if (usernsFix && createConfig.HostConfig) {
|
||||
if ('mode' in usernsFix) createConfig.HostConfig.UsernsMode = usernsFix.mode;
|
||||
else delete createConfig.HostConfig.UsernsMode;
|
||||
}
|
||||
|
||||
// container:<name> mode: clean up conflicting network fields
|
||||
if (networkMode.startsWith('container:')) {
|
||||
delete createConfig.Hostname;
|
||||
|
||||
@@ -32,3 +32,29 @@ export function resolveNanoCpusConflict(hostConfig: CpuHostConfig | null | undef
|
||||
delete hostConfig.CpuQuota;
|
||||
return true;
|
||||
}
|
||||
|
||||
const PODMAN_USERNS_ANNOTATION = 'io.podman.annotations.userns';
|
||||
|
||||
/**
|
||||
* Podman lowers `--userns keep-id`/`auto`/`nomap` to `UsernsMode: "private"` plus generated
|
||||
* `IDMappings` in inspect, losing the original intent. Replaying `UsernsMode: "private"` to
|
||||
* create WITHOUT inline mappings is rejected ("must provide at least one UID or GID mapping
|
||||
* to configure a user namespace", #1409). Podman keeps the real intent in the
|
||||
* `io.podman.annotations.userns` annotation, and `create --userns keep-id` regenerates the
|
||||
* mappings - so restore the annotation value to keep keep-id working across a recreate.
|
||||
*
|
||||
* Returns the corrected UsernsMode: the annotation value ("keep-id", "auto",
|
||||
* "keep-id:uid=1000,gid=1000", ...) when present, `undefined` to STRIP a bare "private" with
|
||||
* no recorded intent, or `null` for "leave UsernsMode untouched". Only the lowered "private"
|
||||
* form is ever changed, so Docker (UsernsMode "", "host", "container:x", ...) is never
|
||||
* touched - no Docker regression.
|
||||
*/
|
||||
export function resolvePodmanUsernsMode(
|
||||
usernsMode: string | undefined | null,
|
||||
annotations: Record<string, string> | undefined | null
|
||||
): { mode: string } | { strip: true } | null {
|
||||
if (usernsMode !== 'private') return null;
|
||||
const intent = annotations?.[PODMAN_USERNS_ANNOTATION]?.trim();
|
||||
if (intent) return { mode: intent };
|
||||
return { strip: true };
|
||||
}
|
||||
Reference in new issue
Block a user