Деплой Rust на Kubernetes: базовое руководство для начинающих
Современная разработка всё чаще требует не только написания быстрого и безопасного кода, но и умения правильно разворачивать его в облачной инфраструктуре. Rust, известный своей производительностью и безопасностью памяти, становится отличным выбором для микросервисов. А Kubernetes — стандартный оркестратор контейнеров — помогает управлять этими сервисами в масштабе.
В этой статье мы пройдем полный путь от написания простого веб-сервера на Rust до его развертывания в кластере Kubernetes. Вы узнаете, как упаковать приложение в Docker-образ, создать необходимые манифесты и запустить его в облаке.
1. Подготовка Rust-приложения для контейнеризации
Для начала создадим простое веб-приложение на Rust с использованием популярного фреймворка actix-web. Оно будет возвращать простое JSON-сообщение — идеальный пример для микросервиса.
Создайте новый проект:
cargo new rust-k8s-demo
cd rust-k8s-demo
Добавьте в Cargo.toml зависимость:
[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
Теперь напишем код приложения в src/main.rs:
use actix_web::{web, App, HttpServer, Responder, HttpResponse};
use serde::Serialize;
#[derive(Serialize)]
struct HealthResponse {
status: String,
message: String,
}
async fn health_check() -> impl Responder {
HttpResponse::Ok().json(HealthResponse {
status: "ok".to_string(),
message: "Rust service is running on Kubernetes!".to_string(),
})
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
println!("Starting server on 0.0.0.0:8080");
HttpServer::new(|| {
App::new()
.route("/health", web::get().to(health_check))
})
.bind("0.0.0.0:8080")?
.run()
.await
}
Обратите внимание: мы привязываемся к 0.0.0.0:8080, так как внутри контейнера приложение должно слушать все интерфейсы. Проверьте локально:
cargo run
Откройте http://localhost:8080/health — вы должны увидеть JSON-ответ.
2. Создание Docker-образа с Rust-приложением
Для Kubernetes нам нужен контейнер. Rust компилируется в нативный бинарник, поэтому мы можем использовать многоэтапную сборку (multi-stage build), чтобы получить минимальный образ.
Создайте файл Dockerfile в корне проекта:
# Этап сборки
FROM rust:1.75-slim-bookworm AS builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release 2>/dev/null || true
COPY src/ src/
RUN cargo build --release
# Финальный образ
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/rust-k8s-demo /usr/local/bin/rust-k8s-demo
EXPOSE 8080
CMD ["rust-k8s-demo"]
Этот Dockerfile сначала собирает зависимости, затем компилирует наш код и копирует бинарник в минимальный образ на основе Debian. Это экономит место и повышает безопасность.
Соберите образ:
docker build -t rust-k8s-demo:latest .
Проверьте контейнер локально:
docker run -p 8080:8080 rust-k8s-demo:latest
Если всё работает — загрузите образ в реестр (например, Docker Hub):
docker tag rust-k8s-demo:latest yourusername/rust-k8s-demo:v1
docker push yourusername/rust-k8s-demo:v1
3. Настройка манифестов Kubernetes
Теперь, когда образ готов, нам нужно создать манифесты для Kubernetes. Мы создадим Deployment (для управления репликами) и Service (для доступа к приложению).
Создайте файл deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: rust-app
labels:
app: rust-app
spec:
replicas: 2
selector:
matchLabels:
app: rust-app
template:
metadata:
labels:
app: rust-app
spec:
containers:
- name: rust-app
image: yourusername/rust-k8s-demo:v1
ports:
- containerPort: 8080
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
Обратите внимание на пробы (probes): они позволяют Kubernetes проверять, живо ли приложение и готово ли оно принимать трафик. Это критически важно для продакшена.
Теперь создайте service.yaml для доступа к подам:
apiVersion: v1
kind: Service
metadata:
name: rust-app-service
spec:
selector:
app: rust-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
Мы используем тип LoadBalancer, чтобы получить внешний IP-адрес (если ваш кластер поддерживает это, например, в облаке). Для локального тестирования можно использовать NodePort.
4. Развертывание в кластере Kubernetes
Убедитесь, что у вас есть доступ к кластеру Kubernetes (например, minikube для локального тестирования или любой облачный кластер).
Примените манифесты:
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
Проверьте статус подов:
kubectl get pods
kubectl get services
Если всё прошло успешно, вы увидите два работающих пода. Для доступа к сервису в minikube выпол