docker-wrapper 0.11.1

A Docker CLI wrapper for Rust
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# Docker Rust Libraries Comparison Guide

This guide helps you choose the right Docker library for your Rust project by comparing docker-wrapper with other popular options like bollard, testcontainers-rs, and raw Docker CLI usage.

## Quick Decision Tree

```
Need containers in Rust?
├── Just for integration tests? → testcontainers-rs
├── Building a container platform/orchestrator? → bollard
├── Building CLI tools or automation scripts? → docker-wrapper
├── Need subprocess control & familiar CLI behavior? → docker-wrapper  
├── Maximum performance for production services? → bollard
├── Want simple Docker-CLI-like API? → docker-wrapper
└── Already have shell scripts to port? → docker-wrapper
```

## Library Comparison Matrix

| Feature | docker-wrapper | bollard | testcontainers-rs | Raw CLI |
|---------|---------------|---------|-------------------|---------|
| **Approach** | CLI subprocess wrapper | Direct Docker API client | Test-focused abstraction | Shell commands |
| **Learning Curve** | Low (Docker CLI knowledge) | Medium (Docker API knowledge) | Low (test-focused) | High (error handling) |
| **Dependencies** | Docker CLI required | None (direct HTTP/socket) | Docker CLI required | Docker CLI required |
| **Performance** | Medium (subprocess overhead) | High (direct API) | Medium | Low (manual parsing) |
| **Feature Coverage** | Complete CLI feature set | Complete API feature set | Test-focused subset | Complete CLI feature set |
| **Error Handling** | Docker CLI error messages | Raw API error responses | Test-friendly errors | Manual parsing required |
| **Compatibility** | Follows Docker CLI changes | Follows API versions | Limited scope | Manual maintenance |
| **Async Support** | Full tokio support | Native async | Test-focused async | Manual implementation |
| **Streaming** | Output streaming | Advanced streaming | Limited | Complex to implement |
| **Production Ready** | Yes | Yes | No (test-focused) | Depends on implementation |

## Use Case Recommendations

### Choose docker-wrapper when:

- **Building CLI tools** or automation scripts
- **Developer tools** that manage containers  
- **CI/CD pipelines** and deployment automation
- **Docker Compose** integration is needed
- **Familiar CLI behavior** is important
- **Cross-runtime support** (Docker + Podman) is needed
- **Prototyping** or **scripting** container workflows
- **Migrating from shell scripts** to Rust
- **Simple container management** for applications

**Example use cases:**
- Development environment setup tools
- Deployment automation scripts  
- Container management CLIs
- Docker Compose workflow automation
- Multi-environment deployment tools

### Choose bollard when:

- **Building container platforms** or orchestrators
- **Production services** managing many containers
- **High-performance** container operations
- **Fine-grained control** over Docker daemon
- **Streaming logs/events** from many containers
- **Container runtime integration** in services
- **Low-level Docker API** access needed

**Example use cases:**
- Container orchestration platforms
- Monitoring and observability tools
- Container-as-a-Service platforms
- CI/CD runners (like GitHub Actions)
- Container security scanning tools

### Choose testcontainers-rs when:

- **Integration testing** is the primary use case
- **Database/service testing** with real containers
- **Test isolation** and **automatic cleanup** needed
- **Pre-built modules** for common services
- **JUnit/TestNG-style** container lifecycle

**Example use cases:**
- Integration tests for microservices
- Database-dependent tests
- End-to-end testing scenarios
- API testing with external dependencies

### Avoid raw Docker CLI when:

- You need robust error handling
- Performance is important  
- Cross-platform compatibility matters
- You want type safety and good APIs

## Performance Comparison

| Operation | docker-wrapper | bollard | testcontainers-rs | Notes |
|-----------|---------------|---------|-------------------|-------|
| **Startup overhead** | Higher (subprocess) | Lower (HTTP connection) | Higher (abstraction layer) | Per command |
| **Bulk operations** | Slower (process spawning) | Fastest (direct API) | Medium (optimized for tests) | Many containers |
| **Memory usage** | Lower (subprocess cleanup) | Medium (connection pools) | Medium (test lifecycle) | Runtime footprint |
| **CPU usage** | Higher (process spawning) | Lower (HTTP calls) | Medium | Sustained operations |
| **Concurrent operations** | Limited (process pools) | Excellent (async HTTP) | Good (parallel tests) | Scalability |

## Code Comparison Examples

### Starting a Container

#### docker-wrapper
```rust
use docker_wrapper::RunCommand;

let result = RunCommand::new("redis:latest")
    .name("my-redis")
    .detach()
    .port(6379, 6379)
    .env("REDIS_PASSWORD", "secret")
    .run()
    .await?;

println!("Container ID: {}", result.container_id());
```

#### bollard
```rust
use bollard::{Docker, container::{Config, CreateContainerOptions}};
use bollard::service::{HostConfig, PortBinding};
use std::collections::HashMap;

let docker = Docker::connect_with_local_defaults()?;

let config = Config {
    image: Some("redis:latest"),
    env: Some(vec!["REDIS_PASSWORD=secret"]),
    host_config: Some(HostConfig {
        port_bindings: Some(HashMap::from([(
            "6379/tcp".to_string(),
            Some(vec![PortBinding {
                host_port: Some("6379".to_string()),
                ..Default::default()
            }])
        )])),
        ..Default::default()
    }),
    ..Default::default()
};

let container = docker.create_container(
    Some(CreateContainerOptions { 
        name: "my-redis",
        platform: None,
    }), 
    config
).await?;

docker.start_container::<String>(&container.id, None).await?;
```

#### testcontainers-rs  
```rust
use testcontainers::{runners::AsyncRunner, GenericImage};

let container = GenericImage::new("redis", "latest")
    .with_exposed_port(6379)
    .start()
    .await?;
let port = container.get_host_port_ipv4(6379)?;
```

### Key Differences

1. **docker-wrapper**: Mirrors Docker CLI exactly - familiar and predictable
2. **bollard**: Requires understanding Docker API structure - more verbose but flexible  
3. **testcontainers**: Optimized for testing - simple but limited scope

## Feature Deep Dive

### Docker Compose Support

| Library | Support Level | Implementation |
|---------|--------------|----------------|
| **docker-wrapper** | Full native support | Direct `docker compose` commands |
| **bollard** | No support | API doesn't include Compose |
| **testcontainers-rs** | Limited | Some compose support for tests |
| **Raw CLI** | Full support | Manual `docker-compose` calls |

### Cross-Platform Runtime Support

| Library | Docker | Podman | Docker Desktop | Other Runtimes |
|---------|--------|--------|---------------|----------------|
| **docker-wrapper** | Yes | Yes | Yes | Yes (any Docker CLI compatible) |
| **bollard** | Yes | Yes (with socket setup) | Yes | Yes (if API compatible) |
| **testcontainers-rs** | Yes | Yes (with configuration) | Yes | Depends on Docker compatibility |

*Note: Podman support typically requires Docker compatibility mode enabled*

### Error Handling Quality

#### docker-wrapper
```rust
// User-friendly Docker CLI error messages
Error: Container 'my-app' is already running
Error: Image 'nginx:invalid-tag' not found
Error: Port 80 is already allocated
```

#### bollard  
```rust
// Raw API error responses
Error: API responded with status 409: Conflict
Error: API responded with status 404: Not Found  
Error: API responded with status 400: Bad Request
```

## Migration Guides

### From Shell Scripts to docker-wrapper

**Before (Bash):**
```bash
#!/bin/bash
docker run -d --name redis \
  -p 6379:6379 \
  -e REDIS_PASSWORD=secret \
  redis:latest

if [ $? -eq 0 ]; then
  echo "Redis started successfully"
else
  echo "Failed to start Redis"
  exit 1
fi
```

**After (Rust with docker-wrapper):**
```rust
use docker_wrapper::RunCommand;

let result = RunCommand::new("redis:latest")
    .name("redis")
    .detach()
    .port(6379, 6379)
    .env("REDIS_PASSWORD", "secret")
    .run()
    .await?;

if result.is_success() {
    println!("Redis started successfully");
} else {
    eprintln!("Failed to start Redis");
    return Err(result.error())?;
}
```

### From testcontainers-rs to docker-wrapper

**Before (testcontainers-rs):**
```rust
#[tokio::test]
async fn test_redis_connection() {
    use testcontainers::{runners::AsyncRunner, GenericImage};
    
    let container = GenericImage::new("redis", "latest")
        .with_exposed_port(6379)
        .start()
        .await?;
    let port = container.get_host_port_ipv4(6379)?;
    
    // Test logic here
    
    // Container automatically cleaned up
}
```

**After (docker-wrapper):**
```rust  
#[tokio::test]
async fn test_redis_connection() {
    let container = RunCommand::new("redis:latest")
        .name("test-redis")
        .port(6379, 0) // Random host port
        .detach()
        .remove() // Auto-remove when stopped
        .run()
        .await?;
        
    let port = container.port_mapping(6379)?;
    
    // Test logic here
    
    StopCommand::new("test-redis").run().await?;
    // Container auto-removed due to --rm flag
}
```

### From bollard to docker-wrapper

**Before (bollard):**
```rust
use bollard::{Docker, container::ListContainersOptions};
use std::collections::HashMap;

let docker = Docker::connect_with_local_defaults()?;

let containers = docker.list_containers(Some(ListContainersOptions::<String> {
    all: true,
    filters: HashMap::from([
        ("status".to_string(), vec!["running".to_string()])
    ]),
    ..Default::default()
})).await?;

for container in containers {
    println!("Container: {} ({})", 
        container.names.unwrap_or_default().join(","),
        container.id.unwrap_or_default()
    );
}
```

**After (docker-wrapper):**
```rust
let result = PsCommand::new()
    .all()
    .filter("status", "running")
    .run()
    .await?;

for container in result.containers() {
    println!("Container: {} ({})", 
        container.name(), 
        container.id()
    );
}
```

## Real-World Examples

### Example 1: Development Environment Setup Tool

**Scenario**: CLI tool to set up development environments with databases and services.

**Why docker-wrapper?**
- Users expect Docker CLI-like behavior
- Need Docker Compose support for complex stacks  
- Cross-platform compatibility (developers use different Docker setups)
- Error messages should be familiar to Docker users

```rust
use docker_wrapper::{RunCommand, ComposeUpCommand};

// Start individual services
let postgres = RunCommand::new("postgres:13")
    .name("dev-postgres")
    .env("POSTGRES_PASSWORD", "dev")
    .port(5432, 5432)
    .detach()
    .run().await?;

// Or start entire stack with Compose
let stack = ComposeUpCommand::new()
    .file("docker-compose.dev.yml")
    .detach()
    .run().await?;
```

### Example 2: CI/CD Pipeline Container Management  

**Scenario**: Build system that runs tests in isolated containers.

**Why docker-wrapper?**
- Familiar Docker CLI commands for DevOps teams
- Need reliable subprocess control
- Integration with existing Docker-based build processes
- Simple container lifecycle management

```rust
use docker_wrapper::{RunCommand, BuildCommand};

// Build test image  
let build = BuildCommand::new(".")
    .tag("app:test")
    .run().await?;

// Run tests in container
let test_result = RunCommand::new("app:test")
    .cmd(vec!["cargo".to_string(), "test".to_string()])
    .volume("./target:/app/target")  
    .remove() // Clean up after test
    .run().await?;

if !test_result.is_success() {
    return Err("Tests failed".into());
}
```

### Example 3: Container Monitoring Platform

**Scenario**: Production service that monitors and manages hundreds of containers.

**Why bollard?**
- High performance for many concurrent operations
- Real-time event streaming from Docker daemon
- Fine-grained control over container lifecycle  
- Integration into long-running service architecture

```rust
use bollard::{Docker, system::{EventsOptions, EventMessage}};
use futures::stream::StreamExt;
use std::collections::HashMap;

let docker = Docker::connect_with_local_defaults()?;

// Stream container events in real-time
let mut events = docker.events(Some(EventsOptions::<String> {
    filters: HashMap::from([
        ("type".to_string(), vec!["container".to_string()])
    ]),
    ..Default::default()
}));

while let Some(event) = events.next().await {
    match event? {
        EventMessage { 
            action: Some(action), 
            actor: Some(actor), 
            .. 
        } => {
            println!("Container {} {}", 
                actor.id.unwrap_or_default(), 
                action
            );
            // Handle container lifecycle events
        }
        _ => {}
    }
}
```

## Performance Characteristics

### Expected Performance Trade-offs

**docker-wrapper**
- **Startup**: Higher latency due to subprocess spawning
- **Throughput**: Limited by process creation overhead  
- **Memory**: Lower baseline, processes cleaned up after commands
- **Concurrency**: Constrained by system process limits

**bollard**  
- **Startup**: Lower latency with direct HTTP API calls
- **Throughput**: Higher throughput with persistent connections
- **Memory**: Higher baseline due to connection pools and caching
- **Concurrency**: Excellent async performance

**testcontainers-rs**
- **Startup**: Higher latency due to test framework abstractions
- **Throughput**: Optimized for test scenarios, not production workloads  
- **Memory**: Test lifecycle management adds overhead
- **Concurrency**: Good for parallel test execution

*Note: Actual performance will vary significantly based on your specific use case, system configuration, and Docker setup. Consider benchmarking with your own workload for accurate comparisons.*

## Summary

### Choose docker-wrapper for:
- CLI tools and automation scripts
- Docker Compose workflows  
- Rapid prototyping and development
- Familiar Docker CLI behavior
- Cross-platform Docker runtime support

### Choose bollard for:
- Container platforms and orchestrators
- High-performance production services  
- Real-time monitoring and events
- Fine-grained Docker API control
- Scalable container management

### Choose testcontainers-rs for:
- Integration testing scenarios
- Database-dependent tests  
- Test isolation and cleanup
- Pre-built service modules
- Quick test environment setup

---

*This comparison is maintained by the docker-wrapper community. For corrections or updates, please open an issue or pull request.*