literegistry-podman-client
literegistry-podman-client is a small, standalone async Python client for
running commands in rootless Podman containers through a LiteRegistry gateway.
The person using it needs only a gateway URL; they do not need Redis, Podman,
Docker, or the full literegistry package.
The same gateway may also expose a Docker Hub pull-through mirror. Mirror use
is configured on the Podman servers by the operator, so client code still only
passes a normal image such as docker.io/library/ubuntu:24.04.
Install
From PyPI after publication:
pip install literegistry-podman-client
From this repository:
pip install ./literegistry_podman_client
The distribution name uses hyphens. Python imports use underscores:
from literegistry_podman_client import PodmanGatewayClient
Its only runtime dependency is aiohttp.
Give a deployment to someone
The operator gives the user one value:
export PODMAN_GATEWAY_URL=http://gateway.example:8080
The user can verify both gateway features:
curl -fsS "$PODMAN_GATEWAY_URL/health"
curl -fsS "$PODMAN_GATEWAY_URL/v2/"
/health checks the LiteRegistry gateway. /v2/ checks its Docker Registry
V2 mirror route. No Redis URL or Podman replica address is exposed to users.
Small async example
This creates one container, writes a file, reads it in a separate command, and always deletes the container at the end:
import asyncio
from literegistry_podman_client import PodmanGatewayClient
async def main() -> None:
gateway_url = "http://gateway.example:8080"
async with PodmanGatewayClient(gateway_url, workdir="/tmp") as client:
async with client.session(
image="docker.io/library/ubuntu:24.04",
client_id="rollout-17",
) as podman:
print(podman.container_id)
await podman.execute(
"printf 'ai2 hello\\n' > hello.txt",
check=True,
)
result = await podman.execute("cat hello.txt", check=True)
print(result.stdout, end="")
asyncio.run(main())
The image pull happens on the selected Podman replica. If the operator wired those replicas to the gateway's mirror, the pull is transparently cached; the user does not change the image reference or client configuration.
The runnable version is examples/ai2_hello.py:
python literegistry_podman_client/examples/ai2_hello.py \
--gateway "$PODMAN_GATEWAY_URL"
Explicit lifecycle
Handshake, execute, and close are all async. The affinity ID returned by the handshake keeps every command on the replica that owns its container.
client = PodmanGatewayClient(gateway_url, workdir="/home/user")
await client.open()
session = None
try:
session = await client.handshake(image=container_image)
first = await client.execute(
session.affinity_id,
"python -c 'print(6 * 7)'",
timeout=60,
)
first.check_returncode()
finally:
try:
if session is not None:
await session.close()
finally:
await client.aclose()
client.close(affinity_id)orsession.close()deletes the container and its gateway affinity binding.client.aclose()only closes the local HTTP connection pool. It cannot guess which concurrent sessions should be deleted.check=Trueorresult.check_returncode()raisesPodmanCommandErrorfor a non-zero command exit. Without it, stdout, stderr, and the exit code remain available onCommandResult.
Concurrent trajectories
One PodmanGatewayClient is intentionally shareable. It does not store a
private "current container". Each handshake returns a separate session:
async def rollout(client: PodmanGatewayClient, number: int) -> str:
async with client.session(client_id=f"rollout-{number}") as podman:
result = await podman.execute("echo $((20 + 22))", check=True)
return result.stdout.strip()
async with PodmanGatewayClient(gateway_url) as client:
outputs = await asyncio.gather(
*(rollout(client, i) for i in range(128))
)
The HTTP pool is shared, while every request carries its explicit affinity ID. As soon as one trajectory completes, application code may start another.
Mirror behavior
There are two distinct flows behind the gateway URL:
Python client -> /affinity/* -> Podman replica -> rootless container
Podman pull -> /v2/* -> Docker mirror -> Docker Hub
The client exposes await client.mirror_health() as a convenience probe, but
it does not configure the mirror. The deployment operator configures each
Podman replica's containers-registries.conf to use the gateway URL. This is
what ensures all users of the gateway benefit from the cache.
Build and publish
cd literegistry_podman_client
python -m build
python -m twine check dist/*
python -m twine upload dist/*
Publishing requires a PyPI account and token. Verify that the distribution
name literegistry-podman-client is available before the first upload.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file literegistry_podman_client-0.1.0.tar.gz.
File metadata
- Download URL: literegistry_podman_client-0.1.0.tar.gz
- Upload date:
- Size: 11.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ed5ddab4a7669be8dcd5187b577b9837acfd761dc637aa739c93ea123aa2336
|
|
| MD5 |
d8e48a9c97b7b23cbd88290f6c8e64bb
|
|
| BLAKE2b-256 |
7b88727cb89995a57e4bd61ebbbaf276f95a877a6753959a886fb475ef9ec86b
|
File details
Details for the file literegistry_podman_client-0.1.0-py3-none-any.whl.
File metadata
- Download URL: literegistry_podman_client-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1fff4611ab55c455fc6cd79f48d88dae23b97d03ba5f5a80cdcd2f42d7e06ea1
|
|
| MD5 |
870757d9407edf9384e6fb5f618131d6
|
|
| BLAKE2b-256 |
5c2177d4f00ab36e6a6df8f1d89a29a0c8e411603dacf7272fd3edbd786b25f2
|