Operators Kubernetes em Zig

Operators Kubernetes em Zig

Kubernetes Operators automatizam a gestão de aplicações complexas. Geralmente escritos em Go com o framework Operator SDK, operators podem ser implementados em qualquer linguagem que consuma a API do Kubernetes. Zig oferece vantagens únicas: binários minúsculos, startup instantâneo e uso mínimo de memória.

Arquitetura de um Operator

┌─────────────────────────────────────────┐
              Kubernetes API              
  (watch CRDs, pods, services, etc.)      
└──────────────┬──────────────────────────┘
                Watch Events
               
┌─────────────────────────────────────────┐
           Zig Operator                   
  ┌─────────────────────────────────┐    
       Reconciliation Loop              
    - Observar estado desejado         
    - Comparar com estado atual        
    - Executar ações corretivas        
  └─────────────────────────────────┘    
└─────────────────────────────────────────┘

Cliente HTTP para API do Kubernetes

const std = @import("std");
const http = std.http;

const K8sClient = struct {
    allocator: std.mem.Allocator,
    api_server: []const u8,
    token: []const u8,

    pub fn init(allocator: std.mem.Allocator) !K8sClient {
        // Dentro de um pod, credenciais são montadas automaticamente
        const token = try std.fs.cwd().readFileAlloc(
            allocator,
            "/var/run/secrets/kubernetes.io/serviceaccount/token",
            8192,
        );

        return .{
            .allocator = allocator,
            .api_server = "https://kubernetes.default.svc",
            .token = token,
        };
    }

    pub fn listarPods(self: *K8sClient, namespace: []const u8) ![]const u8 {
        const url = try std.fmt.allocPrint(
            self.allocator,
            "{s}/api/v1/namespaces/{s}/pods",
            .{ self.api_server, namespace },
        );
        defer self.allocator.free(url);

        var client = http.Client{ .allocator = self.allocator };
        defer client.deinit();

        const uri = try std.Uri.parse(url);
        var buf: [4096]u8 = undefined;
        var req = try client.open(.GET, uri, .{
            .server_header_buffer = &buf,
            .extra_headers = &.{
                .{ .name = "Authorization", .value = try std.fmt.allocPrint(
                    self.allocator, "Bearer {s}", .{self.token},
                ) },
            },
        });
        defer req.deinit();

        try req.send();
        try req.wait();

        return try req.reader().readAllAlloc(self.allocator, 1024 * 1024);
    }
};

Reconciliation Loop

const ReconcileResult = enum {
    ok,
    requeue,
    requeue_after,
    erro,
};

fn reconciliar(client: *K8sClient, recurso: CRD) ReconcileResult {
    // 1. Observar estado desejado (do CRD)
    const desejado = recurso.spec;

    // 2. Observar estado atual
    const atual = client.listarPods(recurso.metadata.namespace) catch
        return .requeue;

    // 3. Comparar e agir
    if (!estadoCorresponde(desejado, atual)) {
        // Criar/atualizar/deletar recursos para atingir estado desejado
        aplicarMudancas(client, desejado, atual) catch return .requeue;
    }

    return .ok;
}

Conclusão

Operators Kubernetes em Zig são viáveis e oferecem vantagens de footprint: imagens de 2-3 MB, memória de 5-10 MB em idle (vs 50-100 MB em Go). Para clusters com muitos operators, a economia de recursos é significativa.

Conteúdo Relacionado

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.