Essential commands for managing containers: listing, logs, copying files, and troubleshooting.
This tutorial covers the commands you'll use daily when working with sdme containers.
Every sdme command has detailed --help output with examples,
environment variables, file locations, and exit codes. This is the
primary documentation for sdme; there is no separate manpage.
sudo sdme --help
Subcommands have their own help:
sudo sdme cp --help
sudo sdme fs import --help
sudo sdme new --help
Stop a running container:
sudo sdme stop mycontainer
Start a stopped container:
sudo sdme start mycontainer
Restart (stop then start) in one command:
sudo sdme restart mycontainer
Restart all running containers:
sudo sdme restart --all
Containers can have CPU and memory limits. Set them at creation time:
sudo sdme new dev -r ubuntu --memory 2G --cpus 2
Or on an existing container with sdme set:
sudo sdme set mycontainer --memory 1G --cpus 0.5
The available flags are:
--memory sets a hard memory limit (e.g. 512M, 2G). Maps to systemd MemoryMax.--cpus limits CPU time as a number of CPUs (e.g. 2, 0.5). Maps to systemd CPUQuota.--cpu-weight sets scheduling weight from 1 to 10000 (default: 100). Higher values get more CPU time relative to other containers. Maps to systemd CPUWeight.sdme set replaces all limits on the container. To remove limits,
run sdme set without any limit flags:
sudo sdme set mycontainer
Limits persist across restarts via a systemd drop-in file. Running containers need a restart for the new limits to take effect.
sudo sdme ps
This shows all containers with their status (running/stopped), health, OS, and any active configuration (pods, userns, binds, kube).
For machine-parseable output:
sudo sdme ps --json
sudo sdme ps --json-pretty
JSON output always includes all fields regardless of whether any
container uses them, including the rootfs name that links each
container to its base root filesystem.
To make JSON the default format for both ps and fs ls:
sudo sdme config set default_output_format json-pretty
sudo sdme fs ls
Shows all imported root filesystems. When any rootfs has containers, a CONTAINERS column shows the count. JSON output includes the full list of container names:
sudo sdme fs ls --json
Container logs are stored in the container's journal. The logs
command runs journalctl inside the container:
sudo sdme logs mycontainer
Extra arguments are passed through to journalctl. Follow logs in real time:
sudo sdme logs mycontainer -- -f
Last 50 lines:
sudo sdme logs mycontainer -- -n 50
Logs since a specific time:
sudo sdme logs mycontainer -- --since '5 min ago'
For OCI application containers, use --oci to see the app service
logs instead of the full container journal:
sudo sdme logs mycontainer --oci
sdme cp copies files between the host, containers, and root
filesystems. Copies are always recursive (no -r flag needed).
Ownership, permissions, timestamps, and extended attributes are
preserved.
Host to container:
sudo sdme cp ./config.txt mycontainer:/etc/config.txt
Container to host:
sudo sdme cp mycontainer:/etc/os-release .
Host to root filesystem:
sudo sdme cp ./config.txt fs:ubuntu:/etc/config.txt
Root filesystem to host:
sudo sdme cp fs:ubuntu:/etc/hostname .
Container and rootfs paths must be absolute (after the colon).
Running containers: files are read and written through the
container's live mount namespace. This gives access to all paths
including /tmp, /run, and /dev/shm. A consistency warning is
printed because the filesystem may be changing concurrently.
Stopped containers: writes go to the overlayfs upper layer.
Writes to /tmp, /run, and /dev/shm are refused because systemd
mounts tmpfs over these directories at boot, hiding anything written
to the upper layer. Use /var/tmp/ as an alternative.
Writes to a root filesystem go directly to the rootfs directory. Running containers that use this rootfs will not see the changes because the kernel caches the overlayfs lower layer. Stop and restart affected containers to pick up changes.
When copying to the host, device nodes are refused by default.
Use --force to skip all safety checks (device nodes and
setuid/setgid warnings).
When a container fails to boot, sdme stops it but leaves the state
on disk for debugging. This applies to both sdme start and
sdme new. You can check the journal for what went wrong.
A common issue is trying to use --hardened or --strict with a
host rootfs clone:
sudo sdme new --hardened
This may fail to boot because the hardened flags enable user namespace
isolation (--userns), which uses overlayfs idmapped mounts. If the
host rootfs contains files with security.capability xattrs, the
kernel refuses to create the idmapped mount.
When sdme new fails, break it into individual steps to isolate the
problem. First create the container without starting it:
sudo sdme create mycontainer --hardened
Then start it separately:
sudo sdme start mycontainer
If start fails, the container is preserved on disk. Check the logs:
sudo sdme logs mycontainer
Use --hardened and --strict with imported rootfs (e.g. -r ubuntu) rather than host rootfs clones. Imported rootfs are clean and don't carry host-specific xattrs that can interfere with user namespace isolation.
Over time, sdme accumulates unused filesystems, orphaned pods, broken
containers, and leftover secrets or volumes. The prune command finds
and removes them all in one step.
See what would be pruned without removing anything:
sudo sdme prune --dry-run
Run interactively (analyze, confirm, then remove):
sudo sdme prune
Skip the confirmation prompt:
sudo sdme prune -f
Exclude specific items from pruning by name:
sudo sdme prune --except=ubuntu,db-creds
When a name appears in multiple categories (e.g. a container and a
secret both named myapp), use the category:name prefix:
sudo sdme prune --except=secret:myapp,container:myapp
The configured default_base_fs is always excluded from pruning.
Kube secrets and configmaps are always listed for pruning because they are copied into the container at create time and not referenced at runtime. Use --except to keep any you plan to reuse in future kube apply commands.