Developing Images Post Docker
Tags: devops, cloud, docker
Published: 2022-06-07 13:57:20

The [Grace Period](https://www.docker.com/blog/the-grace-period-for-the-docker-subscription-service-agreement-ends-soon-heres-what-you-need-to-know/) for Docker has ended.  Organizations and professional will need to pay to play in Docker.  [Another post](https://dev.to/leading-edje/a-window-into-docker-minikube-and-containerd-16bi) covers an unsuccessful attempt to move to another platform .  There was some hope with [minikube](https://minikube.sigs.k8s.io/docs/) 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](https://buildah.io) is a project that builds Docker/Kubernetes compatible images.  [Podman](https://podman.io) 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](https://hub.docker.com) 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](https://docs.podman.io/en/latest/Commands.html) 

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](https://www.redhat.com/sysadmin/podman-play-kube-updates).  Enjoy!

<a href="https://dev.to/leading-edje">
  ![Smart EDJE Image](https://dev-to-uploads.s3.amazonaws.com/i/5uo60qforg9yqdpgzncq.png)
<a/>