Chapter 1. Starting with containers
Linux Containers have emerged as a key open source application packaging and delivery technology, combining lightweight application isolation with the flexibility of image-based deployment methods.
Red Hat Enterprise Linux implements Linux Containers using core technologies such as Control Groups (Cgroups) for Resource Management, Namespaces for Process Isolation, SELinux for Security, enabling secure multi-tenancy and reducing the potential for security exploits. All this is meant to provide you with an environment to producing and running enterprise-quality containers.
Red Hat OpenShift provides powerful command-line and Web UI tools for building, managing and running containers in units referred to as
pods. However, there are times when you might want to build and manage individual containers and container images outside of OpenShift. Tools provided to perform those tasks that run directly on RHEL systems are described in this guide.
Unlike other container tools implementations, tools described here do not center around the monolithic Docker container engine and
docker command. Instead, we provide a set of command-line tools that can operate without a container engine. These include:
- podman - For directly managing pods and container images (run, stop, start, ps, attach, exec, and so on)
- buildah - For building, pushing and signing container images
- skopeo - For copying, inspecting, deleting, and signing images
- runc - For providing container run and build features to podman and buildah
Because these tools are compatible with the Open Container Initiative (OCI), they can be used to manage the same Linux containers that are produced and managed by Docker and other OCI-compatible container engines. However, they are especially suited to run directly on Red Hat Enterprise Linux, in single-node use cases. For a list of supported container tools, see What container runtimes and container management tools are supported?.
For a multi-node container platform, see OpenShift. Instead of relying on the single-node, daemonless tools described in this document, OpenShift requires a daemon-based container engine. Please see Using the CRI-O Container Engine for details.
1.1. Running containers without Docker
Red Hat did not just remove the Docker container engine from OpenShift. It also removed the Docker container engine, along with the
docker command, from Red Hat Enterprise Linux 8 entirely. For RHEL 8, Docker is not included and not supported by Red Hat (although it is still available from other sources).
The removal of Docker reflects a change in Red Hat’s way of thinking about how containers are handled:
- In the enterprise, the focus is not on running individual containers from the command line. The primary venue for running containers is a Kubernetes-based platform, such as OpenShift.
- By repositioning OpenShift as the project for running containers, container engines like Docker become just another component of OpenShift with no direct access by end users.
- Because the container engine in OpenShift is not meant to be used directly, it can be implemented with a limited feature set that focuses on doing everything that OpenShift needs, without having to implement lots of standalone features.
Although Docker is gone from RHEL 8, and OpenShift’s container engine is disconnected from single-node uses, people still want to use commands to work with containers and images manually. So Red Hat set about to create a set of tools to implement most of what the
docker command does.
buildah were developed to take over those
docker command features. Each tool in this scenario can be more light-weight and focused on a subset of features. And with no need for a daemon process running to implement a container engine, these tools can run without the overhead of having to work with a daemon process.
If you feel that you still want to use Docker in RHEL 8, know that you can get Docker from different upstream projects, but that its use is unsupported in RHEL 8. Because so many
docker command-line features have been implemented exactly in
podman, you can set up an alias so that typing
docker causes podman to run.
Installing the podman-docker package sets up such an alias. So every time you run a
docker command line, it actually runs
podman for you. More on this package later.
1.2. Choosing a RHEL architecture for containers
Red Hat provides container images and container-related software for the following computer architectures:
- AMD64 and Intel 64 (base and layered images) (no support for the 32-bit AMD and Intel architecture)
- PowerPC 8 and 9 64-bit (base image and most layered images)
- IBM Z (base image and most layered images)
- ARM 64-bit (base image only)
Although not all Red Hat images were supported across all architectures at first, nearly all are now available on all listed architectures. See Universal Base Images (UBI): Images, repositories, and packages for a list of supported images.
1.3. Getting container tools
To get an environment where you can manipulate individual containers, you can install a Red Hat Enterprise Linux 8 system, then add a set of container tools to find, run, build and share containers. Here are examples of container-related tools you can install with RHEL 8:
podman - Client tool for managing containers. Can replace most features of the
dockercommand for working with individual containers and images.
- buildah - Client tool for building OCI-compliant container images.
- skopeo - Client tool for copying container images to and from container registries. Includes features for signing and authenticating images as well.
- runc - Container runtime client for running and working with Open Container Initiative (OCI) format containers.
Using the RHEL subscription model, if you want to create container images, you must properly register and entitle the host computer on which you build them. When you install packages, as part of the process of building a container, the build process automatically has access to entitlements available from the RHEL host. So it can get RPM packages from any repository enabled on that host.
- Install RHEL: If you are ready to begin, you can start by installing a Red Hat Enterprise Linux system.
Register RHEL: Once RHEL is installed, register the system. You will be prompted to enter your user name and password. Note that the user name and password are the same as your login credentials for Red Hat Customer Portal.
# subscription-manager register Registering to: subscription.rhsm.redhat.com:443/subscription Username: ******** Password: **********
Subscribe RHEL: Either auto subscribe or determine the pool ID of a subscription that includes Red Hat Enterprise Linux. Here is an example of auto-attaching a subscription:
# subscription-manager attach --auto
Install packages: To start building and working with individual containers, install the container-tools module, which pulls in the full set of container software packages:
# yum module install -y container-tools
Install podman-docker (optional): If you are comfortable with the
dockercommand or use scripts that call
dockerdirectly, you can install the podman-docker package. That package installs a link that replaces the
dockercommand-line interface with the matching
podmancommands instead. It also links the man pages together, so
man docker infowill show the
podman infoman page.
# yum install -y podman-docker
1.4. Enabling container settings
No container engine (such as Docker or CRI-O) is required for you to run containers on your local system. However, configuration settings in the
/etc/containers/registries.conf file let you define access to container registries when you work with container tools such as
Here are example settings in the
[registries.search] registries = ['registry.redhat.io', 'registry.access.redhat.com', 'quay.io', 'docker.io'] [registries.insecure] registries =  [registries.block] registries = 
By default, when you use
podman search to search for images from a container registries, based on the
podman looks for the requested image in registry.redhat.io, registry.access.redhat.com, quay.io, and docker.io, in that order.
To add access to a registry that doesn’t require authentication (an insecure registry), you must add the name of that registry under the
[registries.insecure] section. Any registries that you want to disallow from access from your local system needs to be added under the
Here are a few other things you should know about configuring container registries:
- Make sure that each registry is surrounded by single quotes.
If there are multiple registries set for the
registries =value, you must separate those registries by commas.
- Registries can be identified by either IP address or hostname.
- If the registry uses a non-standard port (i.e., other than TCP ports 443 for secure and 80 for insecure), you should enter that port number with the registry name. For example: host.example.com:9999
Registries are searched in the order in which they appear for each section of the
If you are a regular user (rootless) running podman and related tools, you can create your own
registries.conffile to override the default settings.
1.5. Running containers as root or rootless
Running the container tools such as
buildah as a user with superuser privilege (root user) is the best way to ensure that your containers have full access to any feature available on your system. However, with the feature called "Rootless Containers," generally available as of RHEL 8.1, you can work with containers as a regular user.
Although container engines, such as Docker, let you run
docker commands as a regular (non-root) user, the docker daemon that carries out those requests runs as root. So, effectively, regular users can make requests through their containers that harm the system, without there being clarity about who made those requests. By setting up rootless container users, system administrators limit potentially damaging container activities from regular users, while still allowing those users to safely run many container features under their own accounts.
This section describes how to set up your system to use container tools (Podman, Skopeo, and Buildah) to work with containers as a non-root user (rootless). It also describes some of the limitations you will encounter because regular user accounts don’t have full access to all operating system features that their containers might need to run.
1.5.1. Set up for rootless containers
You need to become root user to set up your RHEL system to allow non-root user accounts to use container tools:
- Install RHEL: Install RHEL 8.1 or upgrade to RHEL 8.1 from RHEL 8.0. Earlier RHEL 7 versions are missing features needed for this procedure. If you are upgrading from RHEL 7.6 or earlier, continue to "Upgrade to rootless containers" after this procedure is done.
Install podman and slirp4netns: If not already installed, install the podman and slirp4netns packages:
# yum install slirp4netns podman -y
Increase user namespaces: To increase the number of user namespaces in the kernel, type the following:
# echo "user.max_user_namespaces=28633" > /etc/sysctl.d/userns.conf # sysctl -p /etc/sysctl.d/userns.conf
Create a new user account: To create a new user account and add a password for that account (for example, joe), type the following:
# useradd -c "Joe Jones" joe # passwd joe
The user is automatically configured to be able to use rootless podman.
Try a podman command: Log in directly as the user you just configured (don’t use
su -to become that user because that doesn’t set the correct environment variables) and try to pull and run an image:
$ podman pull registry.access.redhat.com/ubi8/ubi $ podman run registry.access.redhat.com/ubi8/ubi cat /etc/os-release NAME="Red Hat Enterprise Linux" VERSION="8.1 (Ootpa)" ...
Check rootless configuration: To check that your rootless configuration is set up properly, you can run commands inside the modified user namespace with the
podman unsharecommand. As the rootless user, the following command lets you see how the uids are assigned to the user namespace:
$ podman unshare cat /proc/self/uid_map 0 1001 1 1 65537 65536
1.5.2. Upgrade to rootless containers
If you have upgraded from RHEL 7, you must configure subuid and subgid values manually for any existing user you want to be able to use rootless podman.
Using an existing user name and group name (for example, jill), set the range of accessible user and group IDs that can be used for their containers. Here are a couple of warnings:
- Don’t include the rootless user’s UID and GID in these ranges
- If you set multiple rootless container users, use unique ranges for each user
- We recommend 65536 UIDs and GIDs for maximum compatibility with existing container images, but the number can be reduced
Never use UIDs or GIDs under 1000 or reuse UIDs or GIDs from existing user accounts (which, by default, start at 1000)
Here is an example:
# echo "jill:165537:65536" >> /etc/subuid # echo "jill:165537:65536" >> /etc/subgid
The user/group jill is now allocated 65535 user and group IDs, ranging from 165537-231072. That user should be able to begin running commands to work with containers now.
1.5.3. Special considerations for rootless
Here are some things to consider when running containers as a non-root user:
As a non-root container user, container images are stored under your home directory (
$HOME/.local/share/containers/storage/), instead of
- Users running rootless containers are given special permission to run as a range of user and group IDs on the host system. However, they otherwise have no root privileges to the operating system on the host.
If you need to configure your rootless container environment, edit configuration files in your home directory (
$HOME/.config/containers). Configuration files include
storage.conf(for configuring storage) and
libpod.conf(for a variety of container settings). You could also create a
registries.conffile to identify container registries available when you use
podmanto pull, search or run images.
A container running as root in a rootless account can turn on privileged features within its own namespace. But that doesn’t provide any special privileges to access protected features on the host (beyond having extra UIDs and GIDs). Here are examples of container actions you might expect to work from a rootless account that will not work:
- Anything you want to access from a mounted directory from the host must be accessible by the UID running your container or your request to access that component will fail.
There are some system features you won’t be able to change without privilege. For example, you cannot change the system clock by simply setting a SYS_TIME capability inside a container and running the network time service (ntpd). You would have to run that container as root, bypassing your rootless container environment and using the root user’s environment, for that capability to work, such as:
$ sudo podman run -d --cap-add SYS_TIME ntpd
Note that this example allows ntpd to adjust time for the entire system, and not just within the container.
A rootless container has no ability to access a port less than 1024. Inside the rootless container’s namespace it can, for example, start a service that exposes port 80 from an httpd service from the container, but it will not be accessible outside of the namespace:
$ podman run -d httpd
However, a container would need root privilege, again using the root user’s container environment, to expose that port to the host system:
$ sudo podman run -d -p 80:80 httpd
The administrator of a workstation can configure it to allow users to expose services below 1024, but they should understand the security implications. A regular user could, for example, run a web server on the official port 80 and trick external users into believing that it was configured by the administrator. This is generally OK on a workstation, but might not be on a network-accessible development server, and definitely should not be done on production servers. To allow users to bind to ports down to port 80 run the following command:
# echo 80 > /proc/sys/net/ipv4/ip_unprivileged_port_start
- Rootless containers currently relies on setting static subuid and subgid ranges. If you are using LDAP or Active Directory to provide user authentication, there is no automated way to provide those UID and GID ranges to users. A current workaround could be to set static ranges in /etc/subuid and /etc/subgid files to match the known UIDs and GIDs in use.
- Container storage must be on a local file system, because remote file systems do not work well with unprivileged user namespaces.
An on-going list of shortcomings of running
podmanand related tools without root privilege is contained in Shortcomings of Rootless Podman.