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.

Tools like podman, skopeo, and 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 docker command 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.

  1. Install RHEL: If you are ready to begin, you can start by installing a Red Hat Enterprise Linux system.
  2. 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: **********
  3. 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
  4. 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
  5. Install podman-docker (optional): If you are comfortable with the docker command or use scripts that call docker directly, you can install the podman-docker package. That package installs a link that replaces the docker command-line interface with the matching podman commands instead. It also links the man pages together, so man docker info will show the podman info man 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 podman and buildah.

Here are example settings in the /etc/containers/registries.conf file:

[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 registries.conf file, 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 [registries.block] section.

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 registries.conf file.
  • If you are a regular user (rootless) running podman and related tools, you can create your own registries.conf file to override the default settings.

1.5. Running containers as root or rootless

Running the container tools such as podman, skopeo, or 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:

  1. 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.
  2. Install podman and slirp4netns: If not already installed, install the podman and slirp4netns packages:

    # yum install slirp4netns podman -y
  3. 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
  4. 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.

  5. Try a podman command: Log in directly as the user you just configured (don’t use su or 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)"
    ...
  6. 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 unshare command. 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 /var/lib/containers.
  • 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.conf file to identify container registries available when you use podman to 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
  • An on-going list of shortcomings of running podman and related tools without root privilege is contained in Shortcomings of Rootless Podman.