podman-py
podman-py copied to clipboard
can't specify a volume via a host path
According to the documentation listed here https://github.com/containers/podman-py/blob/main/podman/domain/containers_create.py
volumes (Dict[str, Dict[str, str]]): A dictionary to configure volumes mounted inside
the container. The key is either the host path or a volume name, and the value is
a dictionary with the keys:
- bind: The path to mount the volume inside the container
- mode: Either rw to mount the volume read/write, or ro to mount it read-only.
For example:
{'/home/user1/': {'bind': '/mnt/vol2', 'mode': 'rw'},
'/var/www': {'bind': '/mnt/vol1', 'mode': 'ro'}}
...a dictionary is needed to configure volumes inside the container.
Ok, so I'm literally using the same example to create a container.
client.containers.create(image=podman_image_name, name=podman_container_name, volumes={'/home/user1/': {'bind': '/mnt/vol2', 'mode': 'rw'}}
However, I'm met with the following error:
File "/home/user1/Desktop/podman-clamav-el6/./script-podman.py", line 167, in <module>
ensure_container_exists_and_running()
File "/home/user1/Desktop/podman-clamav-el6/./script-podman.py", line 119, in ensure_container_exists_and_running
run_container()
File "/home/user1/Desktop/podman-clamav-el6/./script-podman.py", line 139, in run_container
client.containers.create(image=podman_image_name, name=podman_container_name, volumes={'/home/user1/': {'bind': '/mnt/vol2', 'mode': 'rw'}})
File "/usr/lib/python3.10/site-packages/podman/domain/containers_create.py", line 224, in create
response.raise_for_status(not_found=ImageNotFound)
File "/usr/lib/python3.10/site-packages/podman/api/client.py", line 65, in raise_for_status
raise APIError(cause, response=self._response, explanation=message)
podman.errors.exceptions.APIError: 500 Server Error: Internal Server Error (error creating named volume "/home/user1/": error running volume create option: names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument)
It's trying to create a named volume vs using the host path --even though the documentation clearly states The key is either the host path or a volume name
This was MUCH easier with docker-py
where you could just provide a list of mounts.
I'll dig through the code later, but in the meantime any help would be appreciated.
I sorted out a solution by analyzing containers_create.py
basically I needed to do this to use the mounts
feature (still not sure why the volumes
feature doesn't work)
bind_volumes = [
{
'type': 'bind',
'source': output_rpm_dir_host,
'target': output_rpm_dir_container
}
]
client.containers.run(image=podman_image_name, name=podman_container_name, mounts=bind_volumes)
It would be nice if there was some sort of documentation on how to use the mounts
feature.
Anyways, I hope this helps someone out....
Where would you expect to see the documentation? Interested in opening a PR to add the docs there?
If you look at https://github.com/containers/podman-py/blob/main/podman/domain/containers_create.py
mounts (List[Mount]): Specification for mounts to be added to the container. More
powerful alternative to volumes. Each item in the list is expected to be a
Mount object.
....
volumes (Dict[str, Dict[str, str]]): A dictionary to configure volumes mounted inside
the container. The key is either the host path or a volume name, and the value is
a dictionary with the keys:
- bind: The path to mount the volume inside the container
- mode: Either rw to mount the volume read/write, or ro to mount it read-only.
For example:
{'/home/user1/': {'bind': '/mnt/vol2', 'mode': 'rw'},
'/var/www': {'bind': '/mnt/vol1', 'mode': 'ro'}}
You'll see there's an example given for volumes
--which is a bad example since providing a host path doesn't work.
But for "the much more powerful" mounts
, it just states
Each item in the list is expected to be a Mount object
Does anyone know what a mount object is!?
All I'm saying is that it would be nice to have an example listed there of how to construct a Mount object for that --or rather the data structure....it's not really an object is it?
I could write up a PR for that when I have time...
I don't know if you're using Fedora/CentOS, but I had trouble with bind mounts until I set the context of the host directory to container_file_t
. I was able to get both the mounts=
and the volumes=
directives working. For a an existing podman volume syncthing_config
and a backup directory (with the same contents as the volume) /var/backups/scotty/podman/syncthing_config
:
In [1]: from podman import PodmanClient
In [2]: client = PodmanClient()
In [3]: client.containers.run(image='alpine:3.15',name='test',command=["top"], \
volumes={'syncthing_config': {'bind': '/mnt', 'mode':'rw'}}, \
mounts=[{'type':'bind','source':'/var/backups/scotty/podman/syncthing_config/','target':'/backups'}]
In another terminal:
$ podman exec -it test ls /mnt
cert.pem config.xml.v35 https-cert.pem index-v0.14.0.db
config.xml csrftokens.txt https-key.pem key.pem
$ podman exec -it test ls /backup
cert.pem config.xml.v35 https-cert.pem index-v0.14.0.db
config.xml csrftokens.txt https-key.pem key.pem
To set the correct selinux context on the host directory:
$ sudo semanage fcontext -a -t container_file_t "/var/backups/scotty/podman(/.+)?"
$ sudo restorecon -Frv /var/backups/scotty/podman/
It would be useful if the :z
and :Z
modes are handled by podman-py as well as rw
and ro
for the bind mounts. That would make the selinux issues go away, I think. Also, the volumes=
directive does not seem to work with bind mounts as advertised in the docs (as pointed out by the OP). It doesn't look like the volume
type is supported, only bind
looking at the source code:
In [4]: client.containers.run(image='alpine:3.15', name='test', command["top"], \
volumes={'/var/backups/scotty/podman/syncthing_config': {'bind': '/mnt', 'mode': 'rw'}})
......
APIError: 500 Server Error: Internal Server Error (error creating named volume "/var/backups/scotty/podman/syncthing_config": error running volume create option: names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument)
I've just run into the same error. I have an existing application that uses the Docker API (which this API is clearly based on) and volumes don't work when the keys are the host paths. There's also a similar problem with the user
argument which raises:
500 Server Error: Internal Server Error (decode(): json: cannot unmarshal number into Go struct field SpecGenerator.user of type string)
When you pass a UID, I imagine passing a username will work (although I haven't tested yet).
I am also getting this error. Does anyone know a workaround? It's a blocker for my use case
import os
import podman
os.makedirs("test-output-folder", exist_ok=True)
with podman.PodmanClient(base_url="unix:/var/run/docker.sock") as client:
client.containers.run(
"ubuntu",
command=["touch", "/path/file.txt"],
volumes={
os.path.join(os.getcwd(), "test-output-folder"): {
"bind": "/path",
"mode": "rw",
}
},
remove=True,
)
error is
podman.errors.exceptions.APIError: 500 Server Error: Internal Server Error (creating named "...": running volume create option: names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*: invalid argument)