Build custom application images

Create application-specific container images by using Red Hat Hardened Images as a secure foundation. Use container files to customize images and to create secure images with your applications for production.

Build a custom container image with Red Hat Hardened Images

Build custom images to bundle applications with specific dependencies by using Red Hat Hardened Images as a secure foundation. This ensures consistent, reproducible environments and a minimal attack surface across development and production.

Before you begin

  • The podman package is installed.
  • You know which Red Hat Hardened Image your custom image should be based on.

Procedure

  1. Create a project directory. For example:
    $ mkdir ~/project/
  2. Copy the files that you want to add to the image to your project directory:
    $ cp example.py ~/project/
  3. Create a file named ~/project/Containerfile, that references the Red Hat Hardened Image in the FROM instruction. For example:
    FROM registry.access.redhat.com/hi/python:3.14
    COPY example.py /app/
    WORKDIR /app
    CMD ["python3", "example.py"]

    This example builds a custom image by copying the example.py file into the /app/ directory within the image. The Containerfile then sets this directory as the working directory. Finally, it defines the default command to run the script by using the python3 interpreter when the container starts.

  4. Build the custom image:
    $ podman build -t <image_name> ~/project/

    The -t <image_name> option specifies the name of the image after the build process.

  5. Optional: Display the list of images:
    $ podman image list
    REPOSITORY              TAG     IMAGE ID      CREATED        SIZE
    localhost/<image_name>  latest  2ec87ace0cda  2 minutes ago  107 MB
  6. Create a container that uses the image. For example:
    $ podman run --rm <image_name>:latest

Optimize the image size by using multi-stage builds

Reduce the final size of your application image by separating the build environment from the runtime environment. With multi-stage builds you can compile your code in a stage with extra tools available and then copy only the resulting binary file into a minimal Red Hat Hardened Image.

Before you begin

  • The podman package is installed.
  • You know which Red Hat Hardened Image your custom image should be based on.
  • The Go source code that you want to compile and use in this example is stored in the ~/project/src/ directory.

Procedure

  1. Create a file named ~/project/Containerfile, that references the Red Hat Hardened Images in the FROM instructions. For example:
    # Build stage:
    # Use a builder variant and compile the application
    FROM registry.access.redhat.com/hi/go:latest-builder AS builder
    
    # Use a bind mount to access the source code on the host, and compile the Go application
    RUN --mount=type=bind,source=./src/,target=/src,rw go build -o /tmp/example /src/example.go
    
    
    # Runtime stage:
    # Use a minimal base image for the compiled binary
    FROM registry.access.redhat.com/hi/core-runtime:latest
    
    # Copy the application from the builder image to the runtime image
    COPY --from=builder /tmp/example /app
    ENTRYPOINT ["/app"]

    This example uses the go:latest-builder image variant to compile a Go application. To access the source code on the host, the image uses a bind mount.

    Afterwards, the Containerfile copies the binary file from the builder image to the core-runtime:latest image. This is the image with your application that you later use in production.

  2. Build the custom image:
    $ podman build -t <image_name> ~/project/

    The -t <image_name> option specifies the name of the image after the build process.

  3. Optional: Display the list of images:
    $ podman image list
    REPOSITORY             TAG     IMAGE ID      CREATED        SIZE
    localhost/<image_name>  latest  cbfeaf2405c8  3 minutes ago  34.3 MB
  4. Create a container that uses the image. For example:
    $ podman run --rm <image_name>:latest

Run commands with elevated privileges in images

By default, Red Hat Hardened Images run as a non-root user. If you use multi-stage builds and require root permissions during the builder stage, you can temporarily switch to the root user in the Containerfile.

Procedure

  1. Identify the user ID (UID) of the builder image:
    $ podman inspect --format='{{.Config.User}}' registry.access.redhat.com/hi/<builder_image>
    • If the command returns 0, the container runs as root.
    • If the command returns a user name or a nonzero UID, such as 65532, the container runs as a non-root user.
  2. If the image runs as a user and you require root permissions, for example to install dependencies, you must temporarily switch to the root user in the Containerfile:
    ...
    # Switch to the root user
    USER root
    
    <commands_that_require_root_permissions>
    
    # Return to the non-root user
    USER ${CONTAINER_DEFAULT_USER}
    ...

    For example, when you require Python headers during the builder stage, temporarily switch to the root user, install the packages, and return to the default user of the image:

    FROM registry.access.redhat.com/hi/python:3.14-builder
    USER root
    RUN dnf install -y python3.14-devel && dnf clean all
    USER ${CONTAINER_DEFAULT_USER}