Building containers with Buildah.
Published: 2023-06-20 17:37:44

---
title: Building containers with Buildah.
published: true
date: 2023-02-13 17:13:34 UTC
tags: 
canonical_url: https://carlosmv.hashnode.dev/building-containers-with-buildah
---

DISCLAIMER: This is not a comprehensive article about Buildah or Podman. It explains how to use Buildah to build images and how to build containers.

I write this article to document the process of building an image, and containers that runs Python and a Django application.

We use [Buildah](https://github.com/containers/buildah) for building containers, for running containers we will use [Podman](https://docs.podman.io/en/latest/).

I will not explain Podman, we are going to use it to run a container with a Django App in it.

Buildah works on several Linux distributions. Is not supported on Windows or Mac platforms. But, it can be installed on Windows via WSL.

### Requirements

- A Linux Distribution or WSL with a Linux distribution installed.

- Podman installed.

- Buildah installed.

- Python installed.

### What is Buildah?

Buildah is a command line tool for efficiently and quickly building [**Open Container Initiative**](https://www.opencontainers.org/) (OCI) compliant images and containers.

As Tom Sweeney says in his [article](https://buildah.io/blogs/2017/06/22/introducing-buildah.html) post it on the Buildah website, Buildah simplifies the process of creating, building, and updating images while decreasing the learning curve of the container environment.

One of the differences between Buildah and Docker is there is no requirement for a container runtime daemon to be running on your system.

According to its README, The Buildah provides a command line tool that can be used to:

- Create a working container, either from scratch or using an image as a starting point

- Create an image, either from a working container or via the instructions in a Dockerfile

- Images can be built in either the OCI image format or the traditional upstream docker image format

- Mount a working container's root filesystem for manipulation

- Unmount a working container's root filesystem

- Use the updated contents of a container's root filesystem as a filesystem layer to create a new image

- Delete a working container or an image

- Rename a local container

### Installation

I have Ubuntu installed on WSL2, the command to install Buildah is:

```
# Ubuntu 20.10 and newer
sudo apt-get -y update
sudo apt-get -y install buildah

```

If you have any other Linux Distribution, here are the [Installation Instructions](https://github.com/containers/buildah/blob/main/install.md).

To install Podman:

```
# Ubuntu 20.10 and newer
sudo apt-get -y update
sudo apt-get -y install podman

```

### Building a container

After installation, we can verify if there are images installed by writing this command in our command line:

```
buildah images

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676048544302/021ab2a6-36cf-493a-bbb2-66bfcf7b390f.png)

Right now I have two images installed.

So, I will remove them using the following command:

```
buildah rmi <IMAGE ID>

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676052143805/882b4c92-3cec-46e2-b306-e19dd987c1b7.png)

Now I have no images installed.

Also, we can see a list of working containers by running this command:

```
buildah containers

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676048754562/bd108d1b-f3d5-464c-828c-bd3ed747dbd4.png)

As we can see, there are no working containers.

Now, let's create a new container.

To be consistent with its [tutorial](https://github.com/containers/buildah/blob/main/docs/tutorials/01-intro.md). We will create a working container based on a Fedora image.

```
container=$(buildah from fedora)

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676058491296/20f973ba-5ce7-470b-b8b5-7f709bcbf23f.png)

We can see we have an image installed running the `buildah images` command.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676058755610/c9846d41-8eab-4206-a93f-bb59dd8f9db9.png)

Also, we have a working container.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676058854482/cae405e3-ad81-4c9b-a9f8-f83fb2e05ba8.png)

Let's install Python3 in our container. We run the following command:

```
# buildah run $container -- dnf -y install python3

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676059466219/e33cf9be-f512-4769-9fe3-82071b2605e0.png)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676059575217/446dc336-e47b-48cc-abc1-21a7ad0371f5.png)

As we can see, there are no working containers.

We use the `run` command to execute commands inside a container. It emulates the RUN command in a Dockerfile. In this case, we install Python with `dnf`, which is a package manager on Fedora.

To make sure we have Python installed we run the following command:

```
 buildah run $container python3 --version

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676060415373/2314676f-d815-4d08-9150-c2ce4505b626.png)

After Python is installed, we install Pip.

```
# buildah run $container -- dnf -y install pip

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676059745386/68910f88-9210-4343-b57b-f51a8eebf9d6.png)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676059797841/da6502ca-89d8-4a5e-8b9d-ea023a083c83.png)

Now, we can install python packages and frameworks inside our container. I want to install Django in a container. But I want to do it in another container. So, before installing Django, we will create another container.

```
buildah from <IMAGE ID>

```

The [documentation](https://github.com/containers/buildah/blob/main/docs/buildah-from.1.md) says, the `from` command creates a new working container either from scratch or from an image.

We should see two containers if we run the `buildah containers` command.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676060494323/6ca53aee-7662-40c5-8dc4-bbd97d59e529.png)

Now, we should be able to install Django.

I will install Django inside the last container we created. So, we have to pass a container ID after the `run` command, to say to Buildah which container we want to execute.

```
buildah run <Container ID> pip install django

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676148784696/6baebeb7-09de-4c59-ac15-69b880de9906.png)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676148956603/420bd548-ba8a-4aba-8052-ce389f8ac3ca.png)

Now we can create Django Project inside our container.

```
buildah run <Container ID> django-admin startproject django-demo

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676149732681/78bf601d-e332-45cf-a1b4-d192b63a34b8.png)

To run a Django app, we have to go to the project folder and run the command: `python3` [`manage.py`](http://manage.py) `runserver` . I supposed it will work to run the command: `buildah run 383fa250e17e cd django_demo python3` [`manage.py`](http://manage.py) `runserver` . But, it gave me an error.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676150630479/f6b062c1-9257-4735-a462-0de2c7bafc6a.png)

To be able to run a Django server container, we have to use [Podman.](https://docs.podman.io/en/latest/)

Podman is a tool to run containers and has a feature that allows us to expose the port of our Django App. With Buildah we can't.

But we can manipulate our container's files.

### Mounting a container

We have to mount the container to access its files.

```
mountpoint=$(buildah mount $container)

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676151493394/cff16aa6-cb9d-42f8-8ffa-b3ba42182e7d.png)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676151667248/8e8c520a-088a-4d2d-a05c-1803045042b5.png)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676151751165/15a385eb-feee-4ca7-9a73-03e5e0eb1d2b.png)

The [documentation](https://github.com/containers/buildah/blob/main/docs/buildah-mount.1.md) says that the `mount` command mount a working container root's filesystem. With this command, we can manipulate the files inside a working container.

Let's create a python file, and copy it to our container. It will be a simple file.

hello\_world.py

```
print("HELLO FROM A CONTAINER")

```

To copy the file into a container, we run this command:

```
cp folder/hello_world.py $mountpoint/tmp

```

We copied the `hello_world.py` file to the `tmp` folder of the working container.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676158335728/c9428b1b-1b23-4b9f-aea1-4f699b4badbb.png)

Now, if we run `python3 $mountpoint/tmp/hello_world.py`, we should see the output on our command line.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676159041436/dfeb8ded-bbe3-45ac-bf1c-0fade8cd1dd3.png)

We are just using the Python interpreter of our machine to execute a Python file inside the container.

But, what if we want to create a container for a Django App like we usually do when using Docker?

Well, we can use a Dockerfile.

### Building from a Dockerfile.

We will use the following Dockerfile to create a Django application image.

```
FROM python:3.11

RUN mkdir /code
WORKDIR /code
RUN pip install --upgrade pip
COPY requirements.txt /code/

RUN pip install -r requirements.txt
COPY . /code/

EXPOSE 8000

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

```

We use the bud command to build an image from a Dockerfile.

You can use a blank Django application. And paste the Dockerfile inside the project folder, alongside the `requirements.txt` file.

```
django_buildah/
    django_buildah/
    manage.py
    Dockerfile
    requirements.txt


buildah bud -t django_buildah .

```

We use the command `bud` to create an image from the Dockerfile. The `-t` flag is to assign a name to the image, in this case, I used "django\_buildah". The last argument is the location of the Dockerfile. I executed the command inside the project folder and the `.` indicates to Buildah to use the Dockerfile inside `python_projects/django_buildah/django_buildah`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676216148033/8b2b23a1-6128-4717-a1a6-3265e0ed5e79.png)

With this Django image, we can create a container.

```
buildah from <Django Image ID>

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676212189961/f4b18430-5e6c-4178-b241-cf23b8cd6417.png)

As we can see in the image above, my Django image ID is `e96d30625b63`, then I created a container from it. Using the `containers` command we can see Buildah created a container. And the container ID is `6b050b955575`.

I want to use the `run` command, one more time.

```
buildah run <Container ID> python3 manage.py runserver

```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676212556506/65bda979-e85f-4e23-800d-07e32b5c15a2.png)

But because there is no port exposed, we have the following issue:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676213695819/a942a7a1-d7b9-43f9-80f6-1622b051eea4.png)

### Running a container with Podman

I want to try Podman, to see how it works.

```
podman run --rm -p 8123:8000 django_buildah

```

We use the run command to run a container, it emulates docker run command in functionality. The --rm flag indicates to Podman that it has to remove the container when we shut it down. And the -p flag is to map a port, and the last argument is the name of the image from which we want to create a container and run it.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1676214760960/1151dcfe-74af-44bb-9167-2a3d5ac9379e.png)

Now it works. If we go to `localhost:8123`, we should see the Django Welcome Page.

### Conclusion

I found interesting the approach of having a CLI tool to build images and containers, and another to run containers. I think they are good alternatives to Docker and they are worth trying.

Both CLI tools were easy to use thanks to their documentation and tutorials.

I apologize for the messiness of this article. The intention was to document the process of building a container with Buildah and see its output in the command line.

Thank you for taking the time to read this article.

If you have any recommendations about other packages, architectures, how to improve my code, my English, or anything; please leave a comment or contact me through [**Twitter**](https://twitter.com/Carlos_marcv), or [**LinkedIn**](https://www.linkedin.com/in/carlos-marcano-a2135a134/).

### References

[Introducing Buildah.](https://buildah.io/blogs/2017/06/22/introducing-buildah.html)

[Buildah's GitHub page.](https://github.com/containers/buildah)

[Buildah Tutorial 1](https://github.com/containers/buildah/blob/main/docs/tutorials/01-intro.md).

[Installation Instructions.](https://github.com/containers/buildah/blob/main/install.md)

[Podman documentation](https://docs.podman.io/en/latest/)

[Podman's commands.](https://docs.podman.io/en/latest/Commands.html)