The Grace Period for Docker has ended. Organizations and professional will need to pay to play in Docker. Another post covers an unsuccessful attempt to move to another platform . There was some hope with minikube if running Linux images. That still did not address developing new images to run in other container runtimes.
How does one develop container images without using Docker? Buildah is a project that builds Docker/Kubernetes compatible images. Podman can run those images. Both of these application do not require root permission. This post covers some use cases and syntax for both buildah and podman. The installation of these applications will left as an exercise for the reader. Usage on Windows will need WSL installed and configured.
Build an Image (Buildah)
The nice thing about buildah is we do not need to learn any new syntax for the build file. Any Dockerfile used to create an image should work. This is even true for multi-stage build files. The only caveat with the Dockerfile is referencing the images in the file. If one uses a notation like
FROM node:14-alpine AS node
one will either have to update /etc/containers/registries.conf
to find the repository hosting the image or use a fully qualified path.
FROM docker.io/library/node:14-alpine AS node
The sample multi-stage Dockerfile builds a web front-end with a .NET backend and looks like this (names have been changed to protect the not-so-innocent):
FROM docker.io/library/node:14-alpine AS node
WORKDIR /app
COPY ./AcmeWidgets.OMS.Web ./
RUN cd ./WEB && npm install && npm run test && npm run build
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS dnet
WORKDIR /app
COPY . ./
RUN cd ./AcmeWidgets.OMS.Web && dotnet publish AcmeWidgets.OMS.Web.csproj -c Release -o /app/Output
COPY --from=node /app/wwwroot /app/Output/wwwroot/
RUN cd /app/AcmeWidgets.Tests && dotnet test -c Release --blame
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
COPY --from=dnet /app/Output ./
COPY ./Build/entry.sh .
ENTRYPOINT ["./entry.sh"]
CMD ["dotnet", "AcmeWidgets.OMS.Web.dll"]
EXPOSE 4213
The command to build an image is
> buildah bud -t AcmeWidgets/OMS:latest -f <Docker file name> <project directory>
To verify you have created a new image, issue the command:
> buildah images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/AcmeWidgets/OMS latest 0be7a36b48d9 10 seconds ago 255 MB
mcr.microsoft.com/dotnet/sdk 6.0 83ae347bcb57 3 days ago 740 MB
mcr.microsoft.com/dotnet/aspnet 6.0 69cb014b394b 3 days ago 212 MB
docker.io/library/node 14-alpine 04883debec4a 12 days ago 123 MB
One can also confirm the image creation using podman
> podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/AcmeWidgets/OMS latest 0be7a36b48d9 10 minutes ago 255 MB
mcr.microsoft.com/dotnet/sdk 6.0 83ae347bcb57 3 days ago 740 MB
mcr.microsoft.com/dotnet/aspnet 6.0 69cb014b394b 3 days ago 212 MB
docker.io/library/node 14-alpine 04883debec4a 12 days ago 123 MB
Running an image (Podman)
In addition to listing images, podman can run them. A quick example would be running an nginx image on port 8081.
> podman run -p 8081:80 nginx:latest
Error: error getting default registries to try: short-name "nginx:latest" did not resolve to an alias and no unqualified-search registries are defined in "/etc/containers/registries.conf"
Oops, we got ahead of ourselves. Our system does not have the image. One can either pull the image and run it
> podman pull docker.io/library/nginx:latest
> podman run -p 8081:80 nginx:latest
or use a fully qualified name in the run command.
> podman run -p 8081:80 docker.io/library/nginx:latest
Bonus: Building Legacy Code
I maintain multiple applications using a variety of tech stacks. Some of them are niche and a bit dated. Because of this, I do not want to install the tools on my workstation. Some of them are not available for download. Some interfere with my daily work. Virtualization is great because I can grab an image with the tool(s) I need and run it without installing it.
Let's say I have a Java 8 application built with Maven. I do not want that on my machine for a variety of reasons. I can get an image from dockerhub and build my application that way. Getting and running the image is easy enough, but I am interacting with the filesystem. Podman has ways of mounting folders just like Docker.
> podman run --mount type=bind,src=/home/cool_username/src/directory,target=/src --mount type=bind,src=/home/cool_username/.m2,target=/root/.m2 docker.io/library/maven:3.6.0-jdk-8-slim mvn clean
We will break down the command
- The mount flag tells podman a directory should be mounted into the running container. The bind type is a directory bind.
- The first bind is where the source code to compile is.
- The second bind is the local Maven cache, so it does not have to download everything every time.
- The image to run
- The command to run when the image is started
You can get crafty with this and create an interactive shell out of it. Mine looks like this
export APP_SRC=/home/cool_username/src/directory
export M2_DIR=/home/cool_username/.m2
export POD_IMAGE=maven:3.6.0-jdk-8-slim
podman run --mount type=bind,src=$APP_SRC,target=/src --mount type=bind,src=$M2_DIR,target=/root/.m2 -i $POD_IMAGE /bin/sh $@
You might note the -i
. That is to make it interactive. For more details, the podman commands are broken down here
This post has only scratched the surface of what you can do with Podman and Buildah. I hope the use cases presented here inspire you to make the switch. If not, there are some pretty cool things you can do with Podman. Like generating Kubernetes YAML files and the play kube
feature deserves a post of its own. Enjoy!