bollard-next 0.18.1

An asynchronous Docker daemon API
Documentation
//! This example will run a non-interactive command inside the container using `docker exec`

use bollard_next::container::{Config, RemoveContainerOptions};
use bollard_next::Docker;

use bollard_next::exec::{CreateExecOptions, StartExecResults};
use bollard_next::image::CreateImageOptions;
use futures_util::stream::StreamExt;
use futures_util::TryStreamExt;

const IMAGE: &str = "alpine:3";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
    let docker = Docker::connect_with_socket_defaults().unwrap();

    docker
        .create_image(
            Some(CreateImageOptions {
                from_image: IMAGE,
                ..Default::default()
            }),
            None,
            None,
        )
        .try_collect::<Vec<_>>()
        .await?;

    let alpine_config = Config {
        image: Some(IMAGE.to_owned()),
        tty: Some(true),
        ..Default::default()
    };

    let id = docker
        .create_container::<&str>(None, alpine_config)
        .await?
        .id;
    docker.start_container::<String>(&id, None).await?;

    // non interactive
    let exec = docker
        .create_exec(
            &id,
            CreateExecOptions {
                attach_stdout: Some(true),
                attach_stderr: Some(true),
                cmd: Some(vec!["ls".into(), "-l".into(), "/".into()]),
                ..Default::default()
            },
        )
        .await?
        .id;
    if let StartExecResults::Attached { mut output, .. } = docker.start_exec(&exec, None).await? {
        while let Some(Ok(msg)) = output.next().await {
            print!("{msg}");
        }
    } else {
        unreachable!();
    }

    docker
        .remove_container(
            &id,
            Some(RemoveContainerOptions {
                force: true,
                ..Default::default()
            }),
        )
        .await?;

    Ok(())
}