Деплой Rust на Kubernetes: базовое руководство на практике

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение

Rust — это современный системный язык программирования, который сочетает в себе высокую производительность C/C++ с безопасностью памяти на уровне компиляции. Благодаря отсутствию сборщика мусора и низкому потреблению ресурсов, приложения на Rust идеально подходят для запуска в контейнерных средах. Kubernetes (K8s) — стандарт де-факто для оркестрации контейнеров. В этом руководстве мы на практике разберём, как собрать простое веб-приложение на Rust, упаковать его в Docker-образ и развернуть в кластере Kubernetes.

Статья рассчитана на разработчиков, которые уже знакомы с основами Rust и имеют базовое представление о Docker и Kubernetes. Мы не будем углубляться в теорию, а сосредоточимся на пошаговой инструкции с реальными примерами кода и команд.

1. Подготовка приложения на Rust

В качестве примера создадим минимальный HTTP-сервер с использованием популярного фреймворка actix-web. Он будет отвечать на GET-запросы и возвращать JSON-ответ.

Создайте новый проект:

cargo new rust-k8s-app
cd rust-k8s-app

Добавьте зависимости в Cargo.toml:

[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Теперь напишем код сервера в src/main.rs:

use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use serde::Serialize;

#[derive(Serialize)]
struct HealthResponse {
    status: String,
    message: String,
}

#[get("/health")]
async fn health_check() -> impl Responder {
    HttpResponse::Ok().json(HealthResponse {
        status: "ok".to_string(),
        message: "Сервис работает".to_string(),
    })
}

#[get("/")]
async fn index() -> impl Responder {
    HttpResponse::Ok().json(serde_json::json!({
        "service": "rust-k8s-app",
        "version": env!("CARGO_PKG_VERSION")
    }))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let host = std::env::var("HOST").unwrap_or_else(|_| "0.0.0.0".to_string());
    let port: u16 = std::env::var("PORT")
        .unwrap_or_else(|_| "8080".to_string())
        .parse()
        .expect("PORT must be a number");

    println!("Сервер запущен на {}:{}", host, port);

    HttpServer::new(|| {
        App::new()
            .service(health_check)
            .service(index)
    })
    .bind((host.as_str(), port))?
    .run()
    .await
}

Обратите внимание: мы вынесли хост и порт в переменные окружения. Это стандартная практика для контейнеризованных приложений — конфигурация должна приходить извне.

Проверьте, что приложение собирается и запускается локально:

cargo build --release
./target/release/rust-k8s-app

Откройте браузер на http://localhost:8080/health — вы должны увидеть JSON-ответ.

2. Сборка Docker-образа

Для деплоя в Kubernetes нам нужно упаковать приложение в Docker-образ. Используем многоступенчатую сборку (multi-stage build), чтобы минимизировать размер финального образа.

Создайте файл Dockerfile в корне проекта:

# Этап сборки
FROM rust:1.75-slim-bookworm AS builder

WORKDIR /app

# Копируем только Cargo.toml для кэширования зависимостей
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-app /usr/local/bin/rust-k8s-app

EXPOSE 8080

CMD ["rust-k8s-app"]

Соберите образ:

docker build -t rust-k8s-app:latest .

Проверьте размер образа:

docker images | grep rust-k8s-app

Вы должны увидеть образ размером около 80-100 МБ — это отличный результат для production-приложения на Rust.

Запустите контейнер локально для проверки:

docker run -p 8080:8080 rust-k8s-app:latest

3. Написание манифестов Kubernetes

Теперь подготовим манифесты для деплоя в Kubernetes. Создайте директорию k8s и внутри неё файлы.

3.1. Deployment

Файл k8s/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: rust-app
  labels:
    app: rust-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: rust-app
  template:
    metadata:
      labels:
        app: rust-app
    spec:
      containers:
      - name: rust-app
        image: rust-k8s-app:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        env:
        - name: PORT
          value: "8080"
        - name: HOST
          value: "0.0.0.0"
        resources:
          requests:
            memory: "64Mi"
            cpu: "100m"
          limits:
            memory: "128Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 5

Здесь мы задали 3 реплики для отказоустойчивости, указали лимиты ресурсов и настроили пробы (probes) для проверки здоровья приложения.

3.2. Service

Файл k8s/service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: rust-app-service
spec:
  selector:
    app: rust-app
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP

Этот сервис будет балансировать трафик между подами на порту 80.

3.3. Ingress (опционально)

Если

Блоги

Рекомендаций по книгам