Building and Tag Containers
1. Simple Dockerfile with Ubuntu
The name Dockerfile is special to container engines. It contains a specification of how to build layers onto an image to add user functionality.
Add the following to a file named Dockerfile
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl jq
Build it:
podman build -t my-ubuntu:v1.0.0 .
You can have multiple Dockerfiles in a directory, but this is uncommon. If you do, you can target a specific Dockerfile using -f
. This is also useful if the Dockerfile is in a different directory than the one you're currently in. Remember, the container and images are stored in the /scratch/$USER/.local/share/containers directory - not the current directory.
curDir=$(pwd)
cd ..
podman build -f $curDir/Dockerfile -t my-ubuntu:v1 .
cd $curDir
2. Push Your Image
To push to DockerHub, you must have an account and know your <username>
. You will also need to create a repository using the web API. You will also need to tag your newly created image with the correct tag including docker.io
and <username>
.
- You will need to login after creating the my-ubuntu repository.
podman login docker.io
podman tag my-ubuntu:1.0.0 docker.io/<username>/my-ubuntu:1.0.0
podman push docker.io/<username>/my-ubuntu:1.0.0
To CodeCR:
podman login codecr.jlab.org
podman tag my-dev:alma9.5 codecr.jlab.org/<git_repo>/my-ubuntu:1.0.0
podman push codecr.jlab.org/<git_repo>/my-ubuntu:1.0.0
ℹ️ The container image repository in CodeCR is attached to the git repository of the same name.
3. Container Build Context
The .
at the end of the build command refers to the build context. In an example where you copy a piece of code, you may want to COPY
from the local directory, or a relative directory .
. Then you would copy that to the container.
Add the following to a file named Dockerfile.second
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl jq
COPY tempFile .
touch tempFile
podman build -f Dockerfile.second -t my-ubuntu:v1.0.0 .
curDir=$(pwd)
cd ..
podman build -f $curDir/Dockerfile.second -t my-ubuntu:v1.0.0 .
cd $curDir
- This leads to an error because the tempFile does not exist in the current build context, which is up a directory from Dockerfile.second:
..
⚠️ We overwrote the container image at my-ubuntu:v.1.0.0! This is not great, did you save the container image somewhere before overwriting it? ✅
4. Adding another Layer to a Container
Let us now create two layers by splitting the RUN command. Each command in the Dockerfile is a new layer.
FROM ubuntu:24.04
RUN apt-get update
RUN apt-get install -y curl jq
- It is best to use a new tag in case you want to make comparisons to other versions of the software or containers.
podman build -t my-ubuntu:v1.0.1 .
ℹ️ The version tag is incremented from v1.0.0. A patch number may increment when no minor changes were made, and no major changes to the API are expected. This is commonly used for apps developed and deployed in containers. As an exmaple, if a simple security patch is made, nothing user-facing changes, this is likely a patch. If some small feature changes, but the way the code is interacted with stays the same, the minor version may increment (second number). For a change to the API, a major incrementation number is typically used (first number). For more information this topic, check out the ROOT Scientific Projects. ⚠️ Always ensure you have pushed your containers to a container registry before overwriting them!
Now that we have two container images, lets push them both to the container registry. Next lets see what the differences are!
5. Understand Layers
Each RUN
, COPY
, or ADD
line adds a layer:
RUN dnf install -y git cmake gcc-c++ make
This will be one layer above the base.
Use podman history <image>
to see the differences and optimize layers.
ℹ️ Use the -no-trunc for no truncation, so you can see the entire layer SHA and size.
sdiff --suppress-common <(podman history <image_1>) <(podman history <image_2>)
Notice in the output, the image v1.0.1 has an additional layer that corresponds to the second run command. Note that neither SHA in the new container match the first SHA. This is because the two commands differ in their structure.
ℹ️ It is convenient when changing only lower layers as anything that would produce the same SHA can be skipped.
6. Create a latest
tag
By default podman and docker will search for a container image tag of latest
. If this does not exist, a default image cannot be selected. You can add a latest tag to an image you created.
podman tag docker.io/<username>/my-ubuntu:v1.0.1 docker.io/<username>/my-ubuntu:latest
ℹ️ Remember to push the container to your remote repository! Don't forget to re-label latest. This can quickly become out of date. It is best to manage the container lifecycle using a CI pipeline, this can be done with Kaniko on the Jefferson Lab GitLab instance.
7. Clean Up
After testing, feel free to delete:
podman image rm my-ubuntu:v1.0.0
podman image rm my-ubuntu:v1.0.1
Go ahead and remove your DockerHub or CodeCR repository.