Skip to content

Commit 9c56014

Browse files
Implement pod-level persistence for LocalAI models (#28) (#25)
* Update model persistence for LocalAI (#28) * Enhance pod listing to display all namespaces * Fix language detection for Helm charts * Add debug configuration for CodeLLDB * Improve Helm chart * Update README
1 parent 1bb8472 commit 9c56014

15 files changed

+179
-131
lines changed

.gitattributes

+11-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,11 @@
1-
helm-chart/** linguist-language=Rust
1+
# Mark actual Rust files
2+
*.rs linguist-language=Rust
3+
4+
# Mark Helm/Kubernetes YAML files appropriately
5+
helm-chart/**/*.yaml linguist-language=YAML
6+
helm-chart/**/*.yml linguist-language=YAML
7+
helm-chart/**/*.tpl linguist-language=Smarty
8+
9+
# If you want to mark some helm files as documentation
10+
helm-chart/**/README.md linguist-documentation
11+
helm-chart/**/NOTES.txt linguist-documentation

.vscode/launch.json

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "lldb",
9+
"request": "launch",
10+
"name": "Debug executable 'kube_app'",
11+
"cargo": {
12+
"args": ["build", "--bin=kube_app", "--package=kube_app"],
13+
"filter": {
14+
"name": "kube_app",
15+
"kind": "bin"
16+
}
17+
},
18+
"args": [],
19+
"cwd": "${workspaceFolder}"
20+
},
21+
{
22+
"type": "lldb",
23+
"request": "launch",
24+
"name": "Debug unit tests in executable 'kube_app'",
25+
"cargo": {
26+
"args": ["test", "--no-run", "--bin=kube_app", "--package=kube_app"],
27+
"filter": {
28+
"name": "kube_app",
29+
"kind": "bin"
30+
}
31+
},
32+
"args": [],
33+
"cwd": "${workspaceFolder}"
34+
}
35+
]
36+
}

README.md

+24-14
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,34 @@
11
# Kubernetes with Rust, MicroK8s, cert-manager, Gateway API, and LocalAI
22

3-
This repository demonstrates a [**Kubernetes**](https://kubernetes.io/) cluster managed with [**MicroK8s**](https://microk8s.io/), integrating a [**Rust**](https://www.rust-lang.org/) application that interacts with the Kubernetes API using [**Tokio**](https://tokio.rs/) and the [**kube**](https://kube.rs/) crate. It features modern networking with the [Gateway API](https://gateway-api.sigs.k8s.io/), TLS certificate management via [**cert-manager**](https://cert-manager.io/), and AI capabilities using [**LocalAI**](https://localai.io/). This project is suitable for development and testing purposes, leveraging MicroK8s for a lightweight and efficient Kubernetes environment.
4-
5-
---
3+
This repository demonstrates a [**Kubernetes**](https://kubernetes.io/) cluster managed with [**MicroK8s**](https://microk8s.io/), integrating a [**Rust**](https://www.rust-lang.org/) application that interacts with the Kubernetes API using [**Tokio**](https://tokio.rs/) and the [**kube**](https://kube.rs/) crate. It features modern service networking with the [Gateway API](https://gateway-api.sigs.k8s.io/), TLS certificate management via [**cert-manager**](https://cert-manager.io/), and AI capabilities using [**LocalAI**](https://localai.io/).
64

75
## ⚠️ Development-Only Notice
86

9-
**This application uses a `selfsigned-issuer` for TLS certificates, which is suitable for development but NOT recommended for production.** The self-signed certificates provided by cert-manager are ideal for testing environments; however, they lack the security guarantees required for production use. This repository is NOT intended for production deployments and should not be used as such.
7+
These local Kubernetes deployments use TLS certificates created by a `selfsigned-issuer`, which are suitable for testing only and NOT intended for production use cases. A transition to a production-grade setup would require using [Let's Encrypt](https://letsencrypt.org/) or another trusted certificate authority.
108

119
---
1210

1311
## Features
1412

15-
- **Gateway API**: Next-generation service networking with HTTPRoute for granular traffic control and TLS integration.
16-
- **Cert-Manager**: Automates TLS certificate issuance using a self-signed issuer for development.
17-
- **Rust Application**: Interacts with the Kubernetes API to list Pods and can be extended for advanced cluster operations.
18-
- **LocalAI**: Self-hosted AI capabilities with robust potential for privacy-focused, scalable, and cost-efficient AI model deployment.
19-
20-
---
21-
22-
## Getting Started
23-
24-
This repository provides a lightweight platform for exploring Kubernetes features like Gateway API, cert-manager, and LocalAI in a local development environment. Extend the Rust application or experiment with Kubernetes networking and AI capabilities to suit your needs.
13+
- **Gateway API**: Next-generation service networking with HTTPRoute for granular traffic control and TLS.
14+
- **Cert-Manager**: Automates TLS certificate issuance using a `selfsigned-issuer` for development environments.
15+
- **Rust Application**: A minimal implementation demonstrating [Kubernetes API](https://kubernetes.io/docs/reference/kubernetes-api/) interaction by listing Pods across all namespaces with their statuses, serving as a foundation for building advanced cluster operations such as pod management, resource monitoring, CRD handling, event watching, and multi-cluster management.
16+
- **LocalAI**: Self-hosted AI capabilities with persistent storage for models, offering potential for privacy-focused, scalable, and cost-efficient AI model deployment.
17+
18+
## Direction
19+
20+
This project showcases an educational and experimental setup, offering a starting point for advanced use cases. Here are some possibilities:
21+
22+
- **Production-Grade TLS Certificates**: Transition to production-ready deployments by integrating trusted certificate authorities like Let's Encrypt or custom enterprise CAs for secure and scalable HTTPS traffic management.
23+
- **Dynamic Cluster Management**: Automate scaling, monitoring, and resource optimization across multiple clusters.
24+
- **Custom Resource Definitions (CRDs)**: Implement and manage custom Kubernetes resources tailored to specific application requirements.
25+
- **Event-Driven Automation**: Extend the Rust app to respond to Kubernetes events or webhooks for real-time cluster adjustments.
26+
- **AI Workload Orchestration**: Use LocalAI to manage and deploy advanced AI models for edge computing, predictive analytics, or machine learning tasks.
27+
- **Security Enhancements**: Integrate advanced authentication mechanisms and Role-Based Access Control (RBAC) policies for secure multi-user environments.
28+
- **Multi-Tenancy Support**: Enable resource isolation and quota management for multi-tenant Kubernetes clusters.
29+
- **Advanced Networking**: Leverage Gateway API features for traffic splitting, failover mechanisms, and routing policies based on performance metrics.
30+
- **Hybrid Cloud Deployments**: Adapt the setup for hybrid or multi-cloud Kubernetes deployments.
31+
- **Natural Language Processing (NLP)**: Implement AI-powered features such as text summarization, sentiment analysis, or chatbot functionality for applications requiring language understanding.
32+
- **Image and Video Processing**: Use AI models to enable facial recognition, object detection, image classification, or video analytics for multimedia applications.
33+
- **Predictive Analytics**: Leverage AI for forecasting trends, optimizing business operations, or detecting anomalies in datasets for finance, healthcare, or logistics.
34+
- **Custom AI Model Training**: Train and fine-tune models for domain-specific use cases, such as personalized recommendations, scientific research, or custom automation workflows.

helm-chart/files/models.yaml

-11
This file was deleted.
File renamed without changes.

helm-chart/templates/localai-deployment.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ spec:
5050
resources:
5151
{{- toYaml .Values.localai.resources | nindent 16 }}
5252
volumeMounts:
53+
{{- if .Values.localai.persistence.models.enabled }}
54+
- name: models
55+
mountPath: {{ .Values.localai.persistence.models.mountPath }}
56+
{{- end }}
5357
{{- with .Values.localai.volumeMounts }}
5458
{{- toYaml . | nindent 12 }}
5559
{{- end }}

helm-chart/templates/localai-pvc.yaml

-15
This file was deleted.

helm-chart/templates/models-configmap.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ data:
99
models.yaml: |
1010
models:
1111
- name: mistral
12-
path: /models/mistral-7b-instruct-v0.1.Q4_K_M.gguf
12+
path: build/models/mistral-7b-instruct-v0.1.Q4_K_M.gguf
1313
parameters:
1414
model: mistral-7b-instruct-v0.1.Q4_K_M
1515
temperature: 0.7

helm-chart/templates/pvc.yaml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{{- if .Values.localai.persistence.models.enabled }}
2+
apiVersion: v1
3+
kind: PersistentVolumeClaim
4+
metadata:
5+
name: {{ include "localai.fullname" . }}-models
6+
labels:
7+
{{- include "localai.labels" . | nindent 4 }}
8+
app.kubernetes.io/component: models-storage
9+
annotations:
10+
"helm.sh/resource-policy": keep
11+
spec:
12+
accessModes:
13+
- ReadWriteOnce
14+
resources:
15+
requests:
16+
storage: {{ .Values.localai.persistence.models.size | quote }}
17+
{{- if .Values.localai.persistence.models.storageClass }}
18+
storageClassName: {{ .Values.localai.persistence.models.storageClass }}
19+
{{- end }}
20+
---
21+
{{- end }}
22+
{{- if .Values.localai.persistence.output.enabled }}
23+
apiVersion: v1
24+
kind: PersistentVolumeClaim
25+
metadata:
26+
name: {{ include "localai.fullname" . }}-output
27+
labels:
28+
{{- include "localai.labels" . | nindent 4 }}
29+
app.kubernetes.io/component: output-storage
30+
annotations:
31+
"helm.sh/resource-policy": keep
32+
spec:
33+
accessModes:
34+
- ReadWriteOnce
35+
resources:
36+
requests:
37+
storage: {{ .Values.localai.persistence.output.size | quote }}
38+
{{- if .Values.localai.persistence.output.storageClass }}
39+
storageClassName: {{ .Values.localai.persistence.output.storageClass }}
40+
{{- end }}
41+
{{- end }}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: storage.k8s.io/v1
2+
kind: StorageClass
3+
metadata:
4+
name: localai-storage-wait
5+
provisioner: microk8s.io/hostpath
6+
reclaimPolicy: Retain
7+
volumeBindingMode: WaitForFirstConsumer
8+
allowVolumeExpansion: true

helm-chart/templates/tests/test-connection.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ spec:
1111
- name: wget
1212
image: busybox
1313
command: ['wget']
14-
args: ['{{ include "helm-chart.fullname" . }}:{{ .Values.localai.service.port }}']
14+
args: ['{{ include "helm-chart.fullname" . }}:{{ .Values.service.port }}']
1515
restartPolicy: Never

helm-chart/values.yaml

+21-13
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,46 @@ serviceAccount:
1919
# AutomountServiceAccountToken indicates whether pods running as this service account should have an API token automatically mounted
2020
automount: true
2121

22+
# LocalAI configuration
2223
localai:
2324
enabled: true
2425
replicaCount: 1
2526
image:
2627
repository: localai/localai
2728
tag: latest
2829
pullPolicy: IfNotPresent
29-
30+
31+
# Environment variables configuration
32+
env:
33+
- name: LOCALAI_MODELS_PATH
34+
value: /build/models
35+
3036
# Model configuration
3137
models:
32-
path: /models
38+
path: /build/models
3339
preload:
3440
- name: llama-3.2-1b-instruct-q4_k_m.gguf
3541
url: https://huggingface.co/hugging-quants/Llama-3.2-1B-Instruct-Q4_K_M-GGUF/resolve/main/llama-3.2-1b-instruct-q4_k_m.gguf
36-
42+
3743
# Persistent volume configuration for models
3844
persistence:
3945
models:
4046
enabled: true
41-
accessMode: ReadWriteOnce
47+
createClaim: true
4248
size: 10Gi
43-
storageClass: microk8s-hostpath
44-
mountPath: /models
45-
46-
# Volume mounts configuration
47-
volumeMounts:
48-
- name: models
49-
mountPath: /models
50-
readOnly: false
49+
storageClass: "microk8s-hostpath"
50+
mountPath: /build/models
51+
output:
52+
enabled: false
53+
createClaim: false
54+
size: 1Gi
55+
storageClass: "microk8s-hostpath"
56+
mountPath: /build/output
5157

5258
service:
5359
type: ClusterIP
5460
port: 8080
5561

56-
5762
# Gateway API configuration
5863
gateway:
5964
enabled: true
@@ -86,3 +91,6 @@ gateway:
8691
- path:
8792
type: PathPrefix
8893
value: /
94+
service:
95+
type: ClusterIP
96+
port: 8080

helm-chart/values/localai-values.yaml

-67
This file was deleted.

helm-chart/values/temp-values.yaml

-2
This file was deleted.

src/main.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
11
use kube::{Client, api::Api};
2-
use k8s_openapi::api::core::v1::Pod;
2+
use k8s_openapi::api::core::v1::{Pod, Namespace};
33
use tokio;
44

55
#[tokio::main]
66
async fn main() -> Result<(), Box<dyn std::error::Error>> {
77
// Initialize Kubernetes client
88
let client = Client::try_default().await?;
99

10-
// Access the Pod API in the "default" namespace
11-
let pods: Api<Pod> = Api::namespaced(client, "default");
10+
// Access the Namespace API
11+
let namespaces: Api<Namespace> = Api::all(client.clone());
1212

13-
// List all Pods
13+
// List parameters
1414
let lp = kube::api::ListParams::default();
15-
for pod in pods.list(&lp).await? {
16-
println!("Found Pod: {}", pod.metadata.name.unwrap_or_default());
15+
16+
// Get all namespaces
17+
println!("\nKubernetes Cluster Pod Overview:");
18+
println!("===============================");
19+
20+
for ns in namespaces.list(&lp).await? {
21+
let ns_name = ns.metadata.name.unwrap_or_default();
22+
println!("\nNamespace: {}", ns_name);
23+
println!("{}","-".repeat(ns_name.len() + 10));
24+
25+
// Get pods in this namespace
26+
let pods: Api<Pod> = Api::namespaced(client.clone(), &ns_name);
27+
28+
// List all pods in the namespace
29+
match pods.list(&lp).await {
30+
Ok(pod_list) => {
31+
if pod_list.items.is_empty() {
32+
println!(" No pods found");
33+
} else {
34+
for pod in pod_list {
35+
let pod_name = pod.metadata.name.unwrap_or_default();
36+
let status = pod.status.and_then(|s| s.phase).unwrap_or_default();
37+
println!(" Pod: {} (Status: {})", pod_name, status);
38+
}
39+
}
40+
},
41+
Err(e) => println!(" Error listing pods: {}", e),
42+
}
1743
}
1844

1945
Ok(())

0 commit comments

Comments
 (0)