sal/src/virt/nerdctl
Mahmoud Emad f002445c9e
Some checks failed
Rhai Tests / Run Rhai Tests (push) Waiting to run
Rhai Tests / Run Rhai Tests (pull_request) Has been cancelled
feat: Add PostgreSQL and Redis client support
- Add PostgreSQL client functionality for database interactions.
- Add Redis client functionality for cache and data store operations.
- Extend Rhai scripting with PostgreSQL and Redis client modules.
- Add documentation and test cases for both clients.
2025-05-09 09:45:50 +03:00
..
nerdctldocs ... 2025-04-02 08:49:40 +02:00
cmd.rs added example for nerdctl + testing nerdctl (still a bug with running container from image) 2025-04-02 17:21:39 +02:00
container_builder.rs ... 2025-04-05 11:05:24 +02:00
container_functions.rs ... 2025-04-05 06:34:16 +02:00
container_operations.rs ... 2025-04-05 07:40:32 +02:00
container_test.rs feat: Add PostgreSQL and Redis client support 2025-05-09 09:45:50 +03:00
container_types.rs ... 2025-04-05 05:46:30 +02:00
container.rs ... 2025-04-05 11:05:24 +02:00
health_check_script.rs ... 2025-04-05 07:23:07 +02:00
health_check.rs ... 2025-04-05 05:46:30 +02:00
images.rs git working 2025-05-08 09:05:44 +03:00
mod.rs ... 2025-04-05 07:23:07 +02:00
nerdctl-essentials.md added example for nerdctl + testing nerdctl (still a bug with running container from image) 2025-04-02 17:21:39 +02:00
README.md ... 2025-04-05 05:46:30 +02:00

Container API for nerdctl

This module provides a Rust API for managing containers using nerdctl, a Docker-compatible CLI for containerd.

Overview

The Container API is designed with a builder pattern to make it easy to create and manage containers. It provides a fluent interface for configuring container options and performing operations on containers.

Key Components

  • Container: The main struct representing a container
  • HealthCheck: Configuration for container health checks
  • ContainerStatus: Information about a container's status
  • ResourceUsage: Information about a container's resource usage

Getting Started

Prerequisites

  • nerdctl must be installed on your system
  • containerd must be running

Basic Usage

Add the following to your Cargo.toml:

[dependencies]
sal = { path = "/path/to/sal" }

Then import the Container API in your Rust code:

use sal::virt::nerdctl::Container;

Usage Examples

Getting a Container by Name

You can get a reference to an existing container by name:

use sal::virt::nerdctl::Container;

// Get a container by name (if it exists)
match Container::new("existing-container") {
    Ok(container) => {
        if container.container_id.is_some() {
            println!("Found container with ID: {}", container.container_id.unwrap());
            
            // Perform operations on the existing container
            let status = container.status()?;
            println!("Container status: {}", status.status);
        } else {
            println!("Container exists but has no ID");
        }
    },
    Err(e) => {
        println!("Error getting container: {}", e);
    }
}

Creating a Container

You can create a new container from an image using the builder pattern:

use sal::virt::nerdctl::Container;

// Create a container from an image
let container = Container::from_image("my-nginx", "nginx:latest")?
    .with_port("8080:80")
    .with_env("NGINX_HOST", "example.com")
    .with_volume("/tmp/nginx:/usr/share/nginx/html")
    .with_health_check("curl -f http://localhost/ || exit 1")
    .with_detach(true)
    .build()?;

Container Operations

Once you have a container, you can perform various operations on it:

// Execute a command in the container
let result = container.exec("echo 'Hello from container'")?;
println!("Command output: {}", result.stdout);

// Get container status
let status = container.status()?;
println!("Container status: {}", status.status);

// Get resource usage
let resources = container.resources()?;
println!("CPU usage: {}", resources.cpu_usage);
println!("Memory usage: {}", resources.memory_usage);

// Stop and remove the container
container.stop()?;
container.remove()?;

Container Configuration Options

The Container API supports a wide range of configuration options through its builder pattern:

Ports

Map container ports to host ports:

// Map a single port
.with_port("8080:80")

// Map multiple ports
.with_ports(&["8080:80", "8443:443"])

Volumes

Mount host directories or volumes in the container:

// Mount a single volume
.with_volume("/host/path:/container/path")

// Mount multiple volumes
.with_volumes(&["/host/path1:/container/path1", "/host/path2:/container/path2"])

Environment Variables

Set environment variables in the container:

// Set a single environment variable
.with_env("KEY", "value")

// Set multiple environment variables
let mut env_map = HashMap::new();
env_map.insert("KEY1", "value1");
env_map.insert("KEY2", "value2");
.with_envs(&env_map)

Network Configuration

Configure container networking:

// Set the network
.with_network("bridge")

// Add a network alias
.with_network_alias("my-container")

// Add multiple network aliases
.with_network_aliases(&["alias1", "alias2"])

Resource Limits

Set CPU and memory limits:

// Set CPU limit (e.g., 0.5 for half a CPU, 2 for 2 CPUs)
.with_cpu_limit("0.5")

// Set memory limit (e.g., 512m for 512MB, 1g for 1GB)
.with_memory_limit("512m")

// Set memory swap limit
.with_memory_swap_limit("1g")

// Set CPU shares (relative weight)
.with_cpu_shares("1024")

Health Checks

Configure container health checks:

// Simple health check
.with_health_check("curl -f http://localhost/ || exit 1")

// Health check with custom options
.with_health_check_options(
    "curl -f http://localhost/ || exit 1",  // Command
    Some("30s"),                           // Interval
    Some("10s"),                           // Timeout
    Some(3),                               // Retries
    Some("5s")                             // Start period
)

Other Options

Other container configuration options:

// Set restart policy
.with_restart_policy("always")  // Options: no, always, on-failure, unless-stopped

// Set snapshotter
.with_snapshotter("native")     // Options: native, fuse-overlayfs, etc.

// Set detach mode
.with_detach(true)              // Run in detached mode

Container Operations

Once a container is created, you can perform various operations on it:

Basic Operations

// Start the container
container.start()?;

// Stop the container
container.stop()?;

// Remove the container
container.remove()?;

Command Execution

// Execute a command in the container
let result = container.exec("echo 'Hello from container'")?;
println!("Command output: {}", result.stdout);

File Operations

// Copy files between the container and host
container.copy("container_name:/path/in/container", "/path/on/host")?;
container.copy("/path/on/host", "container_name:/path/in/container")?;

// Export the container to a tarball
container.export("/path/to/export.tar")?;

Image Operations

// Commit the container to an image
container.commit("my-custom-image:latest")?;

Status and Monitoring

// Get container status
let status = container.status()?;
println!("Container state: {}", status.state);
println!("Container status: {}", status.status);
println!("Created: {}", status.created);
println!("Started: {}", status.started);

// Get health status
let health_status = container.health_status()?;
println!("Health status: {}", health_status);

// Get resource usage
let resources = container.resources()?;
println!("CPU usage: {}", resources.cpu_usage);
println!("Memory usage: {}", resources.memory_usage);
println!("Memory limit: {}", resources.memory_limit);
println!("Memory percentage: {}", resources.memory_percentage);
println!("Network I/O: {} / {}", resources.network_input, resources.network_output);
println!("Block I/O: {} / {}", resources.block_input, resources.block_output);
println!("PIDs: {}", resources.pids);

Error Handling

The Container API uses a custom error type NerdctlError that can be one of the following:

  • CommandExecutionFailed: The nerdctl command failed to execute
  • CommandFailed: The nerdctl command executed but returned an error
  • JsonParseError: Failed to parse JSON output
  • ConversionError: Failed to convert data
  • Other: Generic error

Example error handling:

match Container::new("non-existent-container") {
    Ok(container) => {
        // Container exists
        println!("Container found");
    },
    Err(e) => {
        match e {
            NerdctlError::CommandExecutionFailed(io_error) => {
                println!("Failed to execute nerdctl command: {}", io_error);
            },
            NerdctlError::CommandFailed(error_msg) => {
                println!("nerdctl command failed: {}", error_msg);
            },
            _ => {
                println!("Other error: {}", e);
            }
        }
    }
}

Implementation Details

The Container API is implemented in several modules:

  • container_types.rs: Contains the struct definitions
  • container.rs: Contains the main Container implementation
  • container_builder.rs: Contains the builder pattern methods
  • container_operations.rs: Contains the container operations
  • health_check.rs: Contains the HealthCheck implementation

This modular approach makes the code more maintainable and easier to understand.

Complete Example

Here's a complete example that demonstrates the Container API:

use std::error::Error;
use sal::virt::nerdctl::Container;

fn main() -> Result<(), Box<dyn Error>> {
    // Create a container from an image
    println!("Creating container from image...");
    let container = Container::from_image("my-nginx", "nginx:latest")?
        .with_port("8080:80")
        .with_env("NGINX_HOST", "example.com")
        .with_volume("/tmp/nginx:/usr/share/nginx/html")
        .with_health_check("curl -f http://localhost/ || exit 1")
        .with_detach(true)
        .build()?;
    
    println!("Container created successfully");
    
    // Execute a command in the container
    println!("Executing command in container...");
    let result = container.exec("echo 'Hello from container'")?;
    println!("Command output: {}", result.stdout);
    
    // Get container status
    println!("Getting container status...");
    let status = container.status()?;
    println!("Container status: {}", status.status);
    
    // Get resource usage
    println!("Getting resource usage...");
    let resources = container.resources()?;
    println!("CPU usage: {}", resources.cpu_usage);
    println!("Memory usage: {}", resources.memory_usage);
    
    // Stop and remove the container
    println!("Stopping and removing container...");
    container.stop()?;
    container.remove()?;
    
    println!("Container stopped and removed");
    
    Ok(())
}