Red Hat Training

A Red Hat training course is available for RHEL 8

Chapter 11. Building container images with Buildah

Buildah facilitates building OCI container images that meet the OCI Runtime Specification. With Buildah, you can create a working container, either from scratch or using an image as a starting point. You can create an image either from a working container or via the instructions in a Dockerfile. You can mount and unmount a working container’s root filesystem.

11.1. The Buildah tool

Using Buildah is different from building images with the docker command in the following ways:

No Daemon
No container runtime is needed to use Buildah.
Base image or scratch
You can build an image based on another container or start with an empty image (scratch).
Build tools are external

Does not include build tools within the image itself. As a result, Buildah:

  • Reduces the size of built images.
  • Increase security of images by excluding software (e.g. gcc, make, and yum) from the resulting image.
  • Allows to transport the images using fewer resources because of the reduced image size.
Compatibility
Buildah supports building container images with Dockerfiles allowing for an easy transition from Docker to Buildah.
Note

The containers-storage location that Buildah uses by default is the same as the CRI-O container engine uses for storing local copies of images. As a result, the images pulled from a registry by either CRI-O or Buildah, or committed by the buildah command, are stored in the same directory structure. Currently, however, CRI-O and Buildah cannot share containers, though they can share images.

11.2. Installing Buildah

Install the Buildah tool using the yum command.

Procedure

  • Install the Buildah tool:

    # yum -y install buildah

Verification

  • Display the help message:

    # buildah -h

11.3. Getting images with Buildah

Use the buildah from command to create a new working container from scratch or based on a specified image as a starting point.

Procedure

  • Create a new working container based on the registry.redhat.io/ubi8/ubi image:

    # buildah from registry.access.redhat.com/ubi8/ubi
    Getting image source signatures
    Copying blob…
    Writing manifest to image destination
    Storing signatures
    ubi-working-container

Verification

  1. List all images in local storage:

    # buildah images
    REPOSITORY                                  TAG      IMAGE ID       CREATED       SIZE
    registry.access.redhat.com/ubi8/ubi         latest   272209ff0ae5   2 weeks ago   234 MB
  2. List the working containers and their base images:

    # buildah containers
    CONTAINER ID  BUILDER  IMAGE ID     IMAGE NAME                       CONTAINER NAME
    01eab9588ae1     *     272209ff0ae5 registry.access.redhat.com/ub... ubi-working-container

Additional resources

  • buildah-from man page
  • buildah-images man page
  • buildah.containers man page

11.4. Running commands inside of the container

Use the buildah run command to execute a command from the container.

Prerequisites

  • A pulled image is available on the local system.

Procedure

  • Display the operating system version:

    # buildah run ubi-working-container cat /etc/redhat-release
    Red Hat Enterprise Linux release 8.4 (Ootpa)

Additional resources

  • buildah-run man page

11.5. Building an image from a Dockerfile with Buildah

Use the buildah bud command to build an image using instructions from a Containerfile or a Dockerfile.

Note

The buildah bud command uses a Containerfile if found in the context directory, if it is not found the buildah bud command uses a Dockerfile; otherwise any file can be specified with the --file option. The available commands that are usable inside a Containerfile and a Dockerfile are equivalent.

Procedure

  1. Create a Containerfile:

    # cat Containerfile
    FROM registry.access.redhat.com/ubi8/ubi
    ADD myecho /usr/local/bin
    ENTRYPOINT "/usr/local/bin/myecho"
  2. Create a myecho script:

    # cat myecho
    echo "This container works!"
  3. Change the access permissions of myecho script:

    # chmod 755 myecho
  4. Build the myecho image using Containerfile in the current directory:

    # buildah bud -t myecho .
    STEP 1: FROM registry.access.redhat.com/ubi8/ubi
    STEP 2: ADD myecho /usr/local/bin
    STEP 3: ENTRYPOINT "/usr/local/bin/myecho"
    STEP 4: COMMIT myecho
    ...
    Storing signatures

Verification

  1. List all images:

    # buildah images
    REPOSITORY                                  TAG      IMAGE ID       CREATED              SIZE
    localhost/myecho                            latest   b28cd00741b3   About a minute ago   234 MB
  2. Run the myecho container based on the localhost/myecho image:

    # podman run --name=myecho localhost/myecho
    This container works!
  3. List all containers:

    # podman ps -a
    0d97517428d  localhost/myecho                                     12 seconds ago  Exited (0) 13 seconds ago          myecho

Additional resources

  • buildah-bud man page

11.6. Inspecting containers and images with Buildah

Use the buildah inspect command to display information about a container or image.

Prerequisites

Procedure

  • Inspect the image:

    • To inspect the myecho image, enter:

      # buildah inspect localhost/myecho
       {
          "Type": "buildah 0.0.1",
          "FromImage": "localhost/myecho:latest",
          "FromImageID": "b28cd00741b38c92382ee806e1653eae0a56402bcd2c8d31bdcd36521bc267a4",
          "FromImageDigest": "sha256:0f5b06cbd51b464fabe93ce4fe852a9038cdd7c7b7661cd7efef8f9ae8a59585",
          "Config":
          ...
           "Entrypoint": [
                      "/bin/sh",
                      "-c",
                      "\"/usr/local/bin/myecho\""
                  ],
          ...
      }
    • To inspect the working container from the myecho image:

      1. Create a working container based on the localhost/myecho image:

        # buildah from localhost/myecho
      2. Inspect the myecho-working-container container:

        # buildah inspect ubi-working-container
        {
            "Type": "buildah 0.0.1",
            "FromImage": "registry.access.redhat.com/ubi8/ubi:latest",
            "FromImageID": "272209ff0ae5fe54c119b9c32a25887e13625c9035a1599feba654aa7638262d",
            "FromImageDigest": "sha256:77623387101abefbf83161c7d5a0378379d0424b2244009282acb39d42f1fe13",
            "Config":
            ...
        "Container": "ubi-working-container",
        "ContainerID": "01eab9588ae1523746bb706479063ba103f6281ebaeeccb5dc42b70e450d5ad0",
        "ProcessLabel": "system_u:system_r:container_t:s0:c162,c1000",
        "MountLabel": "system_u:object_r:container_file_t:s0:c162,c1000",
        ...
        }

Additional resources

  • buildah-inspect man page

11.7. Modifying a container using buildah mount

Use the buildah inspect command to display information about a container or image.

Prerequisites

Procedure

  1. Create a working container based on the registry.access.redhat.com/ubi8/ubi image and save the name of the container to the mycontainer variable:

    # mycontainer=$(buildah from localhost/myecho)
    
    # echo $mycontainer
    myecho-working-container
  2. Mount the myecho-working-container container and save the mount point path to the mymount variable:

    # mymount=$(buildah mount $mycontainer)
    
    # echo $mymount
    /var/lib/containers/storage/overlay/c1709df40031dda7c49e93575d9c8eebcaa5d8129033a58e5b6a95019684cc25/merged
  3. Modify the myecho script and make it executable:

    # echo 'echo "We modified this container."' >> $mymount/usr/local/bin/myecho
    # chmod +x $mymount/usr/local/bin/myecho
  4. Create the myecho2 image from the myecho-working-container container:

    # buildah commit $mycontainer containers-storage:myecho2

Verification

  1. List all images in local storage:

    # buildah images
    REPOSITORY                                  TAG      IMAGE ID       CREATED          SIZE
    docker.io/library/myecho2                   latest   4547d2c3e436   4 minutes ago    234 MB
    localhost/myecho                            latest   b28cd00741b3   56 minutes ago   234 MB
  2. Run the myecho2 container based on the docker.io/library/myecho2 image:

    # podman run --name=myecho2 docker.io/library/myecho2
    This container works!
    We even modified it.

Additional resources

  • buildah-mount man page
  • buildah-commit man page

11.8. Modifying a container using buildah copy and buildah config

Use buildah copy command to copy files to a container without mounting it. You can then configure the container using the buildah config command to run the script you created by default.

Prerequisites

Procedure

  1. Create a script named newecho and make it executable:

    # cat newecho
    echo "I changed this container"
    # chmod 755 newecho
  2. Create a new working container:

    # buildah from myecho:latest
    myecho-working-container-2
  3. Copy the newecho script to /usr/local/bin directory inside the container:

    # buildah copy myecho-working-container-2 newecho /usr/local/bin
  4. Change the configuration to use the newecho script as the new entrypoint:

    # buildah config --entrypoint "/bin/sh -c /usr/local/bin/newecho" myecho-working-container-2
  5. Optional. Run the myecho-working-container-2 container, the newecho script should be executed:

    # buildah run myecho-working-container-2 -- sh -c '/usr/local/bin/newecho'
    I changed this container
  6. Commit the myecho-working-container-2 container to a new image called mynewecho:

    # buildah commit myecho-working-container-2 containers-storage:mynewecho

Verification

  • List all images in local storage:

    # buildah images
    REPOSITORY                                  TAG      IMAGE ID       CREATED         SIZE
    docker.io/library/mynewecho                 latest   fa2091a7d8b6   8 seconds ago   234 MB

Additional resources

  • buildah-copy man page
  • buildah-config man page
  • buildah-commit man page
  • buildah-run man page

11.9. Creating images from scratch with Buildah

Instead of starting with a base image, you can create a new container that holds only a minimal amount of container metadata.

When creating an image from scratch container, consider: A * You can copy the executable with no dependencies into the scratch image and make a few configuration settings to get a minimal container to work. * You must initialize an RPM database and add a release package in the container to use tools like yum or rpm. * If you are adding a lot of packages, consider using the standard UBI or minimal UBI images instead of scratch images.

Procedure

This procedure adds a web service httpd to a container and configures it to run.

  1. Create an empty container:

    # buildah from scratch
    working-container
  2. Mount the working-container container and save the mount point path to the scratchmnt variable:

    # scratchmnt=$(buildah mount working-container)
    
    
    # echo $scratchmnt
    /var/lib/containers/storage/overlay/be2eaecf9f74b6acfe4d0017dd5534fde06b2fa8de9ed875691f6ccc791c1836/merged
  3. Initialize an RPM database within the scratch image and add the redhat-release package:

    # yum install -y --releasever=8 --installroot=$scratchmnt redhat-release
  4. Install the httpd service to the scratch directory:

    # yum install -y --setopt=reposdir=/etc/yum.repos.d \
          --installroot=$scratchmnt \
          --setopt=cachedir=/var/cache/dnf httpd
  5. Create the $scratchmnt/var/www/html/index.html file:

    # mkdir -p $scratchmnt/var/www/html
    # echo "Your httpd container from scratch works!" > $scratchmnt/var/www/html/index.html
  6. Configure working-container to run the httpd daemon directly from the container:

    # buildah config --cmd "/usr/sbin/httpd -DFOREGROUND" working-container
    # buildah config --port 80/tcp working-container
    # buildah commit working-container localhost/myhttpd:latest

Verification

  1. List all images in local storage:

    # podman images
    REPOSITORY                                 TAG     IMAGE ID      CREATED         SIZE
    localhost/myhttpd                          latest  08da72792f60  2 minutes ago   121 MB
  2. Run the localhost/myhttpd image and and configure port mappings between the container and the host system:

    # podman run -p 8080:80 -d --name myhttpd 08da72792f60
  3. Test the web server:

    # curl localhost:8080
    Your httpd container from scratch works!

Additional resources

  • buildah-config man page
  • buildah-commit man page

11.10. Pushing containers to a private registry

Use buildah push command to push an image from local storage to the public or private repositories.

Prerequisites

Procedure

  1. Create the local registry on your machine:

    # podman run -d -p 5000:5000 registry:2
  2. Push the myecho:latest image to the localhost registry:

    #  buildah push --tls-verify=false myecho:latest localhost:5000/myecho:latest
    Getting image source signatures
    Copying blob sha256:e4efd0...
    ...
    Writing manifest to image destination
    Storing signatures

Verification

  1. List all images in the localhost repository:

    # curl http://localhost:5000/v2/_catalog
    {"repositories":["myecho2]}
    
    
    # curl http://localhost:5000/v2/myecho2/tags/list
    {"name":"myecho","tags":["latest"]}
  2. Inspect the docker://localhost:5000/myecho:latest image:

    # skopeo inspect --tls-verify=false docker://localhost:5000/myecho:latest | less
    {
        "Name": "localhost:5000/myecho",
        "Digest": "sha256:8999ff6050...",
        "RepoTags": [
            "latest"
        ],
        "Created": "2021-06-28T14:44:05.919583964Z",
        "DockerVersion": "",
        "Labels": {
            "architecture": "x86_64",
            "authoritative-source-url": "registry.redhat.io",
        ...
    }
  3. Pull the localhost:5000/myecho image:

    # podman pull --tls-verify=false localhost:5000/myecho2
    # podman run localhost:5000/myecho2
    This container works!

Additional resources

  • buildah-push man page

11.11. Pushing containers to the Docker Hub

Use your Docker Hub credentials to push and pull images from the Docker Hub with the buildah command.

Prerequisites

Procedure

  1. Push the docker.io/library/myecho:latest to your Docker Hub. Replace username and password with your Docker Hub credentials:

    # buildah push --creds username:password \
              docker.io/library/myecho:latest docker://testaccountXX/myecho:latest

Verification

  • Get and run the docker.io/testaccountXX/myecho:latest image:

    • Using Podman tool:

      # podman run docker.io/testaccountXX/myecho:latest
      This container works!
    • Using Buildah and Podman tools:

      # buildah from docker.io/testaccountXX/myecho:latest
      myecho2-working-container-2
      # podman run myecho-working-container-2

Additional resources

  • buildah-push man page

11.12. Removing images with Buildah

Use the buildah rmi command to remove locally stored container images. You can remove an image by its ID or name.

Procedure

  1. List all images on your local system:

    # buildah images
    REPOSITORY                                  TAG      IMAGE ID       CREATED          SIZE
    localhost/johndoe/webserver                 latest   dc5fcc610313   46 minutes ago   263 MB
    docker.io/library/mynewecho                 latest   fa2091a7d8b6   17 hours ago     234 MB
    docker.io/library/myecho2                   latest   4547d2c3e436   6 days ago       234 MB
    localhost/myecho                            latest   b28cd00741b3   6 days ago       234 MB
    localhost/ubi-micro-httpd                   latest   c6a7678c4139   12 days ago      152 MB
    registry.access.redhat.com/ubi8/ubi         latest   272209ff0ae5   3 weeks ago      234 MB
  2. Remove the localhost/myecho image:

    # buildah rmi localhost/myecho
    • To remove multiple images:

      # buildah rmi docker.io/library/mynewecho  docker.io/library/myecho2
    • To remove all images from your system:

      # buildah rmi -a
    • To remove images that have multiple names (tags) associated with them, add the -f option to remove them:

      # buildah rmi -f localhost/ubi-micro-httpd

Verification

  • Ensure that images were removed:

    # buildah images

Additional resources

  • buildah-rmi man page

11.13. Removing containers with Buildah

Use the buildah rm command to remove containers. You can specify containers with the container ID or name.

Prerequisites

  • At least one container has been stopped.

Procedure

  1. List all containers:

    # buildah containers
    CONTAINER ID  BUILDER  IMAGE ID     IMAGE NAME                       CONTAINER NAME
    05387e29ab93     *     c37e14066ac7 docker.io/library/myecho:latest  myecho-working-container
  2. Remove the myecho-working-container container:

    # buildah rm myecho-working-container
    05387e29ab93151cf52e9c85c573f3e8ab64af1592b1ff9315db8a10a77d7c22

Verification

  • Ensure that containers were removed:

    # buildah containers

Additional resources

  • buildah-rm man page