1. Building from a Dockerfile with Podman

Our recommendation is that, if you want to build a container from scratch (e.g. using a Dockerfile), build that container using podman build. To do so, you'll want to

  • A. Build your container with podman.
  • B. Save the container to a docker `.tar` archive.

This guide covers building an image by hand, if you're interested in automating your build and persisting the image in LC's Gitlab container registry, check out this guide.

In greater detail:

A. Building with podman

If you haven't already you'll first have to configure your environment by running the enable-podman.sh script. On LC systems, it lives at /collab/usr/gapps/lcweg/containers/scripts/enable-podman.sh, so in a bash terminal you would run

/collab/usr/gapps/lcweg/containers/scripts/enable-podman.sh

It's a best-practice to do builds on an allocated compute node so that your build doesn't interfere with other users sharing the login nodes. Once you have an allocation, you can build the container with podman build, specifying the Dockerfile with -f and the tag of the container created with -t. Using the Dockerfile Dockerfile.ubuntu and tag myimage, we'd run

podman build -f Dockerfile.example -t myimage

To try this yourself, you can grab the contents of Dockerfile.example.

After podman build ..., run podman images to see your container image.

If you're running each step interactively, the whole build might look something like this:

janeh@pascal43:~$ . /collab/usr/gapps/lcweg/containers/scripts/enable-podman.sh
janeh@pascal43:~$ podman build -f Dockerfile.example -t myimage
STEP 1/3: FROM almalinux:8
Resolved "almalinux" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull docker.io/library/almalinux:8...
Getting image source signatures
Copying blob 2609da11fd88 done   |
Copying config f1218159f1 done   |
Writing manifest to image destination
STEP 2/3: RUN dnf update -y
...
--> bad7ec9d60d8
STEP 3/3: RUN dnf install -y python3.11
...
COMMIT myimage
--> 18ad68021579
Successfully tagged localhost/myimage:latest
18ad680215797a5853c04e6f621049cd29453057b76421547c243d9629847039
janeh@pascal43:~$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED             SIZE
localhost/myimage            latest      18ad68021579  About a minute ago  436 MB
docker.io/library/almalinux  8           f1218159f16a  5 weeks ago         196 MB

 

B. Saving the container to a docker archive

 

By default, the container files created on a compute node will be deleted when the allocation ends. After building and before the allocation ends, you need to explicitly save the container! For example, immediately after building the container in the above, if we terminate the allocation and start a new allocation, we see no remaining images with podman images:

janeh@pascal83:~$ salloc -N 1 -t 1
salloc: Pending job allocation 1535430
salloc: job 1535430 queued and waiting for resources
salloc: job 1535430 has been allocated resources
salloc: Granted job allocation 1535430
salloc: Waiting for resource configuration
salloc: Nodes pascal129 are ready for job
janeh@pascal129:~$ podman images
REPOSITORY   TAG   IMAGE ID   CREATED   SIZE
janeh@pascal129:~$

Instead, use the syntax

podman save TAG_NAME > OUTPUT_FILENAME

to save the container after building. For a container with tag myimage, we might run

podman save myimage > myimage.tar

after building, as below:

janeh@pascal7:~$ podman build -f Dockerfile.example -t myimage
...
janeh@pascal7:~$ podman images
REPOSITORY                   TAG      IMAGE ID       CREATED          SIZE
localhost/myimage            latest   0ef15bc4f175   10 seconds ago   436 MB
docker.io/library/almalinux  8        f1218159f16a   5 weeks ago      196 MB 
janeh@pascal7:~$ podman save myimage -o myimage.tar
Copying blob a5d3eecefb86 done   |
Copying blob 6c6bcdeaf3b8 done   |
Copying blob 57ec06e597cb done   |
Copying config 18ad680215 done   |
Writing manifest to image destination

 

This creates the file myimage.tar. Once you've saved your image, you can run it later with "podman run docker-archive:./myimage.tar ..." The "docker-archive:" portion of the image name tells podman that the image you want to run is stored in a tarfile at the given path in the filesystem.

You may also load the image back into the image store using the "podman load" command:

janeh@pascal23:~$ podman load -i myimage.tar
Getting image source signatures
Copying blob 57ec06e597cb done   |
Copying blob a5d3eecefb86 done   |
Copying blob 6c6bcdeaf3b8 done   |
Copying config 18ad680215 done   |
Writing manifest to image destination
Loaded image: localhost/myimage:latest
janeh@pascal23:~$ podman images
REPOSITORY                   TAG      IMAGE ID       CREATED          SIZE
localhost/myimage            latest   0ef15bc4f175   20 minutes ago   436 MB

2. Special Considerations

A. Debian/Ubuntu containers and setgroups errors

You'll need to specify some additional arguments when building from an image based off of a Debian-like distribution, such as Ubuntu.

podman build --userns-uid-map=0:0:1 --userns-uid-map=1:1:1999 --userns-uid-map=65534:2000:2 ...

You'll see error messages that look like this without those arguments:

STEP 3/6: RUN apt-get update && apt-get install -y curl
E: setgroups 65534 failed - setgroups (22: Invalid argument)
E: setegid 65534 failed - setegid (22: Invalid argument)
Reading package lists...
E: setgroups 65534 failed - setgroups (22: Invalid argument)
E: setegid 65534 failed - setegid (22: Invalid argument)
E: Method gave invalid 400 URI Failure message: Failed to setgroups - setgroups (22: Invalid argument)
E: Method gave invalid 400 URI Failure message: Failed to setgroups - setgroups (22: Invalid argument)
E: Method http has died unexpectedly!
E: Sub-process http returned an error code (112)
Error: building at STEP "RUN apt-get update && apt-get install -y curl": while running runtime: exit status 100