Manage pods, containers, and container images.
Talks, View Code, Edit the Website
This project is maintained by the containers organization.
Subscribe to the blog feed.
This guide shows how to access Podman remotely via the varlink interface with CLI tools and programmatically with python, go and rust.
This should work on Linux, MacOS and Windows 10.
The compatibility matrix shows which feature is supported on which OS in which language.
Note: replace
<podman-machine>
in this guide with the IP or hostname of your Podman machine
If you are on a windows client machine, install the OpenSSH Client built by Microsoft in a cmd.exe in admin mode:
> dism /online /Add-Capability /CapabilityName:OpenSSH.Client~~~~0.0.1.0
Close cmd.exe window.
Note: Works also with other ssh clients, e.g. ssh from Git Bash.
If you don’t want to type your password all the time, or not use an ssh agent, set an empty password.
$ ssh-keygen -f ~/.ssh/podmanuser
$ sudo yum install podman libvarlink-util
$ sudo groupadd podman
Copy /lib/tmpfiles.d/podman.conf
to /etc/tmpfiles.d/podman.conf
.
$ sudo cp /lib/tmpfiles.d/podman.conf /etc/tmpfiles.d/podman.conf
Edit /etc/tmpfiles.d/podman.conf
:
d /run/podman 0750 root podman
Copy /lib/systemd/system/io.podman.socket
to /etc/systemd/system/io.podman.socket
.
$ sudo cp /lib/systemd/system/io.podman.socket /etc/systemd/system/io.podman.socket
Edit section [Socket]
of /etc/systemd/system/io.podman.socket
:
[Socket]
ListenStream=/run/podman/io.podman
SocketMode=0660
SocketGroup=podman
Then activate the changes:
$ sudo systemctl daemon-reload
$ sudo systemd-tmpfiles --create
$ sudo systemctl enable --now io.podman.socket
The directory and socket now belongs to the podman group
$ sudo ls -al /run/podman
drwxr-x---. 2 root podman 60 14. Jan 14:50 .
drwxr-xr-x. 51 root root 1420 14. Jan 14:36 ..
srw-rw----. 1 root podman 0 14. Jan 14:50 io.podman
Note: Wouldn’t it be nice, if there was a Podman group owning the socket already? ;-)
Now we are adding a user podmanuser
and set a password:
$ sudo useradd podmanuser -G podman
$ sudo passwd podmanuser
From your client machine do
$ ssh-copy-id -f ~/.ssh/podmanuser podmanuser@<podman-machine>
Edit .ssh/config
Host <podman-machine>
RequestTTY no
IdentityFile ~/.ssh/podmanuser
User podmanuser
VisualHostKey no
RemoteCommand /usr/bin/varlink bridge --connect unix:/run/podman/io.podman
GSSAPIAuthentication no
ForwardX11 no
Log into <podman-machine>
$ ssh podmanuser@<podman-machine>
Now we lock down podmanuser
to only be used with the varlink bridge from your client machine:
Edit .ssh/authorized-keys
so that the line begins with:
command="/usr/bin/varlink bridge --connect unix:/run/podman/io.podman",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-rsa […]
Log out of <podman-machine>
https://www.python.org/downloads/
$ pip install --user "varlink>=30.0.2"
$ python -m varlink.cli --help
usage: cli.py [-h] [-r RESOLVER] [-A ACTIVATE] [-b BRIDGE]
{info,help,bridge,call} ...
…
$ python -m varlink.cli --bridge "ssh <podman-machine>" info
info
.1:1234
Vendor: Atomic
Product: podman
Version: 0.10.1
URL: https://github.com/containers/podman
Interfaces:
org.varlink.service
io.podman
$ python -m varlink.cli --bridge "ssh <podman-machine>" call io.podman.Ping {}
{
"ping": {
"message": "OK"
}
}
podmanclient.py
:
import varlink
with varlink.Client.new_with_bridge(["ssh", "<podman-machine>"]) as client:
with client.open("io.podman") as podman:
print(podman.Ping())
print(podman.GetInfo())
print(podman.GetVersion())
info = podman.GetInfo()
print("Uptime:", info["info"]["host"]["uptime"])
print("Os:", info["info"]["host"]["os"])
try:
podman.MountContainer("container-id")
except varlink.error.VarlinkError as e:
print(e.error(), e.parameters())
print(e.as_dict())
To find out more about the Podman varlink interface read the io.podman.varlink file or the rendered API.md.
Or you can inspect, what methods your Podman version on <podman-machine>
provides:
$ python -m varlink.cli --bridge "ssh <podman-machine>" help io.podman
$ go get -u github.com/varlink/go/varlink
$ go install github.com/varlink/go/cmd/varlink
$ go install github.com/varlink/go/cmd/varlink-go-interface-generator
The varlink
CLI command in $GOPATH/bin
should output:
$ varlink --bridge "ssh <podman-machine>" info
Vendor: Atomic
Product: podman
Version: 0.10.1
URL: https://github.com/containers/podman
Interfaces:
org.varlink.service
io.podman
$ varlink --bridge "ssh <podman-machine>" call io.podman.Ping
{
"ping": {
"message": "OK"
}
}
$ varlink --bridge "ssh <podman-machine>" call io.podman.MountContainer "{\"name\": \"container-id\"}"
Error: Call failed with error: io.podman.ErrorOccurred
{
"reason": "no container with name or ID container-id found: no such container"
}
To find out more about the Podman varlink interface read the io.podman.varlink file or the rendered API.md.
Or you can inspect, what methods your Podman version on <podman-machine>
provides:
$ varlink --bridge "ssh <podman-machine>" help io.podman
Either clone this repository or:
Create a new go project.
Create a sub directory iopodman
in the project.
Create the io.podman.varlink
either from the podman github sources or dynamically with:
$ varlink --bridge "ssh <podman-machine>" help io.podman > iopodman/io.podman.varlink
Create iopodman/generate.go:
package iopodman
//go:generate $GOPATH/bin/varlink-go-interface-generator io.podman.varlink
Run go generate
:
$ go generate ./...
Create your main.go:
package main
import (
"flag"
"fmt"
"github.com/haraldh/podmangoexampleclient/iopodman"
"github.com/varlink/go/varlink"
"io"
"os"
)
func printError(methodname string, err error) {
fmt.Fprintf(os.Stderr, "Error calling %s: ", methodname)
switch e := err.(type) {
case *iopodman.ImageNotFound:
//error ImageNotFound (name: string)
fmt.Fprintf(os.Stderr, "'%v' name='%s'\n", e, e.Name)
case *iopodman.ContainerNotFound:
//error ContainerNotFound (name: string)
fmt.Fprintf(os.Stderr, "'%v' name='%s'\n", e, e.Name)
case *iopodman.NoContainerRunning:
//error NoContainerRunning ()
fmt.Fprintf(os.Stderr, "'%v'\n", e)
case *iopodman.PodNotFound:
//error PodNotFound (name: string)
fmt.Fprintf(os.Stderr, "'%v' name='%s'\n", e, e.Name)
case *iopodman.PodContainerError:
//error PodContainerError (podname: string, errors: []PodContainerErrorData)
fmt.Fprintf(os.Stderr, "'%v' podname='%s' errors='%v'\n", e, e.Podname, e.Errors)
case *iopodman.NoContainersInPod:
//error NoContainersInPod (name: string)
fmt.Fprintf(os.Stderr, "'%v' name='%s'\n", e, e.Name)
case *iopodman.ErrorOccurred:
//error ErrorOccurred (reason: string)
fmt.Fprintf(os.Stderr, "'%v' reason='%s'\n", e, e.Reason)
case *iopodman.RuntimeError:
//error RuntimeError (reason: string)
fmt.Fprintf(os.Stderr, "'%v' reason='%s'\n", e, e.Reason)
case *varlink.InvalidParameter:
fmt.Fprintf(os.Stderr, "'%v' parameter='%s'\n", e, e.Parameter)
case *varlink.MethodNotFound:
fmt.Fprintf(os.Stderr, "'%v' method='%s'\n", e, e.Method)
case *varlink.MethodNotImplemented:
fmt.Fprintf(os.Stderr, "'%v' method='%s'\n", e, e.Method)
case *varlink.InterfaceNotFound:
fmt.Fprintf(os.Stderr, "'%v' interface='%s'\n", e, e.Interface)
case *varlink.Error:
fmt.Fprintf(os.Stderr, "'%v' parameters='%v'\n", e, e.Parameters)
default:
if err == io.EOF {
fmt.Fprintf(os.Stderr, "Connection closed\n", )
} else if err == io.ErrUnexpectedEOF {
fmt.Fprintf(os.Stderr, "Connection aborted\n", )
} else {
fmt.Fprintf(os.Stderr, "%T - '%v'\n", err, err)
}
}
}
func main() {
var c *varlink.Connection
var err error
c, err = varlink.NewBridge("ssh <podman-machine>")
if err != nil {
fmt.Fprintf(os.Stderr, "Error connecting: %T - '%v'\n", err, err)
os.Exit(1)
}
// Be nice and cleanup
defer c.Close()
info, err := iopodman.GetInfo().Call(c)
if err != nil {
printError("GetInfo()", err)
os.Exit(1)
}
fmt.Printf("Info: %+v\n\n", info)
fmt.Printf("Podman Version: %+v\n\n", info.Podman.Podman_version)
containers, err := iopodman.ListContainers().Call(c)
if err != nil {
printError("ListContainers()", err)
os.Exit(1)
}
for container := range containers {
print(container)
}
mount, err := iopodman.MountContainer().Call(c, "foo")
if err != nil {
printError("MountContainer()", err)
} else {
print(mount)
}
}
First install the C++ part of https://visualstudio.microsoft.com/downloads/
https://rustup.rs/
$ cargo install varlink-cli
Note: Ensure that $HOME/.cargo/bin is in your PATH or copy $HOME/.cargo/bin/varlink in one of your path directories
You can also use varlink
util from libvarlink
or install libvarlink-util
on Fedora/RHEL machines.
The varlink
CLI command in ~/.cargo/bin
should output:
$ varlink --bridge "ssh <podman-machine>" info
Vendor: Atomic
Product: podman
Version: 0.10.1
URL: https://github.com/containers/podman
Interfaces:
org.varlink.service
io.podman
$ varlink --bridge "ssh <podman-machine>" call io.podman.Ping
{
"ping": {
"message": "OK"
}
}
$ varlink --bridge "ssh <podman-machine>" call io.podman.MountContainer "{\"name\": \"container-id\"}"
Error: Call failed with error: io.podman.ErrorOccurred
{
"reason": "no container with name or ID container-id found: no such container"
}
To find out more about the Podman varlink interface read the io.podman.varlink file or the rendered API.md.
Or you can inspect, what methods your Podman version on <podman-machine>
provides:
$ varlink --bridge "ssh <podman-machine>" help io.podman
Either clone this repository or:
$ cargo new --bin podmanrs
$ cd podmanrs
Download the varlink interface from the running Podman varlink service:
$ varlink --bridge "ssh <podman-machine>" help io.podman > src/io.podman.varlink
create build.rs
:
extern crate varlink_generator;
fn main() {
varlink_generator::cargo_build_tosource("src/io.podman.varlink", true);
}
create Cargo.toml
:
[package]
name = "podmanrs"
version = "0.1.0"
authors = ["Harald Hoyer <harald@redhat.com>"]
build = "build.rs"
edition = "2018"
[dependencies]
varlink = "7"
serde = "1"
serde_derive = "1"
serde_json = "1"
chainerror = "0.4"
[build-dependencies]
varlink_generator = "7"
create src/main.rs
:
mod io_podman;
use crate::io_podman::*;
use varlink::Connection;
use std::result::Result;
use std::error::Error;
fn main() -> Result<(), Box<Error>> {
let connection = Connection::with_bridge(
"ssh <podman-machine>",
)?;
let mut podman = VarlinkClient::new(connection.clone());
let reply = podman.ping().call()?;
println!("Ping() replied with '{}'", reply.ping.message);
let reply = podman.get_info().call()?;
println!("Hostname: {}", reply.info.host.hostname);
println!("Info: {:#?}", reply.info);
Ok(())
}
Now run it:
$ cargo run