745 lines
18 KiB
Markdown
745 lines
18 KiB
Markdown
|
|
# Runtime Crate - Comprehensive Integration Guide
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
The Runtime crate provides a unified abstraction layer for managing multiple container runtimes across different platforms and architectures. This guide covers advanced integration patterns, platform-specific considerations, and best practices for using the runtime crate in production environments.
|
||
|
|
|
||
|
|
## Table of Contents
|
||
|
|
|
||
|
|
1. [Supported Runtimes](#supported-runtimes)
|
||
|
|
2. [Platform Detection Strategy](#platform-detection-strategy)
|
||
|
|
3. [Socket Path Configuration](#socket-path-configuration)
|
||
|
|
4. [Remote Runtime Access](#remote-runtime-access)
|
||
|
|
5. [Docker Compose Integration](#docker-compose-integration)
|
||
|
|
6. [Configuration Patterns](#configuration-patterns)
|
||
|
|
7. [Error Handling](#error-handling)
|
||
|
|
8. [Performance Tuning](#performance-tuning)
|
||
|
|
9. [Security Considerations](#security-considerations)
|
||
|
|
10. [Troubleshooting](#troubleshooting)
|
||
|
|
|
||
|
|
## Supported Runtimes
|
||
|
|
|
||
|
|
### Docker
|
||
|
|
|
||
|
|
**Platforms**: Linux, macOS (Docker Desktop), Windows (WSL2)
|
||
|
|
|
||
|
|
**Socket Paths**:
|
||
|
|
- Linux: `/var/run/docker.sock`
|
||
|
|
- macOS: `~/.docker/run/docker.sock` (Docker Desktop)
|
||
|
|
- Windows/WSL2: `/var/run/docker.sock`
|
||
|
|
|
||
|
|
**Key Features**:
|
||
|
|
- Industry-standard container runtime
|
||
|
|
- Full Docker Compose support
|
||
|
|
- TLS certificate support
|
||
|
|
- Buildkit support
|
||
|
|
|
||
|
|
**Configuration Example**:
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimeType};
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
runtime: RuntimeType::Docker,
|
||
|
|
socket_path: "/var/run/docker.sock".to_string(),
|
||
|
|
environment: [
|
||
|
|
("DOCKER_HOST".to_string(), "unix:///var/run/docker.sock".to_string()),
|
||
|
|
].iter().cloned().collect(),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Podman
|
||
|
|
|
||
|
|
**Platforms**: Linux (all distributions), macOS (rootless mode)
|
||
|
|
|
||
|
|
**Socket Paths**:
|
||
|
|
- Linux root: `/run/podman/podman.sock`
|
||
|
|
- Linux rootless: `$XDG_RUNTIME_DIR/podman/podman.sock`
|
||
|
|
- macOS: `$XDG_RUNTIME_DIR/podman/podman.sock`
|
||
|
|
|
||
|
|
**Key Features**:
|
||
|
|
- Docker-compatible API
|
||
|
|
- Rootless container execution
|
||
|
|
- Systemd integration
|
||
|
|
- Podman Compose support
|
||
|
|
|
||
|
|
**Rootless Configuration**:
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimeType};
|
||
|
|
|
||
|
|
let xdg_runtime = std::env::var("XDG_RUNTIME_DIR")
|
||
|
|
.unwrap_or_else(|_| format!("/run/user/{}", unsafe { libc::getuid() }));
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
runtime: RuntimeType::Podman,
|
||
|
|
socket_path: format!("{}/podman/podman.sock", xdg_runtime),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### OrbStack
|
||
|
|
|
||
|
|
**Platforms**: macOS (Intel and Apple Silicon) - Default macOS runtime
|
||
|
|
|
||
|
|
**Socket Path**: `~/.orbstack/run/docker.sock`
|
||
|
|
|
||
|
|
**Key Features**:
|
||
|
|
- Fastest macOS container runtime
|
||
|
|
- Native integration with macOS filesystem
|
||
|
|
- Full Docker Compose compatibility
|
||
|
|
- Minimal resource overhead
|
||
|
|
|
||
|
|
**Configuration Example**:
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimeType};
|
||
|
|
|
||
|
|
let home = std::env::var("HOME").expect("HOME not set");
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
runtime: RuntimeType::OrbStack,
|
||
|
|
socket_path: format!("{}/.orbstack/run/docker.sock", home),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Colima
|
||
|
|
|
||
|
|
**Platforms**: macOS, Linux (via Lima)
|
||
|
|
|
||
|
|
**Socket Paths**:
|
||
|
|
- macOS: `~/.colima/docker.sock`
|
||
|
|
- Linux: `/var/run/docker.sock` (proxied via Colima)
|
||
|
|
|
||
|
|
**Key Features**:
|
||
|
|
- Lightweight VM-based runtime
|
||
|
|
- Docker CLI compatibility
|
||
|
|
- Resource isolation
|
||
|
|
- Cross-platform support
|
||
|
|
|
||
|
|
### nerdctl
|
||
|
|
|
||
|
|
**Platforms**: Linux, macOS, Windows
|
||
|
|
|
||
|
|
**Socket Path**: `unix:///run/containerd/containerd.sock`
|
||
|
|
|
||
|
|
**Key Features**:
|
||
|
|
- containerd-based runtime
|
||
|
|
- Docker-compatible CLI
|
||
|
|
- Efficient resource usage
|
||
|
|
- Kubernetes integration
|
||
|
|
|
||
|
|
## Platform Detection Strategy
|
||
|
|
|
||
|
|
The runtime crate implements intelligent platform-specific detection:
|
||
|
|
|
||
|
|
### Linux Detection Priority
|
||
|
|
|
||
|
|
```
|
||
|
|
1. Docker (socket: /var/run/docker.sock)
|
||
|
|
2. Podman rootless (socket: $XDG_RUNTIME_DIR/podman/podman.sock)
|
||
|
|
3. Podman root (socket: /run/podman/podman.sock)
|
||
|
|
4. nerdctl (socket: unix:///run/containerd/containerd.sock)
|
||
|
|
5. Colima (socket: ~/.colima/docker.sock)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Implementation**:
|
||
|
|
```rust
|
||
|
|
use runtime::detect_runtime;
|
||
|
|
|
||
|
|
#[tokio::main]
|
||
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
|
|
let runtime = detect_runtime().await?;
|
||
|
|
|
||
|
|
match runtime {
|
||
|
|
RuntimeType::Docker => println!("Using Docker"),
|
||
|
|
RuntimeType::Podman => println!("Using Podman"),
|
||
|
|
_ => println!("Using: {}", runtime.name()),
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### macOS Detection Priority
|
||
|
|
|
||
|
|
```
|
||
|
|
1. OrbStack (socket: ~/.orbstack/run/docker.sock)
|
||
|
|
2. Docker Desktop (socket: ~/.docker/run/docker.sock)
|
||
|
|
3. Colima (socket: ~/.colima/docker.sock)
|
||
|
|
4. Podman (socket: $XDG_RUNTIME_DIR/podman/podman.sock)
|
||
|
|
5. nerdctl (socket: unix:///run/containerd/containerd.sock)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Rationale**: OrbStack offers superior performance on macOS compared to Docker Desktop, so it's preferred when available.
|
||
|
|
|
||
|
|
### Windows Detection
|
||
|
|
|
||
|
|
Windows requires WSL2 (Windows Subsystem for Linux 2) for container support. The detection mechanism checks for available runtimes within WSL2 and follows the Linux priority list.
|
||
|
|
|
||
|
|
## Socket Path Configuration
|
||
|
|
|
||
|
|
### Standard Socket Paths
|
||
|
|
|
||
|
|
Each runtime exposes a well-known socket path for communication:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeType;
|
||
|
|
|
||
|
|
fn get_socket_path(runtime: RuntimeType) -> String {
|
||
|
|
match runtime {
|
||
|
|
RuntimeType::Docker => "/var/run/docker.sock".to_string(),
|
||
|
|
RuntimeType::Podman => {
|
||
|
|
std::env::var("XDG_RUNTIME_DIR")
|
||
|
|
.map(|xdg| format!("{}/podman/podman.sock", xdg))
|
||
|
|
.unwrap_or_else(|_| "/run/podman/podman.sock".to_string())
|
||
|
|
}
|
||
|
|
RuntimeType::OrbStack => {
|
||
|
|
let home = std::env::var("HOME").expect("HOME not set");
|
||
|
|
format!("{}/.orbstack/run/docker.sock", home)
|
||
|
|
}
|
||
|
|
RuntimeType::Colima => {
|
||
|
|
let home = std::env::var("HOME").expect("HOME not set");
|
||
|
|
format!("{}/.colima/docker.sock", home)
|
||
|
|
}
|
||
|
|
RuntimeType::Nerdctl => "unix:///run/containerd/containerd.sock".to_string(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Custom Socket Paths
|
||
|
|
|
||
|
|
For non-standard configurations (e.g., custom Docker socket location, remote access):
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimeType};
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
runtime: RuntimeType::Docker,
|
||
|
|
socket_path: "/custom/docker.sock".to_string(),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Environment Variable Overrides
|
||
|
|
|
||
|
|
Use environment variables for dynamic configuration:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeConfig;
|
||
|
|
|
||
|
|
let socket_path = std::env::var("RUNTIME_SOCKET_PATH")
|
||
|
|
.unwrap_or_else(|_| "/var/run/docker.sock".to_string());
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
socket_path,
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
## Remote Runtime Access
|
||
|
|
|
||
|
|
### SSH-Based Remote Access
|
||
|
|
|
||
|
|
Configure remote runtime access via SSH:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RemoteConfig};
|
||
|
|
|
||
|
|
let remote = RemoteConfig {
|
||
|
|
enabled: true,
|
||
|
|
host: "docker.example.com".to_string(),
|
||
|
|
user: "docker-user".to_string(),
|
||
|
|
port: 22,
|
||
|
|
private_key: Some("/home/user/.ssh/id_rsa".to_string()),
|
||
|
|
password: None,
|
||
|
|
known_hosts: Some("/home/user/.ssh/known_hosts".to_string()),
|
||
|
|
jump_host: None, // For bastion/jump host scenarios
|
||
|
|
};
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
remote_config: Some(remote),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Jump Host Configuration
|
||
|
|
|
||
|
|
For accessing runtimes through a bastion host:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RemoteConfig};
|
||
|
|
|
||
|
|
let jump_host = RemoteConfig {
|
||
|
|
host: "bastion.example.com".to_string(),
|
||
|
|
user: "bastion-user".to_string(),
|
||
|
|
private_key: Some("/home/user/.ssh/bastion_key".to_string()),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
let remote = RemoteConfig {
|
||
|
|
enabled: true,
|
||
|
|
host: "docker.internal.example.com".to_string(),
|
||
|
|
user: "docker-user".to_string(),
|
||
|
|
private_key: Some("/home/user/.ssh/docker_key".to_string()),
|
||
|
|
jump_host: Some(Box::new(jump_host)),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
remote_config: Some(remote),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### TLS/HTTPS Remote Access
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeConfig;
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
socket_path: "tcp://docker.example.com:2376".to_string(),
|
||
|
|
environment: [
|
||
|
|
("DOCKER_HOST".to_string(), "tcp://docker.example.com:2376".to_string()),
|
||
|
|
("DOCKER_CERT_PATH".to_string(), "/path/to/certs".to_string()),
|
||
|
|
("DOCKER_TLS_VERIFY".to_string(), "1".to_string()),
|
||
|
|
].iter().cloned().collect(),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
## Docker Compose Integration
|
||
|
|
|
||
|
|
### Automatic Compose Adaptation
|
||
|
|
|
||
|
|
The runtime crate can adapt Docker Compose files for different runtimes:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::adapt_compose;
|
||
|
|
|
||
|
|
#[tokio::main]
|
||
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
|
|
let adapted = adapt_compose(
|
||
|
|
"docker-compose.yaml",
|
||
|
|
RuntimeType::Podman
|
||
|
|
).await?;
|
||
|
|
|
||
|
|
println!("Adapted compose: {}", adapted);
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Compose File Differences
|
||
|
|
|
||
|
|
Different runtimes may require compose file adjustments:
|
||
|
|
|
||
|
|
**Docker** (Standard):
|
||
|
|
```yaml
|
||
|
|
version: '3.8'
|
||
|
|
services:
|
||
|
|
app:
|
||
|
|
image: my-app:latest
|
||
|
|
ports:
|
||
|
|
- "8080:8080"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Podman** (Rootless considerations):
|
||
|
|
```yaml
|
||
|
|
version: '3.8'
|
||
|
|
services:
|
||
|
|
app:
|
||
|
|
image: my-app:latest
|
||
|
|
ports:
|
||
|
|
- "8080:8080"
|
||
|
|
# May require podman-compose specific directives
|
||
|
|
```
|
||
|
|
|
||
|
|
**OrbStack** (Filesystem integration):
|
||
|
|
```yaml
|
||
|
|
version: '3.8'
|
||
|
|
services:
|
||
|
|
app:
|
||
|
|
image: my-app:latest
|
||
|
|
volumes:
|
||
|
|
- ./data:/data:z # z flag for SELinux compatibility
|
||
|
|
```
|
||
|
|
|
||
|
|
### Compose Version Support
|
||
|
|
|
||
|
|
- **Version 3.x**: Fully supported across all runtimes
|
||
|
|
- **Version 2.x**: Limited support; migration recommended
|
||
|
|
- **Buildx Compose**: Docker and Podman only
|
||
|
|
|
||
|
|
## Configuration Patterns
|
||
|
|
|
||
|
|
### Environment-Based Configuration
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimeType};
|
||
|
|
|
||
|
|
fn load_config_from_env() -> RuntimeConfig {
|
||
|
|
let runtime_type = std::env::var("CONTAINER_RUNTIME")
|
||
|
|
.unwrap_or_else(|_| "docker".to_string());
|
||
|
|
|
||
|
|
let socket_path = std::env::var("CONTAINER_SOCKET")
|
||
|
|
.unwrap_or_else(|_| {
|
||
|
|
match runtime_type.as_str() {
|
||
|
|
"podman" => "$XDG_RUNTIME_DIR/podman/podman.sock".to_string(),
|
||
|
|
_ => "/var/run/docker.sock".to_string(),
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
RuntimeConfig {
|
||
|
|
runtime: RuntimeType::from_str(&runtime_type).unwrap_or(RuntimeType::Docker),
|
||
|
|
socket_path,
|
||
|
|
..Default::default()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### File-Based Configuration
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use serde::{Deserialize, Serialize};
|
||
|
|
use std::fs;
|
||
|
|
|
||
|
|
#[derive(Serialize, Deserialize)]
|
||
|
|
struct RuntimeSettings {
|
||
|
|
runtime: String,
|
||
|
|
socket_path: String,
|
||
|
|
environment: std::collections::HashMap<String, String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
fn load_config_from_file(path: &str) -> Result<RuntimeSettings, Box<dyn std::error::Error>> {
|
||
|
|
let content = fs::read_to_string(path)?;
|
||
|
|
let settings: RuntimeSettings = serde_json::from_str(&content)?;
|
||
|
|
Ok(settings)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Builder Pattern Configuration
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimeType};
|
||
|
|
|
||
|
|
let config = RuntimeConfig::builder()
|
||
|
|
.runtime(RuntimeType::Docker)
|
||
|
|
.socket_path("/var/run/docker.sock")
|
||
|
|
.with_env("DOCKER_BUILDKIT", "1")
|
||
|
|
.with_env("COMPOSE_DOCKER_CLI_BUILD", "1")
|
||
|
|
.build();
|
||
|
|
```
|
||
|
|
|
||
|
|
## Error Handling
|
||
|
|
|
||
|
|
### Common Error Scenarios
|
||
|
|
|
||
|
|
**Socket Not Found**:
|
||
|
|
```rust
|
||
|
|
use runtime::{detect_runtime, RuntimeError};
|
||
|
|
|
||
|
|
#[tokio::main]
|
||
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
|
|
match detect_runtime().await {
|
||
|
|
Ok(runtime) => println!("Found: {}", runtime.name()),
|
||
|
|
Err(RuntimeError::SocketNotFound(path)) => {
|
||
|
|
eprintln!("Docker socket not found at {}", path);
|
||
|
|
eprintln!("Please ensure Docker/Podman is running");
|
||
|
|
}
|
||
|
|
Err(e) => eprintln!("Error: {}", e),
|
||
|
|
}
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Permission Denied**:
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeError;
|
||
|
|
|
||
|
|
match some_operation().await {
|
||
|
|
Err(RuntimeError::PermissionDenied) => {
|
||
|
|
eprintln!("Cannot access runtime socket");
|
||
|
|
eprintln!("Try: sudo usermod -aG docker $USER");
|
||
|
|
}
|
||
|
|
Err(e) => eprintln!("Error: {}", e),
|
||
|
|
Ok(result) => println!("Success: {:?}", result),
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Connection Timeout**:
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeError;
|
||
|
|
use std::time::Duration;
|
||
|
|
|
||
|
|
match runtime.with_timeout(Duration::from_secs(5)).info().await {
|
||
|
|
Err(RuntimeError::Timeout) => {
|
||
|
|
eprintln!("Runtime unresponsive (timeout after 5s)");
|
||
|
|
eprintln!("Check if Docker/Podman is running");
|
||
|
|
}
|
||
|
|
Err(e) => eprintln!("Error: {}", e),
|
||
|
|
Ok(info) => println!("Runtime info: {:?}", info),
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance Tuning
|
||
|
|
|
||
|
|
### Connection Pooling
|
||
|
|
|
||
|
|
For applications making many runtime calls:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimePool};
|
||
|
|
|
||
|
|
let pool = RuntimePool::with_size(
|
||
|
|
RuntimeConfig::default(),
|
||
|
|
10 // Pool size
|
||
|
|
);
|
||
|
|
|
||
|
|
// Acquire connections from pool
|
||
|
|
let runtime = pool.get().await?;
|
||
|
|
runtime.info().await?;
|
||
|
|
runtime.close().await?;
|
||
|
|
```
|
||
|
|
|
||
|
|
### Caching Runtime Information
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::detect_runtime;
|
||
|
|
use std::sync::Arc;
|
||
|
|
use tokio::sync::Mutex;
|
||
|
|
|
||
|
|
#[tokio::main]
|
||
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
|
|
let runtime = Arc::new(Mutex::new(detect_runtime().await?));
|
||
|
|
|
||
|
|
// Use cached runtime across async tasks
|
||
|
|
let runtime_clone = Arc::clone(&runtime);
|
||
|
|
tokio::spawn(async move {
|
||
|
|
let rt = runtime_clone.lock().await;
|
||
|
|
// Use cached runtime
|
||
|
|
}).await?;
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Batch Operations
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeBatch;
|
||
|
|
|
||
|
|
let batch = RuntimeBatch::new(runtime);
|
||
|
|
|
||
|
|
batch
|
||
|
|
.add_pull("image:tag")
|
||
|
|
.add_build("/path/to/dockerfile", "image:tag")
|
||
|
|
.add_run("image:tag", vec!["command"])
|
||
|
|
.execute()
|
||
|
|
.await?;
|
||
|
|
```
|
||
|
|
|
||
|
|
## Security Considerations
|
||
|
|
|
||
|
|
### Socket Permissions
|
||
|
|
|
||
|
|
Ensure proper socket file permissions:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Docker socket (default)
|
||
|
|
ls -l /var/run/docker.sock
|
||
|
|
# Should be: srw-rw---- root docker
|
||
|
|
|
||
|
|
# Podman socket (rootless)
|
||
|
|
ls -l $XDG_RUNTIME_DIR/podman/podman.sock
|
||
|
|
# Should be: srw------- (user only)
|
||
|
|
```
|
||
|
|
|
||
|
|
### User Privileges
|
||
|
|
|
||
|
|
For rootless containers:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeConfig;
|
||
|
|
|
||
|
|
// Verify running as unprivileged user
|
||
|
|
if unsafe { libc::getuid() } == 0 {
|
||
|
|
eprintln!("Warning: Running container operations as root");
|
||
|
|
eprintln!("Consider using rootless podman for security");
|
||
|
|
}
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
// Configure for rootless operation
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### TLS Certificates
|
||
|
|
|
||
|
|
For remote access with TLS:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeConfig;
|
||
|
|
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
tls_config: Some(TlsConfig {
|
||
|
|
ca_cert: "/path/to/ca.pem".to_string(),
|
||
|
|
client_cert: "/path/to/cert.pem".to_string(),
|
||
|
|
client_key: "/path/to/key.pem".to_string(),
|
||
|
|
verify: true,
|
||
|
|
}),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Environment Variable Sanitization
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::RuntimeConfig;
|
||
|
|
|
||
|
|
// Avoid storing sensitive data in environment variables
|
||
|
|
let config = RuntimeConfig {
|
||
|
|
environment: [
|
||
|
|
// Only non-sensitive variables
|
||
|
|
("DOCKER_BUILDKIT".to_string(), "1".to_string()),
|
||
|
|
].iter().cloned().collect(),
|
||
|
|
// Load secrets from secure sources instead
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Runtime Not Detected
|
||
|
|
|
||
|
|
**Symptoms**: `detect_runtime()` fails or returns unexpected runtime
|
||
|
|
|
||
|
|
**Diagnosis**:
|
||
|
|
```bash
|
||
|
|
# Check if socket exists
|
||
|
|
ls -l /var/run/docker.sock
|
||
|
|
# or
|
||
|
|
echo $XDG_RUNTIME_DIR
|
||
|
|
ls -l $XDG_RUNTIME_DIR/podman/podman.sock
|
||
|
|
```
|
||
|
|
|
||
|
|
**Solutions**:
|
||
|
|
1. Ensure container runtime is installed
|
||
|
|
2. Start the runtime service: `systemctl start docker` or `systemctl --user start podman`
|
||
|
|
3. Check socket permissions: `sudo usermod -aG docker $USER`
|
||
|
|
|
||
|
|
### Connection Refused
|
||
|
|
|
||
|
|
**Symptoms**: Operations fail with "Connection refused"
|
||
|
|
|
||
|
|
**Diagnosis**:
|
||
|
|
```bash
|
||
|
|
# Test socket connectivity
|
||
|
|
docker ps # or podman ps
|
||
|
|
# If this fails, daemon isn't running
|
||
|
|
```
|
||
|
|
|
||
|
|
**Solutions**:
|
||
|
|
1. Start Docker/Podman daemon
|
||
|
|
2. Check if socket is accessible
|
||
|
|
3. Verify firewall rules for remote access
|
||
|
|
|
||
|
|
### Compose Adaptation Issues
|
||
|
|
|
||
|
|
**Symptoms**: Adapted compose file has errors
|
||
|
|
|
||
|
|
**Solutions**:
|
||
|
|
1. Validate compose file: `docker compose config`
|
||
|
|
2. Check runtime-specific requirements
|
||
|
|
3. Review crate documentation for compatibility matrix
|
||
|
|
|
||
|
|
### Performance Issues
|
||
|
|
|
||
|
|
**Symptoms**: Slow image pulls, container operations
|
||
|
|
|
||
|
|
**Solutions**:
|
||
|
|
1. Check network connectivity
|
||
|
|
2. Monitor disk space for image storage
|
||
|
|
3. Enable BuildKit: `export DOCKER_BUILDKIT=1`
|
||
|
|
4. Consider using image registry caching
|
||
|
|
|
||
|
|
## Integration Patterns
|
||
|
|
|
||
|
|
### Kubernetes Integration
|
||
|
|
|
||
|
|
For Kubernetes environments using Docker or CRI-compatible runtimes:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::detect_runtime;
|
||
|
|
|
||
|
|
#[tokio::main]
|
||
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
|
|
// Detect runtime as per container spec
|
||
|
|
let runtime = detect_runtime().await?;
|
||
|
|
|
||
|
|
// Use for image operations before pod deployment
|
||
|
|
runtime.pull("image:tag").await?;
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### CI/CD Pipeline Integration
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{detect_runtime, RuntimeConfig};
|
||
|
|
|
||
|
|
#[tokio::main]
|
||
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||
|
|
// Auto-detect available runtime in CI environment
|
||
|
|
let runtime = detect_runtime().await?;
|
||
|
|
|
||
|
|
// Build image
|
||
|
|
runtime.build("/app", "my-image:latest").await?;
|
||
|
|
|
||
|
|
// Test container
|
||
|
|
runtime.run("my-image:latest", vec!["cargo", "test"]).await?;
|
||
|
|
|
||
|
|
// Push to registry
|
||
|
|
runtime.push("my-image:latest").await?;
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Multi-Environment Deployment
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use runtime::{RuntimeConfig, RuntimeType};
|
||
|
|
|
||
|
|
fn get_config_for_environment(env: &str) -> RuntimeConfig {
|
||
|
|
match env {
|
||
|
|
"development" => {
|
||
|
|
// Local development: use detected runtime
|
||
|
|
RuntimeConfig::default()
|
||
|
|
}
|
||
|
|
"staging" => {
|
||
|
|
// Staging: connect to staging Docker host
|
||
|
|
RuntimeConfig {
|
||
|
|
socket_path: "tcp://docker.staging.internal:2376".to_string(),
|
||
|
|
..Default::default()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
"production" => {
|
||
|
|
// Production: use production Docker host
|
||
|
|
RuntimeConfig {
|
||
|
|
socket_path: "tcp://docker.prod.internal:2376".to_string(),
|
||
|
|
..Default::default()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
_ => RuntimeConfig::default(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Conclusion
|
||
|
|
|
||
|
|
The Runtime crate provides flexible, production-ready container runtime abstraction. Proper configuration, error handling, and security practices ensure reliable container operations across diverse environments.
|
||
|
|
|
||
|
|
For more information, see:
|
||
|
|
- [Runtime README.md](README.md) - API documentation
|
||
|
|
- [Examples](../../../examples/) - Complete examples
|
||
|
|
- [Integration Architecture](../../../docs/integration-architecture.md) - System integration patterns
|