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?;
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(())
}