Skip to main content
  1. Posts/

Secure and Lightweight containers with Red Hat

·905 words·5 mins· loading · loading ·
Author
Serena Sensini
Enterprise Architect @ Dedalus spa | Writer @ Apogeo | Founder @ TheRedCode.

Why
#

The release of applications through lightweight containers has practical advantages, as the images contain all the dependencies necessary for the correct functioning of the application. However, the benefits of containerization can be lost if these images are too large and therefore require several minutes for the application to start.

In this post, we’ll see how to use Red Hat’s Universal Base Images (UBI) as a base to build images for your containers that are lightweight and secure for your applications.

Create Applications
#

Red Hat provides basic images for building cloud-based applications and web applications in containers. With these images, reliability, security, performance, and image lifecycle features are already built in and verified by people working in this company, so you can create a containerized application using a UBI image, push it to your preferred registry, easily share it, and distribute it on platforms other than Red Hat.

What they are
#

Each UBI image is based on Red Hat Enterprise Linux (alias RHEL), the most widely used enterprise-level Linux distribution of the last two decades. Building the container image on an RHEL software base ensures that the image is reliable, secure, and freely distributable. You don’t need to be a Red Hat customer to use or redistribute UBI images: just use them and let Red Hat manage the base images for you at no cost.

Where to find them
#

They are readily available on both the Red Hat Container Catalog and the official Red Hat repository on Docker Hub.

If we were to choose between the two options, we should prefer to use the Red Hat Catalog console because it displays various information such as image size, version, security checks, the list of installed packages, the Dockerfile, and various options available for pulling the image.

UBI Example

Which image to use
#

Red Hat’s Universal Base Images are offered in different formats:

  • Micro: a reduced image that uses the underlying host’s package manager to install packages, typically using Buildah or a multi-stage build with Podman.
  • Minimal: defines a reduced image that uses microdnf as the package manager.
  • Standard: an image designed to be the base layer for all containerized applications, middleware, and utilities.
  • Init: designed to run a system with a process ID of 1 (corresponding to the Linux init process) to run multiple services within a container.

Example
#

Let’s look at a small use case for Python: we’ll use a sample application that we’ll package into a UBI image.

The code for the sample applications, including the Dockerfile, is available on this GitHub repository.

Here’s the Dockerfile:

FROM registry.access.redhat.com/ubi8/ubi

RUN yum install -y python3.11-pip-wheel  python3.11-wheel python3.11-pip;

WORKDIR /app

COPY ./requirements.txt ./app ./

RUN mkdir -p /.local; \
    chown -R 1001:0 /.local; \
    chmod -R ug+rwX /.local; \
	pip3 install -r requirements.txt; 

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

For the Python example, we use the official Red Hat UBI standard base image, version 8.

The yum command installs the Python executable, while the WORKDIR command specifies the directory where the application is located within the container image, and the RUN command installs dependencies.

The COPY command copies the Python requirements file into the UBI image, which will then be used by the RUN command to install dependencies.

The EXPOSE command specifies the port on which the application will listen, usually 8000 for FastAPI.

Finally, the CMD ommand specifies the command that will be executed when the container is run.

Below are the commands to build and run the image:

docker build -t python-ubi8 .

docker images | grep -i python-ubi8

docker run -it -p 8000:8000 -d python-ubi8

The cURL command should return the following response:

curl -vk http://localhost:8000
>>>
*   Trying ::1:8000...
* TCP_NODELAY set
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
  < HTTP/1.1 200 OK
  < date: Mon, 19 Jun 2023 09:22:48 GMT
  < server: uvicorn
  < content-length: 18
  < content-type: application/json
  <
* Connection #0 to host localhost left intact
  {"Hello":"World!"}

The final size of the image is only 320 MB:

$ docker images
>>>
REPOSITORY              TAG     IMAGE ID       CREATED          SIZE
python-ubi8             latest  50c12e1ca549   55 minutes ago   320MB

Clearly, these sizes could be further reduced by using a minimal UBI image, perhaps with pre-installed Python, as in the following example:

FROM registry.access.redhat.com/ubi8/ubi-minimal

RUN microdnf install -y python3

WORKDIR /app

COPY ./requirements.txt ./app ./

RUN python3 -m pip install -r /app/requirements.txt

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

In this case, the sizes are halved since unnecessary packages have already been removed:

$ docker images
>>>
REPOSITORY              TAG     IMAGE ID       CREATED          SIZE
python-ubi8             latest  c4f0d7e3049c   8 minutes ago   161MB

Conclusions
#

The use of UBIs offers greater reliability, security, and peace of mind for your containerized applications.

Moreover, you can freely distribute containerized applications based on UBI to your friends (and enemies) on both Red Hat and non-Red Hat platforms, benefiting from the security checks performed periodically.

In the example seen earlier, we used a simple UBI8, but there are already ready-made ones with Python and other languages pre-installed and configured by default: why not give it a try?

Useful Resources
#


Original post published on TheRedCode.it