server_forge/containerization.rs
1//! # Containerization Module
2//!
3//! This module provides functionality for setting up and managing containerization
4//! technologies, specifically Docker and Kubernetes, on a Linux server. It includes
5//! functions for installation, configuration, and deployment of containerized applications.
6//!
7//! The module is designed to work across different Linux distributions by leveraging
8//! the appropriate package manager and installation methods for each system.
9
10use crate::config::Config;
11use crate::distro::{get_package_manager, PackageManager};
12use crate::rollback::RollbackManager;
13use crate::utils::run_command;
14use log::info;
15use std::error::Error;
16
17/// Sets up Docker on the system.
18///
19/// This function installs Docker, configures it, and ensures it's running and enabled on boot.
20/// It creates a snapshot before installation for potential rollback.
21///
22/// # Arguments
23///
24/// * `rollback` - A reference to the `RollbackManager` for creating snapshots
25///
26/// # Returns
27///
28/// Returns `Ok(())` if Docker is set up successfully, or an error if setup fails.
29pub fn setup_docker(rollback: &RollbackManager) -> Result<(), Box<dyn Error>> {
30 info!("Setting up Docker...");
31
32 let snapshot = rollback.create_snapshot()?;
33
34 install_docker()?;
35 configure_docker()?;
36
37 rollback.commit_snapshot(snapshot)?;
38
39 info!("Docker setup completed");
40 Ok(())
41}
42
43/// Sets up Kubernetes on the system.
44///
45/// This function installs Kubernetes tools (kubectl and minikube), configures them,
46/// and ensures they're ready for use. It creates a snapshot before installation for potential rollback.
47///
48/// # Arguments
49///
50/// * `rollback` - A reference to the `RollbackManager` for creating snapshots
51///
52/// # Returns
53///
54/// Returns `Ok(())` if Kubernetes is set up successfully, or an error if setup fails.
55pub fn setup_kubernetes(rollback: &RollbackManager) -> Result<(), Box<dyn Error>> {
56 info!("Setting up Kubernetes...");
57
58 let snapshot = rollback.create_snapshot()?;
59
60 install_kubernetes()?;
61 configure_kubernetes()?;
62
63 rollback.commit_snapshot(snapshot)?;
64
65 info!("Kubernetes setup completed");
66 Ok(())
67}
68
69/// Deploys containers for all applications specified in the configuration.
70///
71/// This function iterates through the list of applications in the configuration
72/// and deploys each as a container, either using Docker or Kubernetes based on the configuration.
73///
74/// # Arguments
75///
76/// * `config` - A reference to the `Config` struct containing deployment information
77/// * `rollback` - A reference to the `RollbackManager` for creating snapshots
78///
79/// # Returns
80///
81/// Returns `Ok(())` if all containers are deployed successfully, or an error if any deployment fails.
82pub fn deploy_containers(
83 config: &Config,
84 rollback: &RollbackManager,
85) -> Result<(), Box<dyn Error>> {
86 info!("Deploying containers...");
87 let snapshot = rollback.create_snapshot()?;
88
89 for app in &config.deployed_apps {
90 deploy_container(app, config.use_kubernetes)?;
91 }
92
93 rollback.commit_snapshot(snapshot)?;
94
95 info!("Container deployment completed");
96 Ok(())
97}
98
99/// Installs Docker on the system.
100///
101/// This function installs Docker using the appropriate method for the current Linux distribution.
102/// It adds the Docker repository, installs necessary dependencies, and installs Docker components.
103///
104/// # Returns
105///
106/// Returns `Ok(())` if Docker is installed successfully, or an error if installation fails.
107pub fn install_docker() -> Result<(), Box<dyn Error>> {
108 let package_manager = get_package_manager()?;
109
110 match package_manager {
111 PackageManager::Apt => {
112 run_command("apt", &["update"])?;
113 run_command(
114 "apt",
115 &[
116 "install",
117 "-y",
118 "apt-transport-https",
119 "ca-certificates",
120 "curl",
121 "gnupg",
122 "lsb-release",
123 ],
124 )?;
125 run_command(
126 "curl",
127 &[
128 "-fsSL",
129 "https://download.docker.com/linux/ubuntu/gpg",
130 "|",
131 "gpg",
132 "--dearmor",
133 "-o",
134 "/usr/share/keyrings/docker-archive-keyring.gpg",
135 ],
136 )?;
137 run_command("echo", &["\"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\"", "|", "tee", "/etc/apt/sources.list.d/docker.list", ">", "/dev/null"])?;
138 run_command("apt", &["update"])?;
139 run_command(
140 "apt",
141 &[
142 "install",
143 "-y",
144 "docker-ce",
145 "docker-ce-cli",
146 "containerd.io",
147 ],
148 )?;
149 }
150 PackageManager::Yum => {
151 run_command("yum", &["install", "-y", "yum-utils"])?;
152 run_command(
153 "yum-config-manager",
154 &[
155 "--add-repo",
156 "https://download.docker.com/linux/centos/docker-ce.repo",
157 ],
158 )?;
159 run_command(
160 "yum",
161 &[
162 "install",
163 "-y",
164 "docker-ce",
165 "docker-ce-cli",
166 "containerd.io",
167 ],
168 )?;
169 }
170 PackageManager::Dnf => {
171 run_command("dnf", &["install", "-y", "dnf-plugins-core"])?;
172 run_command(
173 "dnf",
174 &[
175 "config-manager",
176 "--add-repo",
177 "https://download.docker.com/linux/fedora/docker-ce.repo",
178 ],
179 )?;
180 run_command(
181 "dnf",
182 &[
183 "install",
184 "-y",
185 "docker-ce",
186 "docker-ce-cli",
187 "containerd.io",
188 ],
189 )?;
190 }
191 }
192
193 run_command("systemctl", &["start", "docker"])?;
194 run_command("systemctl", &["enable", "docker"])?;
195
196 Ok(())
197}
198
199/// Configures Docker after installation.
200///
201/// This function sets up the Docker daemon with optimal settings, creates a Docker group,
202/// adds the current user to the Docker group, and restarts the Docker service to apply changes.
203///
204/// # Returns
205///
206/// Returns `Ok(())` if Docker is configured successfully, or an error if configuration fails.
207pub fn configure_docker() -> Result<(), Box<dyn Error>> {
208 // Create docker group if it doesn't exist
209 run_command("groupadd", &["docker"])?;
210
211 // Add current user to docker group
212 run_command("usermod", &["-aG", "docker", "$USER"])?;
213
214 // Set up Docker daemon configuration
215 let daemon_config = r#"
216{
217 "log-driver": "json-file",
218 "log-opts": {
219 "max-size": "100m",
220 "max-file": "3"
221 },
222 "default-ulimits": {
223 "nofile": {
224 "Name": "nofile",
225 "Hard": 64000,
226 "Soft": 64000
227 }
228 }
229}
230"#;
231 std::fs::write("/etc/docker/daemon.json", daemon_config)?;
232
233 // Restart Docker to apply changes
234 run_command("systemctl", &["restart", "docker"])?;
235
236 Ok(())
237}
238
239/// Installs Kubernetes tools (kubectl and minikube) on the system.
240///
241/// This function downloads and installs kubectl and minikube, and installs a virtualization
242/// driver (VirtualBox in this implementation) required for running Kubernetes locally.
243///
244/// # Returns
245///
246/// Returns `Ok(())` if Kubernetes tools are installed successfully, or an error if installation fails.
247pub fn install_kubernetes() -> Result<(), Box<dyn Error>> {
248 let package_manager = get_package_manager()?;
249
250 // Install kubectl
251 run_command("curl", &["-LO", "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"])?;
252 run_command("chmod", &["+x", "./kubectl"])?;
253 run_command("mv", &["./kubectl", "/usr/local/bin/kubectl"])?;
254
255 // Install minikube
256 run_command(
257 "curl",
258 &[
259 "-Lo",
260 "minikube",
261 "https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64",
262 ],
263 )?;
264 run_command("chmod", &["+x", "minikube"])?;
265 run_command("mv", &["minikube", "/usr/local/bin/"])?;
266
267 // Install required virtualization driver (using VirtualBox in this example)
268 match package_manager {
269 PackageManager::Apt => run_command("apt", &["install", "-y", "virtualbox"])?,
270 PackageManager::Yum => run_command("yum", &["install", "-y", "VirtualBox"])?,
271 PackageManager::Dnf => run_command("dnf", &["install", "-y", "VirtualBox"])?,
272 }
273
274 Ok(())
275}
276
277/// Configures Kubernetes after installation.
278///
279/// This function starts minikube, enables necessary addons (ingress and dashboard),
280/// and sets up kubectl autocomplete for easier use.
281///
282/// # Returns
283///
284/// Returns `Ok(())` if Kubernetes is configured successfully, or an error if configuration fails.
285pub fn configure_kubernetes() -> Result<(), Box<dyn Error>> {
286 // Start minikube
287 run_command("minikube", &["start"])?;
288
289 // Enable necessary addons
290 run_command("minikube", &["addons", "enable", "ingress"])?;
291 run_command("minikube", &["addons", "enable", "dashboard"])?;
292
293 // Set up kubectl autocomplete
294 run_command(
295 "kubectl",
296 &["completion", "bash", ">", "/etc/bash_completion.d/kubectl"],
297 )?;
298
299 Ok(())
300}
301
302/// Deploys a single container for the specified application.
303///
304/// This function deploys the application either to Kubernetes or directly to Docker,
305/// based on the `use_kubernetes` flag.
306///
307/// # Arguments
308///
309/// * `app` - A string slice representing the application to deploy
310/// * `use_kubernetes` - A boolean indicating whether to use Kubernetes for deployment
311///
312/// # Returns
313///
314/// Returns `Ok(())` if the container is deployed successfully, or an error if deployment fails.
315pub fn deploy_container(app: &str, use_kubernetes: bool) -> Result<(), Box<dyn Error>> {
316 if use_kubernetes {
317 deploy_to_kubernetes(app)?;
318 } else {
319 deploy_to_docker(app)?;
320 }
321 Ok(())
322}
323
324/// Deploys a single container for the specified application.
325///
326/// This function deploys the application either to Kubernetes or directly to Docker,
327/// based on the `use_kubernetes` flag.
328///
329/// # Arguments
330///
331/// * `app` - A string slice representing the application to deploy
332/// * `use_kubernetes` - A boolean indicating whether to use Kubernetes for deployment
333///
334/// # Returns
335///
336/// Returns `Ok(())` if the container is deployed successfully, or an error if deployment fails.
337pub fn deploy_to_kubernetes(app: &str) -> Result<(), Box<dyn Error>> {
338 // Create a basic deployment YAML
339 let deployment_yaml = format!(
340 r#"
341apiVersion: apps/v1
342kind: Deployment
343metadata:
344 name: {}
345spec:
346 replicas: 1
347 selector:
348 matchLabels:
349 app: {}
350 template:
351 metadata:
352 labels:
353 app: {}
354 spec:
355 containers:
356 - name: {}
357 image: {}:latest
358 ports:
359 - containerPort: 80
360"#,
361 app, app, app, app, app
362 );
363
364 // Write the deployment YAML to a file
365 std::fs::write(format!("{}-deployment.yaml", app), deployment_yaml)?;
366
367 // Apply the deployment
368 run_command(
369 "kubectl",
370 &["apply", "-f", &format!("{}-deployment.yaml", app)],
371 )?;
372
373 // Expose the deployment as a service
374 run_command(
375 "kubectl",
376 &[
377 "expose",
378 "deployment",
379 app,
380 "--type=LoadBalancer",
381 "--port=80",
382 ],
383 )?;
384
385 Ok(())
386}
387
388/// Deploys an application to Kubernetes.
389///
390/// This function creates a Kubernetes Deployment and Service for the specified application.
391/// It generates a basic YAML configuration, applies it to the cluster, and exposes the deployment as a service.
392///
393/// # Arguments
394///
395/// * `app` - A string slice representing the application to deploy
396///
397/// # Returns
398///
399/// Returns `Ok(())` if the application is deployed to Kubernetes successfully, or an error if deployment fails.
400pub fn deploy_to_docker(app: &str) -> Result<(), Box<dyn Error>> {
401 // Pull the latest image
402 run_command("docker", &["pull", app])?;
403
404 // Stop and remove any existing container with the same name
405 run_command("docker", &["stop", app]).ok();
406 run_command("docker", &["rm", app]).ok();
407
408 // Run the new container
409 run_command("docker", &["run", "-d", "--name", app, "-p", "80:80", app])?;
410
411 Ok(())
412}