kube_cluster

Ruby-native Kubernetes. Define, transform, and deploy cluster resources with pure Ruby.

Install

gem "kube_cluster", "~> 0.3"

Examples

Define a resource

pod = Kube::Cluster["Pod"].new {
  .name = "redis"
  spec.containers = [{ name: "redis", image: "redis:8" }]
}

puts pod.to_yaml

Subclass for reuse

class RedisPod < Kube::Cluster["Pod"]
  def initialize(&block)
    super {
      .name = "redis"
      spec.containers = [{ name: "redis", image: "redis:8", ports: [{ containerPort: 6379 }] }]
    }
    instance_exec(&block) if block_given?
  end
end

puts RedisPod.new { .namespace = "production" }.to_yaml

Manifest + middleware

One Deployment declaration becomes a fully-configured stack:

manifest = Kube::Cluster::Manifest.new(
  Kube::Cluster["Deployment"].new {
    .name = "web"
    .labels = {
      "app.kubernetes.io/expose": "app.example.com",
      "app.kubernetes.io/autoscale": "2-10",
      "app.kubernetes.io/size": "small"
    }
    spec.selector.matchLabels = { app: "web" }
    spec.template.spec.containers = [
      { name: "web", image: "nginx", ports: [{ name: "http", containerPort: 8080 }] }
    ]
  }
)

Kube::Cluster::Middleware::Stack.new {
  use Middleware::ServiceForDeployment
  use Middleware::IngressForService
  use Middleware::HPAForDeployment
  use Middleware::Namespace, "production"
  use Middleware::Labels, managed_by: "kube_cluster"
  use Middleware::ResourcePreset
  use Middleware::SecurityContext
  use Middleware::PodAntiAffinity
}.call(manifest)

puts manifest.to_yaml  # => Deployment, Service, Ingress, HPA — all configured

Dirty tracking + patching

cluster = Kube::Cluster.connect(kubeconfig: "~/.kube/config")

config = Kube::Cluster["ConfigMap"].new(cluster:) {
  .name = "app-config"
  self.data = { version: "1" }
}

config.apply           # creates on cluster
config.data.version = "2"
config.changed?        # => true
config.patch           # sends only { data: { version: "2" } }

Helm charts as manifests

manifest = Kube::Helm::Repo
  .new("bitnami", url: "https://charts.bitnami.com/bitnami")
  .fetch("nginx", version: "18.1.0")
  .apply_values("replicaCount" => 3)

puts manifest.to_yaml

Register CRDs as first-class resources

chart = Kube::Helm::Repo.new("jetstack", url: "https://charts.jetstack.io")
  .fetch("cert-manager", version: "1.17.2")

chart.crds.each { |crd|
  s = crd.to_json_schema
  Kube::Schema.register(s[:kind], schema: s[:schema], api_version: s[:api_version])
}

issuer = Kube::Cluster["ClusterIssuer"].new {
  .name = "letsencrypt"
  spec.acme.server = "https://acme-v02.api.letsencrypt.org/directory"
}

Middleware

Middleware Effect
Namespace Sets metadata.namespace on all resources
Labels Merges standard Kubernetes labels
Annotations Merges annotations
ResourcePreset Injects CPU/memory from app.kubernetes.io/size (nano → 2xlarge)
SecurityContext Injects restricted/baseline security contexts
PodAntiAffinity Spreads pods across nodes
ServiceForDeployment Generates Service from named container ports
IngressForService Generates Ingress from app.kubernetes.io/expose label
HPAForDeployment Generates HPA from app.kubernetes.io/autoscale label

More examples

See the examples/ directory for complete runnable projects.

License

Apache-2.0