Install shiplift via Cargo.toml
masterTo use shiplift in your Rust project, add it to your Cargo.toml dependencies. This provides a Rust interface for maneuvering Docker containers.
[dependencies]
shiplift = "0.7"repository·master·Indexed 20 days ago
https://github.com/softprops/shipliftA Rust interface for maneuvering Docker containers, providing programmatic access to Docker operations. Version 0.7.0 allows users to manage container lifecycles, stream logs, attach to TTYs, and move files between the host and container filesystem. It provides specialized interfaces for images, services, networks, and volumes, and supports connection via Unix sockets or TCP/Host URIs.
To use shiplift in your Rust project, add it to your Cargo.toml dependencies. This provides a Rust interface for maneuvering Docker containers.
[dependencies]
shiplift = "0.7"shiplift crate.Operations that involve long-running processes like build, pull, or import return a stream of ImageBuildChunk items. These chunks represent the progress or status of the operation.
Variants of ImageBuildChunk:
Update { stream: String }: A line of text from the process output.Error { error: String, error_detail: ErrorDetail }: An error occurred during the operation.Digest { aux: Aux }: The operation completed successfully, providing the image ID.PullStatus { status: String, id: Option<String>, progress: Option<String>, progress_detail: Option<ProgressDetail }: Status updates for pull operations.The HostConfig struct defines the resource constraints and host-level settings for a container.
Key configuration areas:
cpu_shares, memory, nano_cpus, pids_limit, and memory_swappiness.network_mode, port_bindings (via PortMap), and dns settings.binds, mounts, volumes_from, and tmpfs.privileged, cap_add, cap_drop, security_opt, and user.restart_policy and auto_remove.The Services struct provides an interface to interact with the collection of services on a Docker host. You can use it to list all services or retrieve a handle to a specific named service using .get(name).
To use it, initialize it with a reference to a Docker instance.
let services = Services::new(&docker);
// List all services
let list = services.list(&ServiceListOptions::builder().build()).await?;
// Get a handle to a specific service
let service = services.get("my-service-name");To start using Shiplift, create a new Docker instance using Docker::new(). This instance serves as the entry point for interacting with the Docker daemon via various sub-modules like images(), containers(), networks(), etc. Most operations are asynchronous and return a Result.
# async {
let docker = shiplift::Docker::new();
match docker.images().list(&Default::default()).await {
Ok(images) => {
for image in images {
println!("{:?}", image.repo_tags);
}
},
Err(e) => eprintln!("Something bad happened! {}", e),
}
# };You can create a Docker client instance using several methods depending on your connection requirements:
Docker::new() looks for the DOCKER_HOST environment variable. If not set, it defaults to the Unix socket at /var/run/docker.sock (requires the unix-socket feature).Docker::unix(path) to connect to a specific Unix socket path.Docker::host(uri) to connect to a specific host via a Uri object.If the tls feature is enabled, Docker will automatically attempt to use TLS certificates if the DOCKER_CERT_PATH environment variable is set.
```rust
// Using default (DOCKER_HOST or /var/run/docker.sock)
let docker = Docker::new();
// Using a specific Unix socket
let docker = Docker::unix("/tmp/docker.sock");
// Using a specific host URI
let uri = Uri::new("tcp", "localhost", Some(2375));
let docker = Docker::host(uri);
```埋To run a command inside an existing container, you must first create an Exec instance and then start it.
Exec::create with a container_id and ExecContainerOptions to initialize the execution context..start() on the returned Exec instance to receive a multiplexed TTY stream of the command's output.Alternatively, if you want to perform both steps in a single flow, the internal create_and_start method (not directly exposed to end-users in the public API, but following the same logic) combines these to avoid lifetime issues with the container ID and options.
// 1. Build options
let opts = ExecContainerOptions::builder()
.cmd(vec!["ls", "/tmp"])
.attach_stdout(true)
.attach_stderr(true)
.build();
// 2. Create the exec instance
let exec = Exec::create(&docker, "container_id_here", &opts).await?;
// 3. Start and process the stream
let mut stream = exec.start();
while let Some(chunk) = stream.next().await {
let chunk = chunk?;
// handle tty::TtyChunk
}Once you have a Network instance (obtained via Networks::get(id) or from NetworkCreateInfo), you can manipulate that specific network:
inspect(): Returns NetworkDetails for the network.delete(): Removes the network.connect(&ContainerConnectionOptions): Attaches a container to the network.disconnect(&ContainerConnectionOptions): Detaches a container from the network.let network = networks.get("network-id");
// Inspect details
let details = network.inspect().await?;
// Connect a container
let conn_opts = ContainerConnectionOptions::builder("container-id")
.aliases(vec!["web-server"])
.build();
network.connect(&conn_opts).await?;
// Delete the network
network.delete().await?;Use TagOptions::builder() to configure how an existing image is tagged.
Available configuration methods:
repo(r): The repository name to tag the image with.tag(t): The tag to apply.let opts = TagOptions::builder()
.repo("my-org/my-image")
.tag("v1.2.3")
.build();
image.tag(&opts).await?;The events() method returns a stream of Event objects. You can filter these events using EventsOptions constructed via the EventsOptionsBuilder.
Use the filter() method on the builder to apply various filters:
EventFilter::Container(id)EventFilter::Image(id)EventFilter::Volume(id)EventFilter::Network(id)EventFilter::Daemon(id)EventFilter::Label(label)EventFilter::Type(type) (e.g., Container, Image, Volume, Network, Daemon)You can also filter by time using .since(timestamp) and .until(timestamp).
let mut builder = EventsOptionsBuilder::default();
builder.filter(vec![
EventFilter::Type(EventFilterType::Container),
EventFilter::Label("status=running".to_string())
]);
let opts = builder.build();
let mut event_stream = docker.events(&opts);
while let Some(event) = event_stream.next().await {
let event = event?;
println!("Event: {} on {}", event.action, event.actor.id);
}```rust
let mut builder = EventsOptionsBuilder::default();
builder.filter(vec![
EventFilter::Type(EventFilterType::Container),
EventFilter::Label("status=running".to_string())
]);
let opts = builder.build();
let mut event_stream = docker.events(&opts);
while let Some(event) = event_stream.next().await {
let event = event?;
println!("Event: {} on {}", event.action, event.actor.id);
}
```埋Use NetworkCreateOptions::builder(name) to configure a new network before creation. The builder pattern allows you to specify the driver and labels.
Available builder methods:
driver(name: &str): Sets the network driver (e.g., "bridge", "overlay").label(labels: HashMap<String, String>): Sets metadata labels for the network.build(): Finalizes the options.let mut labels = HashMap::new();
labels.insert("environment".to_string(), "production".to_string());
let opts = NetworkCreateOptions::builder("prod-net")
.driver("bridge")
.label(labels)
.build();