A Simple Executable Container

A Simple Executable Container

By Langdon White November 7, 2023

Getting started with containers? One cool way to start is by making a container that can run an application that is unavailable on your host operating system.

First up, you need to get a container runtime installed. I prefer podman but docker will work as well. For the simplest installation experience, I would recommend the desktop variants:

Once you have those installed, you can almost always use podman and docker interchangeably on the command line. We will be using the command line because, at the time of writing, Docker Desktop doesn’t support building containers in the GUI.

First up, make a new directory somewhere and create a file called Containerfile. Note the lack of extension you Windows users! Windows really doesn’t like creating files with no extension so be sure to make sure it doesn’t add .txt or something. You may have heard of a Dockerfile before but the two filenames are also interchangeable. However, you may have a lot more luck googling “Dockerfile” because it has been around longer. As a quick side bar, we use Containerfile because all the tools support a shared specification created by the Open Container Initiative (OCI) called the OCI Image Format Specification. If you want to learn more, you should probably wait, but you can go here if you really want to :).

Creating the Containerfile

OK, so now you have your file. At the top of the file, add the following line:

FROM fedora

What this is saying is we are going to base our container on an image of Fedora, a Linux distribution. In the above, FROM is the instruction and is typically capitalized. We could also use a smaller base image like fedora-minimal but we are going as simple as possible for this tutorial.

Next, we need to add our cool app and we use the Fedora package manager dnf to do so. You may have used a package manager in the past (e.g. brew, apt, choco, npm, pip) but did not realize that this is a whole class of software. If you want to learn about them, they are really interesting, you can check out the Wikipedia page. Now add the following line:

RUN dnf install -y cowsay

As you might imagine, dnf won’t install something without confirmation by default. As a result, we need to pass -y to get it to install without confirmation. Why do we need this you may ask? Well, when we build our container it is not an interactive process so we can’t say “Yes” to dnf.

Now you may ask, what is cowsay? Well, you can look for yourself, or wait for the reveal!!

Now let’s do the last line of our Containerfile. Here it is:

ENTRYPOINT ["cowsay"]

Here we have what the container should do when it launches. Specifically, we want the container to launch cowsay and pass it any parameters that were on the command line. We will get to more on that in a minute.

Building the Container Image

OK, now save your file and open a command line. Let’s build the container.

podman build -t simple-cowsay .

As I said before, you can swap podman for docker depending on what you installed. Fair warning, this might take awhile, might be time for a coffee. You should now see an output like the following (not exactly but similar):

STEP 1/3: FROM fedora
STEP 2/3: RUN dnf install -y cowsay
Updating and loading repositories:
 Fedora 38 - x86_64 - Updates           100% | 372.7 KiB/s |  11.4 MiB |  00m31s
 Fedora 38 openh264 (From Cisco) - x86_ 100% | 899.0   B/s |   6.5 KiB |  00m07s
 Fedora 38 - x86_64                     100% |   2.1 MiB/s |  34.5 MiB |  00m16s
Repositories loaded.
Package                       Arch   Version              Repository      Size
Installing:
 cowsay                       noarch 3.7.0-7.fc38         fedora      72.5 KiB
Installing dependencies:
 groff-base                   x86_64 1.22.4-11.fc38       fedora       3.8 MiB
<snip />
 perl-vars                    noarch 1.05-497.fc38        updates      4.8 KiB
Installing weak dependencies:
 perl-NDBM_File               x86_64 1.15-497.fc38        updates     29.7 KiB

Transaction Summary:
 Installing:       62 packages

Downloading Packages:
[ 1/62] perl-Carp-0:1.52-490.fc38.noarc 100% |  13.2 KiB/s |  28.8 KiB |  00m02s
<snip />
[62/62] perl-NDBM_File-0:1.15-497.fc38. 100% |  30.1 KiB/s |  23.6 KiB |  00m01s
--------------------------------------------------------------------------------
[62/62] Total                           100% | 321.9 KiB/s |   8.5 MiB |  00m27s

Verifying PGP signatures

Running transaction
[1/2] Verify package files              100% |   1.6 KiB/s |  62.0   B |  00m00s
[2/3] Prepare transaction               100% |   2.3 KiB/s |  62.0   B |  00m00s
[3/4] Installing ncurses-0:6.4-3.202301 100% |  38.1 MiB/s | 624.1 KiB |  00m00s
<snip />
>>> Stop trigger-install scriptlet: glibc-common-0:2.37-1.fc38.x86_64
--------------------------------------------------------------------------------
[64/64] Total                           100% |  54.3 MiB/s |  30.1 MiB |  00m01sRemoved 82 files, 11 directories. 0 errors occurred.
--> e010c8ceb6f7
STEP 3/3: ENTRYPOINT ["/bin/cowsay"]
COMMIT simple-cowsay
--> 0afbf280e77a
Successfully tagged localhost/simple-cowsay:latest

Running the Container

Once that completes, let’s run it!

podman run -it simple-cowsay 'Cows are AWESOME!!'

Now you can play with it to your heart’s content!

A Little Bit Extra

If you want to do a slightly more advanced version, you can also clean up the container after the installation of cowsay. When you create a container image, each line in the Containerfile is independent and creates a layer that is carried through to the final image. When we install things in the container image using the package manager, the package manager has to download all the dependency information to figure out what the thing you want to install needs. As you might imagine, this can be a lot of content and it is a permanent part of the container image after that layer. As a result, it is recommended that you remove the content you don’t need after the installation. In order to do that we add dnf clean all -y to the installation line. We need to replace the installation line like this:

RUN dnf install -y cowsay && dnf clean all

The RUN instruction is just the equivalent of running the command in Linux. In Linux, the && just links two commands together and if the first one is successful, the second one runs. Now before you rebuild the container, run podman images and note the size of your simple-cowsay container. Now rebuild the container and see how much smaller it is by running podman images again.

The Whole Shebang

The whole file, just in case:

FROM fedora
RUN dnf install -y cowsay && dnf clean all
ENTRYPOINT ["cowsay"]
Back to Blog
Link copied!