Mike Slinn
Mike Slinn

Docker, OCI Images, Buildah and podman

Published 2021-04-28. Last modified 2021-05-06.
Time to read: about 4 minutes.

This article is categorized under AWS Lambda, Docker, Linux.

There are many ways to create and run Docker-compatible images. Docker is probably the worst option, mostly because it runs as a daemon, and all *nix daemons run with root privileges. Also, the docker-ce package lists iptables as a dependency, which needs systemd to be running normally, and WSL2 only partially supports systemd.

A Comprehensive Container Runtime Comparison provides helpful background information and an interesting historical viewpoint.

Open Container Initiative (OCI)

The latest evolution of Docker-compatible images, OCI image format (not to be confused with Oracle Cloud Infrastructure), is compatible with:

Supported OCI formats include:

  • Docker containers schema 1
  • Docker containers schema 2
  • Pods (groups of containers)
  • Images
  • Volumes

Buildah, podman and skopeo

This blog post discusses 3 related open source projects from RedHat / IBM that provide an alternative to Docker: Buildah, podman and skopeo. These 3 projects share a common source code base, and are daemonless tools for managing Open Container Initiative (OCI) images.

Paraphrasing the reasons expressed in Podman and Buildah for Docker Users for using podman instead of Docker, wherever podman is mentioned, read “podman, Buildah and skopeo”:

The Podman approach is simply to directly interact with the image registry, with the container and image storage, and with the Linux kernel through the runC container runtime process (not a daemon).

Running Podman as a normal user means that Podman will, by default, store images and containers in the user’s home directory. Podman uses a repository in the user’s home directory: ~/.local/share/containers (instead of /var/lib/docker).

Despite the new locations for the local repositories, the images created by Docker and Podman are compatible with the OCI standard. Podman can push to and pull from popular container registries like Quay.io and Docker hub, as well as private registries.

Buildah vs. podman

Podman can build OCI containers interactively or in batch mode. You can either build using a Dockerfile using podman build (batch mode), or you can interactively run a container, make changes to the running image, and then podman commit those changes to a new image tag.

Buildah was written before podman. Some of Buildah's source code for creating and managing container images was ported to podman. The podman build command is a subset of Buildah’s functionality.

However, apparently the differences between the two programs are important:

Buildah builds OCI images. Confusingly, podman build can also be used to build Docker images also, but it’s incredibly slow and used up a lot of disk space by using the vfs storage driver by default. buildah bud (‘build using Dockerfile’) was much faster for me, and uses the overlay storage driver.

  – From Goodbye Docker: Purging is Such Sweet Sorrow by Ian Miell.

podman

Podman supports developing, managing, and running OCI Containers on Linux systems, including WSL, without requiring root privilege.

shell Installation on Ubuntu
$ yes | sudo apt install buildah podman skopeo
Podman commands are very nearly the same as Docker’s.

Because podman is a drop-in replacement for docker, the following alias enables the docker command to invoke podman:

~/.bash_aliases
alias docker=podman

As described in How to Install and Use Podman on Ubuntu 20.04, I added 'registry.access.redhat.com' to the list of registries in /etc/containers/registries.conf. I also added 'gallery.ecr.aws' and 'gcr.io'.

/etc/containers/registries.conf
[registries.search]
registries = ['docker.io', 'gallery.ecr.aws', 'gcr.io', 'quay.io', 'registry.access.redhat.com']

podman Help

Shell
$ podman --help
Manage pods, containers and images
Usage: podman [flags] podman [command]
Available Commands: attach Attach to a running container auto-update Auto update containers according to their auto-update policy build Build an image using instructions from Containerfiles commit Create new image based on the changed container container Manage containers cp Copy files/folders between a container and the local filesystem create Create but do not start a container diff Display the changes to the object's file system events Show podman events exec Run a process in a running container export Export container's filesystem contents as a tar archive generate Generate structured data based on containers and pods. healthcheck Manage health checks on containers help Help about any command history Show history of a specified image image Manage images images List images in local storage import Import a tarball to create a filesystem image info Display podman system information init Initialize one or more containers inspect Display the configuration of object denoted by ID kill Kill one or more running containers with a specific signal load Load an image from container archive login Login to a container registry logout Logout of a container registry logs Fetch the logs of one or more containers manifest Manipulate manifest lists and image indexes mount Mount a working container's root filesystem network Manage networks pause Pause all the processes in one or more containers play Play a pod and its containers from a structured file. pod Manage pods port List port mappings or a specific mapping for the container ps List containers pull Pull an image from a registry push Push an image to a specified destination restart Restart one or more containers rm Remove one or more containers rmi Removes one or more images from local storage run Run a command in a new container save Save image to an archive search Search registry for image start Start one or more containers stats Display a live stream of container resource usage statistics stop Stop one or more containers system Manage podman tag Add an additional name to a local image top Display the running processes of a container unmount Unmounts working container's root filesystem unpause Unpause the processes in one or more containers unshare Run a command in a modified user namespace untag Remove a name from a local image version Display the Podman Version Information volume Manage volumes wait Block on one or more containers
Flags: --cgroup-manager string Cgroup manager to use ("cgroupfs"|"systemd") (default "cgroupfs") --cni-config-dir string Path of the configuration directory for CNI networks --conmon string Path of the conmon binary -c, --connection string Connection to use for remote Podman service --events-backend string Events backend to use ("file"|"journald"|"none") (default "file") --help Help for podman --hooks-dir strings Set the OCI hooks directory path (may be set multiple times) (default [/usr/share/containers/oci/hooks.d]) --identity string path to SSH identity file, (CONTAINER_SSHKEY) --log-level string Log messages above specified level (debug, info, warn, error, fatal, panic) (default "error") --namespace string Set the libpod namespace, used to create separate views of the containers and pods on the system --network-cmd-path string Path to the command for configuring the network -r, --remote Access remote Podman service (default false) --root string Path to the root directory in which data, including images, is stored --runroot string Path to the 'run directory' where all state information is stored --runtime string Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc --storage-driver string Select which storage driver is used to manage storage of images and containers (default is overlay) --storage-opt stringArray Used to pass an option to the storage driver --syslog Output logging information to syslog as well as the console (default false) --tmpdir string Path to the tmp directory for libpod state content. Note: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'. --url string URL to access Podman service (CONTAINER_HOST) (default "unix:/home/mslinn/.docker/run/podman/podman.sock") -v, --version Version of Podman
Use "podman [command] --help" for more information about a command.

podman info

Shell
$ podman info
host:
  arch: amd64
  buildahVersion: 1.15.2
  cgroupVersion: v1
  conmon:
    package: 'conmon: /usr/libexec/podman/conmon'
    path: /usr/libexec/podman/conmon
    version: 'conmon version 2.0.20, commit: unknown'
  cpus: 8
  distribution:
    distribution: ubuntu
    version: "20.10"
  eventLogger: file
  hostname: Bear
  idMappings:
    gidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
    uidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
  kernel: 5.4.72-microsoft-standard-WSL2
  linkmode: dynamic
  memFree: 897724416
  memTotal: 6231638016
  ociRuntime:
    name: runc
    package: 'containerd.io: /usr/bin/runc'
    path: /usr/bin/runc
    version: |-
      runc version 1.0.0-rc93
      commit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec
      spec: 1.0.2-dev
      go: go1.13.15
      libseccomp: 2.5.1
  os: linux
  remoteSocket:
    path: /home/mslinn/.docker/run/podman/podman.sock
  rootless: true
  slirp4netns:
    executable: /bin/slirp4netns
    package: Unknown
    version: |-
      slirp4netns version 1.0.1
      commit: 6a7b16babc95b6a3056b33fb45b74a6f62262dd4
      libslirp: 4.3.1
  swapFree: 0
  swapTotal: 0
  uptime: 306h 23m 6.37s (Approximately 12.75 days)
registries:
  search:
  - quay.io
  - docker.io
  - gallery.ecr.aws
  - registry.access.redhat.com
store:
  configFile: /home/mslinn/.config/containers/storage.conf
  containerStore:
    number: 8
    paused: 0
    running: 0
    stopped: 8
  graphDriverName: overlay
  graphOptions:
    overlay.mount_program:
      Executable: /bin/fuse-overlayfs
      Package: Unknown
      Version: |-
        fusermount3 version: 3.9.3
        fuse-overlayfs: version 1.0.0
        FUSE library version 3.9.3
        using FUSE kernel interface version 7.31
  graphRoot: /home/mslinn/.local/share/containers/storage
  graphStatus:
    Backing Filesystem: extfs
    Native Overlay Diff: "false"
    Supports d_type: "true"
    Using metacopy: "false"
  imageStore:
    number: 4
  runRoot: /home/mslinn/.docker/run/containers
  volumePath: /home/mslinn/.local/share/containers/storage/volumes
version:
  APIVersion: 1
  Built: 0
  BuiltTime: Wed Dec 31 19:00:00 1969
  GitCommit: ""
  GoVersion: go1.14.7
  OsArch: linux/amd64
  Version: 2.0.6 

podman container Help

Shell
$ man podman-container
podman-container(1)                                   General Commands Manual                                   podman-container(1)
NAME podman-container - Manage containers
SYNOPSIS podman container subcommand
DESCRIPTION The container command allows you to manage containers
COMMANDS ┌───────────┬────────────────────────────────┬───────────────────────────────────┐ │Command │ Man Page │ Description │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │attach │ podman-attach(1) │ Attach to a running container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │checkpoint │ podman-container-checkpoint(1) │ Checkpoints one or more running │ │ │ │ containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │cleanup │ podman-container-cleanup(1) │ Cleanup the container's network │ │ │ │ and mountpoints. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │commit │ podman-commit(1) │ Create new image based on the │ │ │ │ changed container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │cp │ podman-cp(1) │ Copy files/folders between a │ │ │ │ container and the local │ │ │ │ filesystem. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │create │ podman-create(1) │ Create a new container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │diff │ podman-diff(1) │ Inspect changes on a container or │ │ │ │ image's filesystem. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │exec │ podman-exec(1) │ Execute a command in a running │ │ │ │ container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │exists │ podman-container-exists(1) │ Check if a container exists in │ │ │ │ local storage │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │export │ podman-export(1) │ Export a container's filesystem │ │ │ │ contents as a tar archive. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │init │ podman-init(1) │ Initialize a container │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │inspect │ podman-inspect(1) │ Display a container or image's │ │ │ │ configuration. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │kill │ podman-kill(1) │ Kill the main process in one or │ │ │ │ more containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │list │ podman-ps(1) │ List the containers on the │ │ │ │ system.(alias ls) │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │logs │ podman-logs(1) │ Display the logs of a container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │mount │ podman-mount(1) │ Mount a working container's root │ │ │ │ filesystem. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │pause │ podman-pause(1) │ Pause one or more containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │port │ podman-port(1) │ List port mappings for the │ │ │ │ container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │prune │ podman-container-prune(1) │ Remove all stopped containers │ │ │ │ from local storage. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │restart │ podman-restart(1) │ Restart one or more containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │restore │ podman-container-restore(1) │ Restores one or more containers │ │ │ │ from a checkpoint. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │rm │ podman-rm(1) │ Remove one or more containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │run │ podman-run(1) │ Run a command in a container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │runlabel │ podman-container-runlabel(1) │ Executes a command as described │ │ │ │ by a container image label. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │start │ podman-start(1) │ Starts one or more containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │stats │ podman-stats(1) │ Display a live stream of one or │ │ │ │ more container's resource usage │ │ │ │ statistics. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │stop │ podman-stop(1) │ Stop one or more running │ │ │ │ containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │top │ podman-top(1) │ Display the running processes of │ │ │ │ a container. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │unmount │ podman-unmount(1) │ Unmount a working container's │ │ │ │ root filesystem.(Alias unmount) │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │unpause │ podman-unpause(1) │ Unpause one or more containers. │ ├───────────┼────────────────────────────────┼───────────────────────────────────┤ │wait │ podman-wait(1) │ Wait on one or more containers to │ │ │ │ stop and print their exit codes. │ └───────────┴────────────────────────────────┴───────────────────────────────────┘
SEE ALSO podman, podman-exec, podman-run
podman-container(1)

Podman Run Help

Shell
$ podman container run --help
Run a command in a new container
Description: Runs a command in a new container from the given image
Usage: podman container run [flags] IMAGE [COMMAND [ARG...]]
Examples: podman container run imageID ls -alF /etc podman container run --network=host imageID dnf -y install java podman container run --volume /var/hostdir:/var/ctrdir -i -t fedora /bin/bash
Flags: --add-host strings Add a custom host-to-IP mapping (host:ip) (default []) --annotation strings Add annotations to container (key:value) -a, --attach strings Attach to STDIN, STDOUT or STDERR --authfile string Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override --blkio-weight string Block IO weight (relative weight) accepts a weight value between 10 and 1000. --blkio-weight-device DEVICE_NAME:WEIGHT Block IO weight (relative device weight, format: DEVICE_NAME:WEIGHT) --cap-add strings Add capabilities to the container --cap-drop strings Drop capabilities from the container --cgroup-parent string Optional parent cgroup for the container --cgroupns string cgroup namespace to use --cgroups string control container cgroup configuration ("enabled"|"disabled"|"no-conmon") (default "enabled") --cidfile string Write the container ID to the file --conmon-pidfile string Path to the file that will receive the PID of conmon --cpu-period uint Limit the CPU CFS (Completely Fair Scheduler) period --cpu-quota int Limit the CPU CFS (Completely Fair Scheduler) quota --cpu-rt-period uint Limit the CPU real-time period in microseconds --cpu-rt-runtime int Limit the CPU real-time runtime in microseconds --cpu-shares uint CPU shares (relative weight) --cpus float Number of CPUs. The default is 0.000 which means no limit --cpuset-cpus string CPUs in which to allow execution (0-3, 0,1) --cpuset-mems string Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. -d, --detach Run container in background and print container ID --detach-keys [a-Z] Override the key sequence for detaching a container. Format is a single character [a-Z] or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-cf`, `@`, `^`, `[`, `\`, `]`, `^` or `_` (default "ctrl-p,ctrl-q") --device strings Add a host device to the container --device-cgroup-rule strings Add a rule to the cgroup allowed devices list --device-read-bps strings Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb) --device-read-iops strings Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000) --device-write-bps strings Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb) --device-write-iops strings Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000) --disable-content-trust This is a Docker specific option and is a NOOP --dns strings Set custom DNS servers --dns-opt strings Set custom DNS options --dns-search strings Set custom DNS search domains --entrypoint string Overwrite the default ENTRYPOINT of the image -e, --env stringArray Set environment variables in container (default [PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin,TERM=xterm]) --env-file strings Read in a file of environment variables --env-host Use all current host environment variables in container --expose strings Expose a port or a range of ports --gidmap strings GID map to use for the user namespace --group-add strings Add additional groups to join --health-cmd string set a healthcheck command for the container ('none' disables the existing healthcheck) --health-interval string set an interval for the healthchecks (a value of disable results in no automatic timer setup) (default "30s") --health-retries uint the number of retries allowed before a healthcheck is considered to be unhealthy (default 3) --health-start-period string the initialization time needed for a container to bootstrap (default "0s") --health-timeout string the maximum time allowed to complete the healthcheck before an interval is considered failed (default "30s") -h, --hostname string Set container hostname --http-proxy Set proxy environment variables in the container based on the host proxy vars (default true) --image-volume string Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore") (default "bind") --init Run an init binary inside the container that forwards signals and reaps processes --init-path string Path to the container-init binary -i, --interactive Keep STDIN open even if not attached --ip string Specify a static IPv4 address for the container --ipc string IPC namespace to use --kernel-memory <number>[<unit>] Kernel memory limit (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) -l, --label stringArray Set metadata on container --label-file strings Read in a line delimited file of labels --log-driver string Logging driver for the container --log-opt strings Logging driver options --mac-address string Container MAC address (e.g. 92:d0:c6:0a:29:33) -m, --memory <number>[<unit>] Memory limit (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) --memory-reservation <number>[<unit>] Memory soft limit (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) --memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap --memory-swappiness int Tune container memory swappiness (0 to 100, or -1 for system default) (default -1) --mount stringArray Attach a filesystem mount to the container --name string Assign a name to the container --network string Connect a container to a network (default "slirp4netns") --no-healthcheck Disable healthchecks on container --no-hosts Do not create /etc/hosts within the container, instead use the version from the image --oom-kill-disable Disable OOM Killer --oom-score-adj int Tune the host's OOM preferences (-1000 to 1000) --pid string PID namespace to use --pids-limit int Tune container pids limit (set 0 for unlimited, -1 for server defaults) --pod string Run container in an existing pod --pod-id-file string Read the pod ID from the file --privileged Give extended privileges to container -p, --publish strings Publish a container's port, or a range of ports, to the host (default []) -P, --publish-all Publish all exposed ports to random ports on the host interface --pull string Pull image before creating ("always"|"missing"|"never") (default "missing") -q, --quiet Suppress output information when pulling images --read-only Make containers root filesystem read-only --read-only-tmpfs When running containers in read-only mode mount a read-write tmpfs on /run, /tmp and /var/tmp (default true) --replace If a container with the same name exists, replace it --restart string Restart policy to apply when a container exits ("always"|"no"|"on-failure") --rm Remove container (and pod if created) after exit --rmi Remove container image unless used by other containers --rootfs The first argument is not an image but the rootfs to the exploded container --seccomp-policy string Policy for selecting a seccomp profile (experimental) (default "default") --security-opt stringArray Security Options --shm-size <number>[<unit>] Size of /dev/shm (format: <number>[<unit>], where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes)) (default "65536k") --sig-proxy Proxy received signals to the process (default true) --stop-signal string Signal to stop a container. Default is SIGTERM --stop-timeout uint Timeout (in seconds) to stop a container. Default is 10 (default 10) --subgidname string Name of range listed in /etc/subgid for use in user namespace --subuidname string Name of range listed in /etc/subuid for use in user namespace --sysctl strings Sysctl options --systemd string Run container in systemd mode ("true"|"false"|"always") (default "true") --tmpfs tmpfs Mount a temporary filesystem (tmpfs) into a container -t, --tty Allocate a pseudo-TTY for container --uidmap strings UID map to use for the user namespace --ulimit strings Ulimit options -u, --user string Username or UID (format: <name|uid>[:<group|gid>]) --userns string User namespace to use --uts string UTS namespace to use -v, --volume stringArray Bind mount a volume into the container --volumes-from strings Mount volumes from the specified container(s) -w, --workdir string Working directory inside the container

podman run

From Building and Deploying Lambdas from a Docker Container by Keith Gregory:

Shell
$ podman run \
  -it \
  --entrypoint /bin/bash \
  --rm \
  -v /tmp:/mnt \
  amazon/aws-lambda-python:3.8
Trying to pull quay.io/amazon/aws-lambda-python:3.8...
  Requesting bear token: invalid status code from registry 405 (Method Not Allowed)
Trying to pull docker.io/amazon/aws-lambda-python:3.8...
Getting image source signatures
Copying blob df513d38f4d9 skipped: already exists
Copying blob 2e2bb77ae2dc skipped: already exists
Copying blob 031c6369fb2b skipped: already exists
Copying blob 03ac043af787 skipped: already exists
Copying blob 842c9dce67e8 skipped: already exists
Copying blob 1de4740de1c2 [--------------------------------------] 0.0b / 0.0b
Copying config e12ea62c55 done
Writing manifest to image destination
Storing signatures
bash-4.2# pwd
/var/task 
Shell
$ buildah run \
  --entrypoint /var/lang/bin/pip \
  --rm \
  --user "$(id -u):$(id -g)" \
  -v "$(pwd):/mnt" \
  amazon/aws-lambda-python:3.8 \
  install --target /mnt/build --upgrade psycopg2-binary

Buildah

Buildah is a drop-in replacement for using docker build and a Dockerfile.

Where Buildah really shines is in its native commands, which you can use to interact with container builds. Rather than using build-using-dockerfile/bud for each build, Buildah has commands to actually interact with the temporary container created during the build process. (Docker uses temporary, or intermediate containers, too, but you don’t really interact with them while the image is being built.)

Unlike docker build, Buildah doesn’t commit changes to a layer automatically for every instruction in the Dockerfile – it builds everything from top to bottom, every time. On the positive side, this means non-cached builds (for example, those you would do with automation or build pipelines) end up being somewhat faster than their Docker build counterparts, especially if there are many instructions.

  – From Getting started with Buildah., published by opensource.com

Some key Buildah subcommands:

buildah bud
Buildah’s build-using-dockerfile, or bud argument makes it behave just like docker build does.
buildah from
Build up a container root filesystem from an image or from scratch.
buildah config
Adjust defaults in the image's configuration blob.
buildah run
buildah run is for running commands that build a container image. This is similar to RUN in a Dockerfile, and unlike docker run.
buildah commit
Commit changes to the container to a new image.
buildah push
Push images to registries (such a Quay) or a local dockerd instance.

Buildah Help

Shell
$ buildah -h
A tool that facilitates building OCI images
Usage: buildah [flags] buildah [command]
Available Commands: add Add content to the container build-using-dockerfile Build an image using instructions in a Dockerfile commit Create an image from a working container config Update image configuration settings containers List working containers and their base images copy Copy content into the container from Create a working container based on an image help Help about any command images List images in local storage info Display Buildah system information inspect Inspect the configuration of a container or image login Login to a container registry logout Logout of a container registry manifest Manipulate manifest lists and image indexes mount Mount a working container's root filesystem pull Pull an image from the specified location push Push an image to a specified destination rename Rename a container rm Remove one or more working containers rmi Remove one or more images from local storage run Run a command inside of the container tag Add an additional name to a local image umount Unmount the root file system of the specified working containers unshare Run a command in a modified user namespace version Display the Buildah version information
Flags: -h, --help help for buildah --log-level string The log level to be used. Either "debug", "info", "warn" or "error". (default "error") --registries-conf string path to registries.conf file (not usually used) --registries-conf-dir string path to registries.conf.d directory (not usually used) --root string storage root dir (default "/var/lib/containers/storage") --runroot string storage state dir (default "/var/run/containers/storage") --storage-driver string storage-driver --storage-opt strings storage driver option --userns-gid-map ctrID:hostID:length default ctrID:hostID:length GID mapping to use --userns-uid-map ctrID:hostID:length default ctrID:hostID:length UID mapping to use -v, --version version for buildah
Use "buildah [command] --help" for more information about a command.

Buildah / Dockerfile Compatibility

Buildah can create an image from a Dockerfile by typing:

Shell
$ buildah bud -t hello .

…instead of:

Shell
$ sudo docker build -t hello .

Buildah can create an image called hello from the Dockerfile and the Python app by typing:

Shell
$ buildah bud -t hello .
STEP 1: FROM public.ecr.aws/lambda/python:3.8
  Getting image source signatures
  Copying blob 1de4740de1c2 done
  Copying blob 2e2bb77ae2dc done
  Copying blob df513d38f4d9 done
  Copying blob 03ac043af787 done
  Copying blob 031c6369fb2b done
  Copying blob 842c9dce67e8 done
  Copying config e12ea62c55 done
  Writing manifest to image destination
  Storing signatures
  STEP 2: COPY app.py   ./
  STEP 3: CMD ["app.handler"]
  STEP 4: COMMIT hello
  Getting image source signatures
  Copying blob 109f575f8e6a skipped: already exists
  Copying blob ff64b4f854ad skipped: already exists
  Copying blob dd66ad8702f4 skipped: already exists
  Copying blob d6fa53d6caa6 skipped: already exists
  Copying blob 80166c3283e5 skipped: already exists
  Copying blob 61f74564c3aa skipped: already exists
  Copying blob d95ebdc79761 done
  Copying config 40ef32b39c done
  Writing manifest to image destination
  Storing signatures
  --> 40ef32b39cf
  40ef32b39cf4ffd3d2e4e3426bec4a5ea168524f7f3fcfe863a378abd9794270 

Once the build is complete, the new image can be displayed with the buildah images command:

Shell
$ buildah images
REPOSITORY                     TAG      IMAGE ID       CREATED          SIZE
localhost/hello                latest   40ef32b39cf4   56 seconds ago   622 MB 

The new image, tagged hello:latest, can be pushed to a remote image registry. This is easily accomplished with the buildah push command.

buildah push Help

Shell
$ man buildah-push
buildah-push(1)                                   General Commands Manual                                  buildah-push(1)
NAME buildah-push - Push an image from local storage to elsewhere.
SYNOPSIS buildah push [options] image [destination]
DESCRIPTION Pushes an image from local storage to a specified destination, decompressing and recompessing layers as needed.
imageID Image stored in local container/storage
DESTINATION The DESTINATION is a location to store container images. If omitted, the source image parameter will be reused as destination.
The Image "DESTINATION" uses a "transport":"details" format. Multiple transports are supported:
dir:path An existing local directory path storing the manifest, layer tarballs and signatures as individual files. This is a non-standardized format, primarily useful for debugging or noninvasive container inspection.
docker://docker-reference An image in a registry implementing the "Docker Registry HTTP API V2". By default, uses the authorization state in $XDG\_RUNTIME\_DIR/containers/auth.json, which is set using (buildah login). If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using (docker login). If docker-reference does not include a registry name, the image will be pushed to a registry running on local‐ host.
docker-archive:path[:docker-reference] An image is stored in the docker save formatted file. docker-reference is only used when creating such a file, and it must not contain a digest.
docker-daemon:docker-reference An image _dockerreference stored in the docker daemon internal storage. If _dockerreference does not begin with a valid registry name (a domain name containing "." or the reserved name "localhost") then the default registry name "docker.io" will be prepended. _dockerreference must contain either a tag or a digest. Alternatively, when reading images, the format can also be docker-daemon:algo:digest (an image ID).
oci:path:tag An image tag in a directory compliant with "Open Container Image Layout Specification" at path.
oci-archive:path:tag An image tag in a tar archive compliant with "Open Container Image Layout Specification" at path.
If the transport part of DESTINATION is omitted, "docker://" is assumed.
OPTIONS --authfile path
Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json, which is set using buildah lo‐ gin. If the authorization state is not found there, $HOME/.docker/config.json is checked, which is set using docker login.
--cert-dir path
Use certificates at path (*.crt, *.cert, *.key) to connect to the registry. Default certificates directory is /etc/containers/certs.d.
--creds creds
The [username[:password]] to use to authenticate with the registry if required. If one or both values are not sup‐ plied, a command line prompt will appear and the value can be entered. The password is entered without echo.
--digestfile Digestfile
After copying the image, write the digest of the resulting image to the file.
--disable-compression, -D
Don't compress copies of filesystem layers which will be pushed.
--encryption-key key
The [protocol:keyfile] specifies the encryption protocol, which can be JWE (RFC7516), PGP (RFC4880), and PKCS7 (RFC2315) and the key material required for image encryption. For instance, jwe:/path/to/key.pem or pgp:admin@exam‐ ple.com or pkcs7:/path/to/x509-file.
--format, -f
Manifest Type (oci, v2s1, or v2s2) to use when saving image to directory using the 'dir:' transport (default is manifest type of source)
--quiet, -q
When writing the output image, suppress progress output.
--remove-signatures
Don't copy signatures when pushing images.
--sign-by fingerprint
Sign the pushed image using the GPG key that matches the specified fingerprint.
--tls-verify bool-value
Require HTTPS and verify certificates when talking to container registries (defaults to true)
EXAMPLE This example pushes the image specified by the imageID to a local directory in docker format.
# buildah push imageID dir:/path/to/image
This example pushes the image specified by the imageID to a local directory in oci format.
# buildah push imageID oci:/path/to/layout:image:tag
This example pushes the image specified by the imageID to a tar archive in oci format.
# buildah push imageID oci-archive:/path/to/archive:image:tag
This example pushes the image specified by the imageID to a container registry named registry.example.com.
# buildah push imageID docker://registry.example.com/repository:tag
This example pushes the image specified by the imageID to a container registry named registry.example.com and saves the digest in the specified digestfile.
# buildah push --digestfile=/tmp/mydigest imageID docker://registry.example.com/repository:tag
This example works like docker push, assuming registry.example.com/my_image is a local image.
# buildah push registry.example.com/my_image
This example pushes the image specified by the imageID to a private container registry named registry.example.com with authentication from /tmp/auths/myauths.json.
# buildah push --authfile /tmp/auths/myauths.json imageID docker://registry.example.com/repository:tag
This example pushes the image specified by the imageID and puts into the local docker container store.
# buildah push imageID docker-daemon:image:tag
This example pushes the image specified by the imageID and puts it into the registry on the localhost while turning off tls verification. # buildah push --tls-verify=false imageID docker://localhost:5000/my-imageID
This example pushes the image specified by the imageID and puts it into the registry on the localhost using creden‐ tials and certificates for authentication. # buildah push --cert-dir /auth --tls-verify=true --creds=username:password imageID docker://local‐ host:5000/my-imageID
ENVIRONMENT BUILD_REGISTRY_SOURCES
BUILD_REGISTRY_SOURCES, if set, is treated as a JSON object which contains lists of registry names under the keys insecureRegistries, blockedRegistries, and allowedRegistries.
When pushing an image to a registry, if the portion of the destination image name that corresponds to a registry is compared to the items in the blockedRegistries list, and if it matches any of them, the push attempt is denied. If there are registries in the allowedRegistries list, and the portion of the name that corresponds to the registry is not in the list, the push attempt is denied.
TMPDIR The TMPDIR environment variable allows the user to specify where temporary files are stored while pulling and pushing images. Defaults to '/var/tmp'.
FILES registries.conf (/etc/containers/registries.conf)
registries.conf is the configuration file which specifies which container registries should be consulted when com‐ pleting image names which do not include a registry or domain portion.
policy.json (/etc/containers/policy.json)
Signature policy file. This defines the trust policy for container images. Controls which container registries can be used for image, and whether or not the tool should trust the images.
SEE ALSO buildah(1), buildah-login(1), containers-policy.json(5), docker-login(1), containers-registries.conf(5)
buildah June 2017 buildah-push(1)

How To

The following was inspired by Recap: images and containers from Docker for beginners. The equivalent commands for Docker alternatives are shown.

Check software version

$ docker -v
Docker version 20.10.2, build 20.10.2-0ubuntu1~20.10.1
$ buildah -v
buildah version 1.15.2 (image-spec 1.0.1, runtime-spec 1.0.2-dev)
$ podman -v
podman version 2.0.6

Download the Amazon Linux 2 image

AWS Lambda functions run under Amazon Linux.

Each of these 3 commands does a very similar task, downloading a specific image. Docker uses different subdirectories for images than Buildah and podman do.

$ sudo docker pull amazonlinux
Using default tag: latest
latest: Pulling from library/amazonlinux
3c2c91c7c431: Pull complete
Digest: sha256:06b9e2433e4e563e1d75bc8c71d32b76dc49a2841e9253746eefc8ca40b80b5e
Status: Downloaded newer image for amazonlinux:latest
docker.io/library/amazonlinux:latest 

Buildah works without complaint.

$ buildah pull amazonlinux
53ef897d731f9a5673c083d0e86d7911f85d6e63bb2be2346b17bdbacdc58637 

podman seems to hiccup and then complete successfully.

$ podman pull amazonlinux
Trying to pull quay.io/amazonlinux...
  error parsing HTTP 404 response body: invalid character '<' looking for beginning of value: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>\n"
Trying to pull docker.io/library/amazonlinux...
Getting image source signatures
Copying blob 3c2c91c7c431 [--------------------------------------] 0.0b / 0.0b
Copying config 53ef897d73 done
Writing manifest to image destination
Storing signatures
53ef897d731f9a5673c083d0e86d7911f85d6e63bb2be2346b17bdbacdc58637
 

Run a Bash Command in an OCI Container

Again, Docker must be run as root for this operation, this represents an unnecessary security risk.

$ sudo docker container run amazonlinux echo 'Hello World!'
Hello World! 
$ podman container run amazonlinux cat /etc/os-release
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/" 

Show All Locally Available Images

Again, Docker must be run as root for this operation, this represents an unnecessary security risk.

$ sudo docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
amazonlinux   latest    53ef897d731f   21 hours ago   163MB 
$ podman images
REPOSITORY                     TAG     IMAGE ID      CREATED       SIZE
localhost/hello                latest  40ef32b39cf4  5 hours ago   622 MB
docker.io/library/amazonlinux  latest  53ef897d731f  21 hours ago  170 MB 

List OCI Containers

$ sudo docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ podman container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

View All OCI Containers (Running or Not)

$ sudo docker container ls -a
CONTAINER ID   IMAGE         COMMAND                 CREATED          STATUS                      PORTS     NAMES
250f56d9aced   amazonlinux   "echo 'Hello World!'"   14 minutes ago   Exited (0) 14 minutes ago             competent_einstein 
$ podman container ls -a
CONTAINER ID  IMAGE                                 COMMAND            CREATED            STATUS                        PORTS   NAMES
  0f8203e9d3b8  docker.io/library/amazonlinux:latest  echo Hello world!  36 minutes ago     Exited (0) 36 minutes ago
    beautiful_mestorf
  14282ace8978  docker.io/library/amazonlinux:latest  echo Hello world!  36 minutes ago     Exited (0) 36 minutes ago
    beautiful_goldwasser
  1b9a8db52fb9  docker.io/library/alpine:latest       echo Hello World!  About an hour ago  Exited (0) About an hour ago          zealous_easley
  6444ee144488  docker.io/library/amazonlinux:latest  echo Hello World!  12 minutes ago     Exited (0) 12 minutes ago
    frosty_ritchie
  7444122cbc59  docker.io/library/alpine:latest       cat /etc/motd      About an hour ago  Exited (0) About an hour ago          elated_sammet
  aef84973d6ad  docker.io/library/amazonlinux:latest  echo Hello world!  About an hour ago  Exited (0) About an hour ago          lucid_sinoussi
  e210f74bc209  docker.io/library/amazonlinux:latest  cat /etc/motd      About an hour ago  Exited (0) About an hour ago          jovial_borg 

List Running OCI containers

$ sudo docker container ps -a
CONTAINER ID   IMAGE         COMMAND                 CREATED         STATUS                     PORTS     NAMES
250f56d9aced   amazonlinux   "echo 'Hello World!'"   5 minutes ago   Exited (0) 5 minutes ago             competent_einstein 

podman has a problem with the container ps sub-subcommand.

$ podman container ps -a
Error: unrecognized command `podman container ps`
Try 'podman container --help' for more information. 

buildah push to Docker Daemon

Shell
$ buildah push hello:latest docker-daemon:hello:latest
Getting image source signatures
  Copying blob sha256:72fcdba8cff9f105a61370d930d7f184702eeea634ac986da0105d8422a17028
   247.02 MiB / 247.02 MiB [==================================================] 2s
  Copying blob sha256:e567905cf805891b514af250400cc75db3cb47d61219750e0db047c5308bd916
   144.75 MiB / 144.75 MiB [==================================================] 1s
  Copying config sha256:6d54bef73e638f2e2dd8b7bf1c4dfa26e7ed1188f1113ee787893e23151ff3ff
   1.59 KiB / 1.59 KiB [======================================================] 0s
  Writing manifest to image destination
  Storing signatures 

$ buildah images | head -n2
REPOSITORY              TAG             IMAGE ID        CREATED                 SIZE
docker.io/hello      latest       6d54bef73e63  2 minutes ago   398 MB 

$ buildah run -t hello:latest
Hello, world! 

Delete an OCI Image

Delete an OCI image in Buildah's ~/.local/share/container directory with the rmi subcommand:

Shell
$ buildah rmi e12ea62c5582
e12ea62c5582f91a2228e3e284ea957f2df4f1cdb150fd2c189ef8f11d7633ce