podman is not docker
podman
is not docker
.. yeah. That's an understatement.
This example is a one-shot container. It's not a pod
(that might be an upcoming post). I'm running one command in the container and then I remove it. The task is to do some async calls (usually less than 10,000) to Business Central and log the results. The log must be persistent.
On with the show.
# Dockerfile
FROM python:3.11-buster
WORKDIR /usr/src/myapp
ADD src ./src
COPY .env .
COPY poetry.lock .
COPY pyproject.toml .
RUN curl -sSL https://install.python-poetry.org | python3 -
ENV PATH="/root/.local/bin:$PATH"
RUN poetry config installer.max-workers 10
RUN poetry install --only main
One image, based on python3.11-buster
and a src
folder containing the application.
My application must have persistent logging. Coming from docker
one would assume that a VOLUMES
directive in the Dockerfile
or, my preferred method:
# docker-compose.yaml
version: "3"
services:
amazingapp:
container_name: amazingapp
env_file: .env
build: .
volumes:
- ./logs:/usr/src/myapp/logs
docker-compose
would do the trick. Well. I believe that I've read, somewhere, that docker-compose
should just work with podman
, but even this minuscule example fails. The VOLUME
directive does nothing.
So, enter podman-compose.
Does it work? Yes, yes it does. Very well actually.
$ podman-compose -f docker-compose.yaml build
$ podman-compose -f docker-compose.yaml run --rm amazingapp \
/path/to/my/script
To my surprise, this did not create persistent volumes visible for podman volume ls
. But it works just as it should.
You might find it easier to run this just using plain podman
. After all, it's one less dependency and is perhaps more future-proof.
$ podman build --tag amazingapp:latest .
$ podman run -it --name myhoovercraftisfulofeels \
./logs:/usr/src/myapp/logs:rw,z \
localhost/amazingapp:latest \
/path/to/my/script
Again, it works and no volumes are created.
If you instead execute /bin/bash
(replacing /path/to/my/script
) you can inspect your running container and find that - indeed the logs
directory are being mounted inside the container at the WORKDIR
path.
WORKDIR
was the crux of this matter!$ podman inspect -f '{{.Mounts}}' <containername>
[{bind /home/USER/path/to/logs /usr/src/myapp/logs \
[rbind] true rprivate}
So what are then volumes?
In a pod where you typically would use a kubernetes
compatible yaml
description you would add a persistentVolumeClaim
for each volume
. This does basically the same as
$ podman volume create amazingapp-volume
Inspecting the volume
$ podman volume inspect amazingapp-volume
[
{
"Name": "amazingapp-volume",
"Driver": "local",
"Mountpoint": "/home/USER/.local/share/containers/storage/ \
volumes/amazingapp-volume/_data",
"CreatedAt": "2023-09-26T08:26:04.236862704+02:00",
"Labels": {},
"Scope": "local",
"Options": {},
"MountCount": 0,
"NeedsCopyUp": true,
"LockNumber": 3
}
]
Using the volume
instead of /home/USER/path/to/logs
$ podman run -it --name myhoovercraftisfulofeels \
-v amazingapp-volume:/usr/src/myapp/logs:rw,z \
localhost/amazingapp:latest \
/path/to/my/script
Where's your log? It's at:/home/USER/.local/share/containers/storage/volumes/amazingapp-volume/_data
not particularly convenient.
There are other mounting options as well:
$ podman run -it --name myhoovercraftisfulofeels \
--mount type=bind,source=/home/USER/path/to/logs,\
target=/usr/src/amazingapp localhost/amazingapp:latest \
/path/to/my/script
Using mount this way, you'll probably run into SELinux
problems. Adding --privileged
might help, but I'd just stick to the -v
and rw,z
option to avoid turning off SELinux
for the entire container process.
So here we are. This has been a long arduous journey. podman
and docker
are just different enough to really really trip you up. The takeaways are:
podman is better
docker has got better documentation
and a heck of a lot larger installed base
but you'll find the answer to your podman question
eventually