...
This commit is contained in:
parent
c177ac5efb
commit
4c50d4b62c
@ -4,7 +4,7 @@ sidebar_position: 20
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Buildah = container builder
|
||||
# Container Builder
|
||||
|
||||
The Buildah module provides functions for working with containers and images using the Buildah tool. Buildah helps you create and manage container images.
|
||||
|
||||
|
198
src/docs/docs/sal/nerdctl.md
Normal file
198
src/docs/docs/sal/nerdctl.md
Normal file
@ -0,0 +1,198 @@
|
||||
---
|
||||
title: "run containers"
|
||||
sidebar_position: 21
|
||||
hide_title: true
|
||||
---
|
||||
|
||||
# Container Manager
|
||||
|
||||
The Container Manager module provides a comprehensive API for working with containers using nerdctl. It offers a modern builder pattern approach for container management.
|
||||
|
||||
## Container Builder Pattern
|
||||
|
||||
The Container Builder Pattern allows for fluent, chainable configuration of containers. This pattern makes container creation more readable and maintainable by allowing you to build complex container configurations step by step.
|
||||
|
||||
### Creating a Container
|
||||
|
||||
Start by creating a new container instance:
|
||||
|
||||
```rhai
|
||||
// Create an empty container with just a name
|
||||
let container = nerdctl_container_new("my-container");
|
||||
|
||||
// Or create a container from an image
|
||||
let container = nerdctl_container_from_image("my-container", "nginx:latest");
|
||||
```
|
||||
|
||||
### Configuring the Container
|
||||
|
||||
Once you have a container instance, you can configure it using the various builder methods:
|
||||
|
||||
```rhai
|
||||
// Configure the container with various options
|
||||
let container = nerdctl_container_from_image("web-server", "nginx:latest")
|
||||
.with_port("8080:80") // Map port 8080 to container port 80
|
||||
.with_volume("/host/path:/container/path") // Mount a volume
|
||||
.with_env("NGINX_HOST", "localhost") // Set an environment variable
|
||||
.with_network("bridge") // Set the network
|
||||
.with_detach(true); // Run in detached mode
|
||||
```
|
||||
|
||||
### Resetting Container Configuration
|
||||
|
||||
If you need to reset the container configuration to its default state while keeping the name and image:
|
||||
|
||||
```rhai
|
||||
// Reset the container configuration
|
||||
let container = nerdctl_container_from_image("web-server", "nginx:latest")
|
||||
.reset() // Reset all configuration to defaults
|
||||
.with_port("8080:80") // Start configuring again
|
||||
.with_detach(true);
|
||||
```
|
||||
|
||||
### Building and Starting the Container
|
||||
|
||||
After configuring the container, you can build and start it:
|
||||
|
||||
```rhai
|
||||
// Build the container (creates it but doesn't start it)
|
||||
let built_container = container.build();
|
||||
|
||||
// Start the container
|
||||
let start_result = built_container.start();
|
||||
|
||||
// Check if the container started successfully
|
||||
if (start_result.success) {
|
||||
println("Container started successfully!");
|
||||
} else {
|
||||
println(`Failed to start container: ${start_result.stderr}`);
|
||||
}
|
||||
```
|
||||
|
||||
### Container Lifecycle Operations
|
||||
|
||||
Once your container is running, you can perform various operations:
|
||||
|
||||
```rhai
|
||||
// Execute a command in the container
|
||||
let exec_result = container.exec("ls -la");
|
||||
|
||||
// Get container logs
|
||||
let logs = container.logs();
|
||||
|
||||
// Stop the container
|
||||
let stop_result = container.stop();
|
||||
|
||||
// Remove the container
|
||||
let remove_result = container.remove();
|
||||
```
|
||||
|
||||
## Available Builder Methods
|
||||
|
||||
The Container Builder Pattern provides the following methods for configuring containers:
|
||||
|
||||
| Method | Description | Example |
|
||||
|--------|-------------|---------|
|
||||
| `reset()` | Reset configuration to defaults | `.reset()` |
|
||||
| `with_port(port)` | Add a port mapping | `.with_port("8080:80")` |
|
||||
| `with_ports(ports_array)` | Add multiple port mappings | `.with_ports(["8080:80", "443:443"])` |
|
||||
| `with_volume(volume)` | Add a volume mount | `.with_volume("/host/path:/container/path")` |
|
||||
| `with_volumes(volumes_array)` | Add multiple volume mounts | `.with_volumes(["/host/path1:/container/path1", "/host/path2:/container/path2"])` |
|
||||
| `with_env(key, value)` | Add an environment variable | `.with_env("NGINX_HOST", "localhost")` |
|
||||
| `with_envs(env_map)` | Add multiple environment variables | `.with_envs(#{"KEY1": "value1", "KEY2": "value2"})` |
|
||||
| `with_network(network)` | Set the network | `.with_network("bridge")` |
|
||||
| `with_network_alias(alias)` | Add a network alias | `.with_network_alias("web-server")` |
|
||||
| `with_network_aliases(aliases_array)` | Add multiple network aliases | `.with_network_aliases(["web-server", "http-service"])` |
|
||||
| `with_cpu_limit(cpus)` | Set CPU limit | `.with_cpu_limit("1.0")` |
|
||||
| `with_cpu_shares(shares)` | Set CPU shares | `.with_cpu_shares("1024")` |
|
||||
| `with_memory_limit(memory)` | Set memory limit | `.with_memory_limit("512m")` |
|
||||
| `with_memory_swap_limit(memory_swap)` | Set memory swap limit | `.with_memory_swap_limit("1g")` |
|
||||
| `with_restart_policy(policy)` | Set restart policy | `.with_restart_policy("unless-stopped")` |
|
||||
| `with_health_check(cmd)` | Set health check command | `.with_health_check("curl -f http://localhost/ || exit 1")` |
|
||||
| `with_health_check_options(cmd, interval, timeout, retries, start_period)` | Set health check with options | `.with_health_check_options("curl -f http://localhost/ || exit 1", "5s", "3s", 3, "10s")` |
|
||||
| `with_snapshotter(snapshotter)` | Set snapshotter | `.with_snapshotter("native")` |
|
||||
| `with_detach(detach)` | Set detach mode | `.with_detach(true)` |
|
||||
|
||||
## Complete Example: Web Server
|
||||
|
||||
Here's a complete example that demonstrates setting up an Nginx web server using the Container Builder Pattern:
|
||||
|
||||
```rhai
|
||||
// Create a temporary directory for our files
|
||||
let work_dir = "/tmp/nerdctl";
|
||||
mkdir(work_dir);
|
||||
chdir(work_dir);
|
||||
|
||||
// Create a custom index.html file
|
||||
let html_content = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Rhai Nerdctl Demo</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 40px;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
}
|
||||
h1 {
|
||||
color: #0066cc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello from Rhai Nerdctl!</h1>
|
||||
<p>This page is served by an Nginx container created using the Rhai nerdctl wrapper.</p>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
// Write the HTML file
|
||||
let html_file = `${work_dir}/index.html`;
|
||||
file_write(html_file, html_content);
|
||||
|
||||
// Set up environment variables
|
||||
let env_map = #{};
|
||||
env_map["NGINX_HOST"] = "localhost";
|
||||
env_map["NGINX_PORT"] = "80";
|
||||
env_map["NGINX_WORKER_PROCESSES"] = "auto";
|
||||
|
||||
// Create and configure the container
|
||||
let container_name = "rhai-nginx-demo";
|
||||
|
||||
// First, try to remove any existing container with the same name
|
||||
nerdctl_remove(container_name);
|
||||
|
||||
// Create a container with a rich set of options using the builder pattern
|
||||
let container = nerdctl_container_from_image(container_name, "nginx:latest")
|
||||
.reset() // Reset to default configuration
|
||||
.with_detach(true)
|
||||
.with_ports(["8080:80"]) // Add multiple ports at once
|
||||
.with_volumes([`${work_dir}:/usr/share/nginx/html`]) // Mount our work dir
|
||||
.with_envs(env_map) // Add multiple environment variables at once
|
||||
.with_network("bridge")
|
||||
.with_network_aliases(["web-server", "nginx-demo"]) // Add multiple network aliases
|
||||
.with_cpu_limit("1.0")
|
||||
.with_memory_limit("512m");
|
||||
|
||||
// Build and start the container
|
||||
let built_container = container.build();
|
||||
let start_result = built_container.start();
|
||||
|
||||
println("The web server is running at http://localhost:8080");
|
||||
```
|
||||
|
||||
## Image Management Functions
|
||||
|
||||
The module also provides functions for managing container images:
|
||||
|
||||
| Function | Description | Example |
|
||||
|----------|-------------|---------|
|
||||
| `nerdctl_images()` | List images in local storage | `nerdctl_images()` |
|
||||
| `nerdctl_image_remove(image)` | Remove an image | `nerdctl_image_remove("nginx:latest")` |
|
||||
| `nerdctl_image_push(image, destination)` | Push an image to a registry | `nerdctl_image_push("my-image:latest", "registry.example.com/my-image:latest")` |
|
||||
| `nerdctl_image_tag(image, new_name)` | Add an additional name to a local image | `nerdctl_image_tag("nginx:latest", "my-nginx:latest")` |
|
||||
| `nerdctl_image_pull(image)` | Pull an image from a registry | `nerdctl_image_pull("nginx:latest")` |
|
||||
| `nerdctl_image_commit(container, image_name)` | Commit a container to an image | `nerdctl_image_commit("web-server", "my-nginx:latest")` |
|
||||
| `nerdctl_image_build(tag, context_path)` | Build an image using a Dockerfile | `nerdctl_image_build("my-image:latest", "./")` |
|
@ -50,6 +50,11 @@ pub fn container_from_image(name: &str, image: &str) -> Result<Container, Box<Ev
|
||||
nerdctl_error_to_rhai_error(Container::from_image(name, image))
|
||||
}
|
||||
|
||||
/// Reset the container configuration to defaults while keeping the name and image
|
||||
pub fn container_reset(mut container: Container) -> Container {
|
||||
container.reset()
|
||||
}
|
||||
|
||||
/// Add a port mapping to a Container
|
||||
pub fn container_with_port(mut container: Container, port: &str) -> Container {
|
||||
container.with_port(port)
|
||||
@ -476,6 +481,7 @@ pub fn register_nerdctl_module(engine: &mut Engine) -> Result<(), Box<EvalAltRes
|
||||
engine.register_fn("nerdctl_container_from_image", container_from_image);
|
||||
|
||||
// Register Container instance methods
|
||||
engine.register_fn("reset", container_reset);
|
||||
engine.register_fn("with_port", container_with_port);
|
||||
engine.register_fn("with_volume", container_with_volume);
|
||||
engine.register_fn("with_env", container_with_env);
|
||||
|
@ -69,7 +69,7 @@ env_map["NGINX_PORT"] = "80";
|
||||
env_map["NGINX_WORKER_PROCESSES"] = "auto";
|
||||
|
||||
// Create a container with a rich set of options using batch methods
|
||||
let container = _container_from_image(container_name, "nginx:latest")
|
||||
let container = nerdctl_container_from_image(container_name, "nginx:latest")
|
||||
.reset()
|
||||
.with_detach(true)
|
||||
.with_ports(["8080:80"]) // Add multiple ports at once
|
||||
@ -77,6 +77,7 @@ let container = _container_from_image(container_name, "nginx:latest")
|
||||
.with_envs(env_map) // Add multiple environment variables at once
|
||||
.with_cpu_limit("1.0")
|
||||
.with_memory_limit("512m")
|
||||
.start();
|
||||
|
||||
|
||||
println("\n web server workflow completed successfully!");
|
||||
|
@ -6,6 +6,38 @@ use super::container_types::{Container, HealthCheck};
|
||||
use super::health_check_script::prepare_health_check_command;
|
||||
|
||||
impl Container {
|
||||
/// Reset the container configuration to defaults while keeping the name and image
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Self` - The container instance for method chaining
|
||||
pub fn reset(mut self) -> Self {
|
||||
let name = self.name;
|
||||
let image = self.image.clone();
|
||||
let container_id = self.container_id.clone();
|
||||
|
||||
// Create a new container with just the name, image, and container_id
|
||||
Self {
|
||||
name,
|
||||
container_id,
|
||||
image,
|
||||
config: std::collections::HashMap::new(),
|
||||
ports: Vec::new(),
|
||||
volumes: Vec::new(),
|
||||
env_vars: std::collections::HashMap::new(),
|
||||
network: None,
|
||||
network_aliases: Vec::new(),
|
||||
cpu_limit: None,
|
||||
memory_limit: None,
|
||||
memory_swap_limit: None,
|
||||
cpu_shares: None,
|
||||
restart_policy: None,
|
||||
health_check: None,
|
||||
detach: false,
|
||||
snapshotter: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a port mapping
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -7,12 +7,54 @@ use serde_json;
|
||||
|
||||
impl Container {
|
||||
/// Start the container and verify it's running
|
||||
/// If the container hasn't been created yet, it will be created automatically.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// * `Result<CommandResult, NerdctlError>` - Command result or error with detailed information
|
||||
pub fn start(&self) -> Result<CommandResult, NerdctlError> {
|
||||
if let Some(container_id) = &self.container_id {
|
||||
// If container_id is None, we need to create the container first
|
||||
let container = if self.container_id.is_none() {
|
||||
// Check if we have an image specified
|
||||
if self.image.is_none() {
|
||||
return Err(NerdctlError::Other("No image specified for container creation".to_string()));
|
||||
}
|
||||
|
||||
// Clone self and create the container
|
||||
println!("Container not created yet. Creating container from image...");
|
||||
|
||||
// First, try to pull the image if it doesn't exist locally
|
||||
let image = self.image.as_ref().unwrap();
|
||||
match execute_nerdctl_command(&["image", "inspect", image]) {
|
||||
Err(_) => {
|
||||
println!("Image '{}' not found locally. Pulling image...", image);
|
||||
if let Err(e) = execute_nerdctl_command(&["pull", image]) {
|
||||
return Err(NerdctlError::CommandFailed(
|
||||
format!("Failed to pull image '{}': {}", image, e)
|
||||
));
|
||||
}
|
||||
println!("Image '{}' pulled successfully.", image);
|
||||
},
|
||||
Ok(_) => {
|
||||
println!("Image '{}' found locally.", image);
|
||||
}
|
||||
}
|
||||
|
||||
// Now create the container
|
||||
match self.clone().build() {
|
||||
Ok(built) => built,
|
||||
Err(e) => {
|
||||
return Err(NerdctlError::CommandFailed(
|
||||
format!("Failed to create container from image '{}': {}", image, e)
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Container already has an ID, use it as is
|
||||
self.clone()
|
||||
};
|
||||
|
||||
if let Some(container_id) = &container.container_id {
|
||||
// First, try to start the container
|
||||
let start_result = execute_nerdctl_command(&["start", container_id]);
|
||||
|
||||
@ -24,14 +66,14 @@ impl Container {
|
||||
}
|
||||
|
||||
// Verify the container is actually running
|
||||
match self.verify_running() {
|
||||
match container.verify_running() {
|
||||
Ok(true) => start_result,
|
||||
Ok(false) => {
|
||||
// Container started but isn't running - get detailed information
|
||||
let mut error_message = format!("Container {} started but is not running.", container_id);
|
||||
|
||||
// Get container status
|
||||
if let Ok(status) = self.status() {
|
||||
if let Ok(status) = container.status() {
|
||||
error_message.push_str(&format!("\nStatus: {}, State: {}, Health: {}",
|
||||
status.status,
|
||||
status.state,
|
||||
@ -69,7 +111,7 @@ impl Container {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(NerdctlError::Other("No container ID available".to_string()))
|
||||
Err(NerdctlError::Other("Failed to create container. No container ID available.".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user