bollard
An asynchronous Rust client for the Docker and Podman Engine API, built on Hyper and Tokio.
Repository Health
Technical Analysis
Bollard is an async Rust client library for the Docker daemon API, built on Hyper and Tokio so every call returns futures and streams that fit naturally into async/await code. It treats Docker and Podman as first-class, interchangeable container runtimes, with automatic socket discovery for rootless Podman and Windows support through named pipes, so the same client code can target either engine without branching logic.
Connectivity is pluggable through Cargo feature flags: local Unix sockets or Windows named pipes by default, plus optional TCP, TLS via Rustls (ring or aws-lc-rs providers), SSH tunneling, and WebSocket-based container attach. Request and response types are generated from Docker’s OpenAPI schema into a separately versioned bollard-stubs crate, and an optional buildkit feature adds gRPC/protobuf bindings for BuildKit-based image builds, making Bollard suitable for anything from a simple container-status CLI to a full CI/CD orchestration or image-building tool written in Rust.
What You Get
- A single
Dockerclient with named constructors (connect_with_local_defaults,connect_with_podman_defaults,connect_with_socket_defaults,connect_with_http_defaults,connect_with_ssl_defaults,connect_with_ssh_defaults) covering every supported transport - Typed, builder-pattern options for every Engine API call (e.g.
ListImagesOptionsBuilder,CreateContainerOptionsBuilder,StatsOptionsBuilder) generated from Docker’s OpenAPI schema via thebollard-stubscrate - Streaming support for logs, stats, and events as
futures_core::Streams, decoded through custom JSON-line and newline log-output decoders - First-class Podman support with automatic rootless/system socket discovery and fallback to the Docker socket, not just Docker-only compatibility
- Optional BuildKit integration (gRPC/protobuf via Tonic) for modern buildx-style image builds with session providers and cache import/export
- Cross-platform transport: Unix sockets and Windows named pipes locally, plus TCP, Rustls-backed TLS, SSH tunneling, and WebSocket container attach as opt-in features
Common Use Cases
- Container orchestration tooling - building custom schedulers, deploy agents, or PaaS control planes that create, inspect, and manage containers programmatically
- CI/CD pipeline tooling - Rust-based build agents that build, tag, and push images, including BuildKit-based builds with cache import/export
- Local dev tooling and CLIs - Rust CLIs that need to start/stop/inspect Docker or Podman containers without shelling out to
docker - Container monitoring and stats dashboards - streaming per-container stats and logs into a Rust backend for observability tooling
- Swarm and cluster automation - managing Docker Swarm services, nodes, secrets, and tasks from Rust automation scripts
Under The Hood
Architecture
The Docker struct in src/docker.rs (roughly 2,450 lines) is the central client, owning a hyper-based transport abstracted behind a ClientType enum that covers Unix sockets (via hyperlocal), TCP (via hyper-util’s HttpConnector), TLS (via hyper-rustls), Windows named pipes (via hyper-named-pipe), and SSH tunnels (via openssh). Every API call funnels through a small set of generic transport methods — process_into_value, process_into_stream, process_into_unit, process_into_status, process_into_body, process_into_string — that provide a uniform request/response pipeline on top of Request<Full<Bytes>>, with streaming JSON and log decoding handled by read.rs’s JsonLineDecoder and NewlineLogOutputDecoder. Feature modules (container.rs, image.rs, network.rs, volume.rs, exec.rs, swarm.rs, plugin.rs, node.rs, task.rs, secret.rs, service.rs, system.rs) are all impl blocks on Docker, each wrapping one Engine API resource and calling the shared process_into_* methods with typed models re-exported from the separately versioned bollard-stubs crate — cleanly separating hand-written transport/ergonomics from OpenAPI-generated wire types, so a Docker API schema bump mostly ripples through the pinned bollard-stubs dependency rather than this crate’s own code.
Tech Stack
Rust 2021 edition, async on Tokio with Hyper 1.3 as the HTTP client (via hyper-util’s legacy Client and TokioExecutor). Transport is pluggable through Cargo features: hyperlocal for Unix sockets, hyper-named-pipe for Windows, hyper-rustls/rustls 0.23 (choice of ring or aws-lc-rs crypto providers) for TLS, openssh for SSH tunneling, and tokio-tungstenite for WebSocket container-attach streams. Serialization runs on serde/serde_json plus the exactly pinned bollard-stubs crate holding OpenAPI-generated request/response models, backed by a workspace-level codegen pipeline (codegen/swagger using Java/Maven and swagger-codegen, codegen/proto using Tonic/prost with an xtask regeneration command) for the models and the optional BuildKit gRPC bindings (bollard-buildkit-proto, Tonic 0.14). Errors are typed via thiserror::Error. CI runs on CircleCI, driving Docker-in-Docker matrices across TCP, SSL, SSH, and Unix-socket transports, plus AppVeyor for Windows, with Dependabot keeping dependencies current.
Code Quality
Thirteen source files carry inline #[test]/#[tokio::test] unit tests, and a large tests/ directory holds roughly eighteen integration test files (container_test.rs, image_test.rs, network_test.rs, swarm_test.rs, podman_test.rs, and more) that exercise real Docker or Podman daemons, gated behind feature flags (test_http, test_ssh, test_ssl, test_podman, test_swarm, test_checkpoint, etc.) so different transport and runtime combinations run in isolation across CI jobs. Errors are explicit and typed through a #[non_exhaustive] thiserror::Error enum rather than swallowed or stringly-typed. lib.rs enables #![deny(missing_docs, missing_debug_implementations, ...)] and #![warn(rust_2018_idioms)], enforcing documentation coverage and idiomatic-Rust discipline at compile time. unwrap() appears extensively across the source tree, a mix of doc examples, tests, and internal invariants rather than unchecked production paths, since public APIs consistently return Result.
API Design
Builder-pattern options structs give every one of the roughly fifteen resource modules a consistent, discoverable way to construct requests without hand-building query strings or partial structs. Multiple connection strategies are exposed as clearly named constructors, with connect_with_local_defaults and connect_with_podman_defaults auto-detecting the right local socket including rootless Podman discovery, lowering the boilerplate needed to get a working client versus manually configuring a Hyper client and connector. Feature-gating (http+pipe enabled by default, ssl/ssh/websocket/buildkit opt-in) lets consumers keep binary size and dependency footprint minimal while still supporting the full Docker/Podman/BuildKit surface when needed — a deliberate trade-off many comparable HTTP-API-wrapper crates skip. First-class Podman support alongside Docker, with automatic socket discovery and fallback, differentiates it from most Docker-only Rust clients.