bollard

chronista-club's avatarfrom chronista-club

Rust製非同期Docker APIクライアント「Bollard」の使い方と実装パターン

⭐1stars🔀0forks📁View on GitHub🕐Updated Jan 9, 2026

When & Why to Use This Skill

This Claude skill provides a comprehensive guide and implementation patterns for Bollard, the leading asynchronous Rust client for the Docker API. It covers essential operations such as container lifecycle management, image handling, and advanced error handling using Tokio and futures, enabling developers to build robust, high-performance containerized applications and tools in Rust.

Use Cases

  • Case 1: Automating container lifecycle management (create, start, stop, remove) within Rust-based backend services or microservices.
  • Case 2: Developing custom CLI tools or lightweight orchestrators that require direct programmatic interaction with the Docker Engine API.
  • Case 3: Implementing robust error handling and status-code-based retry logic for Docker operations in asynchronous environments.
  • Case 4: Programmatically managing Docker images, volumes, and networks, including streaming image pull progress and handling complex label configurations.
namebollard
descriptionRust製非同期Docker APIクライアント「Bollard」の使い方と実装パターン
tags[docker, rust, async, container]
version1.0.0

Bollard Skill

Rust製非同期Docker APIクライアント「Bollard」の実装ガイドです。

概要

Bollardは、Rust製の非同期Docker API クライアントライブラリです。 HyperとTokioを使用し、futuresとasync/awaitパラダイムで実装されています。

スキルの起動タイミング

このスキルは以下の場合に活用してください:

  • ✅ Docker操作を実装する際
  • ✅ コンテナ、イメージ、ボリューム、ネットワーク操作
  • ✅ Bollardのエラーハンドリング
  • ✅ Rustでコンテナ管理機能を実装する際
  • ✅ Docker APIを使ったツール開発

クイックリファレンス

基本的な接続

use bollard::Docker;

// OS固有のデフォルト設定で接続(推奨)
let docker = Docker::connect_with_local_defaults()?;

コンテナ操作

use bollard::container::{Config, CreateContainerOptions};

// 作成
let response = docker.create_container(Some(options), config).await?;

// 起動
docker.start_container::<String>(&container_id, None).await?;

// 停止
docker.stop_container(&container_id, Some(StopContainerOptions { t: 10 })).await?;

// 削除
docker.remove_container(&container_id, Some(RemoveContainerOptions {
    force: true,
    v: true,
    ..Default::default()
})).await?;

// 一覧
let containers = docker.list_containers(Some(ListContainersOptions::<String> {
    all: true,
    ..Default::default()
})).await?;

イメージ操作

use bollard::image::CreateImageOptions;
use futures_util::stream::TryStreamExt;

// Pull
let options = Some(CreateImageOptions {
    from_image: "postgres",
    tag: "16",
    ..Default::default()
});

let mut stream = docker.create_image(options, None, None);
while let Some(info) = stream.try_next().await? {
    println!("{:?}", info);
}

エラーハンドリング

use bollard::errors::Error;

match docker.create_container(options, config).await {
    Ok(response) => { /* 成功 */ }
    Err(Error::DockerResponseServerError { status_code: 409, .. }) => {
        // コンテナが既に存在
    }
    Err(Error::DockerResponseServerError { status_code: 404, .. }) => {
        // イメージが見つからない
    }
    Err(e) => { /* その他のエラー */ }
}

実装パターン

Docker Composeライクなラベル設定

use bollard::container::{Config, CreateContainerOptions};
use bollard::models::HostConfig;
use std::collections::HashMap;

let config = Config {
    image: Some("postgres:16".to_string()),
    labels: Some({
        let mut labels = HashMap::new();
        // Docker Compose互換のラベル
        labels.insert("com.docker.compose.project".to_string(),
                     format!("{}-{}", project_name, stage_name));
        labels.insert("com.docker.compose.service".to_string(),
                     service_name.to_string());
        // カスタムラベル
        labels.insert("app.project".to_string(), project_name.to_string());
        labels.insert("app.stage".to_string(), stage_name.to_string());
        labels
    }),
    host_config: Some(HostConfig {
        port_bindings: Some(port_bindings),
        binds: Some(volumes),
        ..Default::default()
    }),
    ..Default::default()
};

let options = CreateContainerOptions {
    name: format!("{}-{}-{}", project_name, stage_name, service_name),
    ..Default::default()
};

エラーハンドリングと既存コンテナの処理

match docker.create_container(Some(create_options.clone()), config.clone()).await {
    Ok(response) => {
        println!("  ✓ コンテナ作成: {}", response.id);
        docker.start_container::<String>(&response.id, None).await?;
        println!("  ✓ 起動完了");
    }
    Err(bollard::errors::Error::DockerResponseServerError { status_code: 409, .. }) => {
        println!("  ℹ コンテナは既に存在します");
        match docker.start_container::<String>(&container_name, None).await {
            Ok(_) => println!("  ✓ 既存コンテナを起動"),
            Err(e) => println!("  ⚠ 起動エラー: {}", e),
        }
    }
    Err(e) => {
        return Err(anyhow::anyhow!("コンテナ作成エラー: {}", e));
    }
}

ベストプラクティス

1. 接続の再利用

Docker接続インスタンスは複数の操作で再利用できます:

let docker = Docker::connect_with_local_defaults()?;

// 同じインスタンスを使い回す
docker.create_container(...).await?;
docker.start_container(...).await?;
docker.list_containers(...).await?;

2. エラーの詳細な分類

ステータスコードで適切にハンドリング:

match result {
    Err(Error::DockerResponseServerError { status_code: 404, .. }) => {
        // イメージが見つからない → pull
    }
    Err(Error::DockerResponseServerError { status_code: 409, .. }) => {
        // 既に存在 → 起動試行
    }
    Err(Error::DockerResponseServerError { status_code: 500, .. }) => {
        // サーバーエラー(ポート競合など)
    }
    Ok(result) => { /* 成功 */ }
    Err(e) => { /* その他 */ }
}

3. 非同期処理の適切な使用

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let docker = Docker::connect_with_local_defaults()?;
    let containers = docker.list_containers(None).await?;
    Ok(())
}

詳細リファレンス

詳細な実装例とパターンについては、以下のリファレンスを参照してください:

外部リンク

よくある実装機能

Bollardを使って実装できる機能:

  • イメージの自動pull
  • コンテナログのストリーミング表示
  • ヘルスチェック
  • 依存関係順の起動制御
  • リソース制限設定
  • ネットワーク自動作成・管理
  • ボリューム自動管理