kube_schema
Ruby objects for every Kubernetes resource. Validated against the real OpenAPI spec.
Kube::Schema["Deployment"].new {
.name = "web"
.namespace = "prod"
spec.replicas = 3
spec.template.spec.containers = [
{ name: "app", image: "nginx:1.27", ports: [{ containerPort: 80 }] }
]
}
No YAML. No hash literals. Just Ruby blocks that know their schema.
Contents
- Install
- Resources
- The block DSL
- Subclassing
- Validation
- Error messages
- Manifests
- Schema versions
- Related projects
- Built with
Install
gem install kube_schema
Resources
Every Kubernetes kind is a class. Fetch it by name.
Kube::Schema["Deployment"] # => Class < Kube::Schema::Resource
Kube::Schema["Service"]
Kube::Schema["ConfigMap"]
Kube::Schema["NetworkPolicy"]
Specific versions:
Kube::Schema["1.34"]["Deployment"]
Kube::Schema["1.31"]["Pod"]
Discovery:
Kube::Schema.schema_versions # => ["1.19", "1.20", ..., "1.35"]
Kube::Schema.latest_version # => "1.35"
Kube::Schema["1.34"].list_resources
# => ["Binding", "CSIDriver", "ConfigMap", "Deployment", ...]
The block DSL
Nested attributes just work. No intermediate hashes, no string keys.
deploy = Kube::Schema["Deployment"].new {
.name = "web"
.namespace = "prod"
.labels = { app: "web" }
spec.replicas = 3
spec.selector.matchLabels = { app: "web" }
spec.template..labels = { app: "web" }
spec.template.spec.containers = [
{ name: "app", image: "nginx:1.27", ports: [{ containerPort: 80 }] }
]
}
apiVersion and kind are derived from the schema automatically:
deploy.to_h[:apiVersion] # => "apps/v1"
deploy.to_h[:kind] # => "Deployment"
Subclassing
class RailsApp < Kube::Schema["Deployment"]
def default_image
"ruby:3.4"
end
end
app = RailsApp.new {
.name = "rails"
spec.template.spec.containers = [
{ name: "web", image: "myapp:latest" }
]
}
app.default_image # => "ruby:3.4"
app.valid? # => true
Validation
Every resource validates against the full Kubernetes OpenAPI spec.
deploy.valid? # => true
bad = Kube::Schema["Deployment"].new {
self.apiVersion = 12345
}
bad.valid? # => false
bad.valid!
# Kube::ValidationError: Schema validation failed for Deployment:
# - apiVersion = 12345 — expected string, got Integer
to_yaml refuses to serialize invalid resources:
bad.to_yaml # raises Kube::ValidationError
Error messages
Validation errors render annotated YAML with color-coded diagnostics. Error lines are highlighted in red, missing required keys are injected inline, and each problem gets a clear explanation:

Manifests
Group resources into multi-document YAML.
manifest = Kube::Schema::Manifest.new
manifest << Kube::Schema["Namespace"].new {
.name = "prod"
}
manifest << Kube::Schema["Deployment"].new {
.name = "web"
.namespace = "prod"
spec.replicas = 3
spec.template.spec.containers = [
{ name: "app", image: "nginx:1.27" }
]
}
manifest << Kube::Schema["Service"].new {
.name = "web"
.namespace = "prod"
spec.selector = { app: "web" }
spec.ports = [{ port: 80, targetPort: 8080 }]
}
puts manifest.to_yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: prod
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: prod
spec:
replicas: 3
...
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: prod
spec:
selector:
app: web
ports:
- port: 80
targetPort: 8080
File I/O
# Write
manifest.write("cluster.yaml")
# Read
loaded = Kube::Schema::Manifest.open("cluster.yaml")
# Modify and write back
loaded << new_resource
loaded.write
Composition
Manifests flatten into each other. No nesting.
infra = Kube::Schema::Manifest.new(namespace, configmap, secret)
app = Kube::Schema::Manifest.new(deployment, service)
combined = Kube::Schema::Manifest.new
combined << infra
combined << app
combined.size # => 5
Enumerable
manifest.map { |r| r.to_h[:kind] }
manifest.select { |r| r.to_h[:kind] == "Service" }
manifest.any? { |r| r.to_h[:kind] == "Pod" }
manifest.count
Schema versions
Bundled schemas ship with the gem for Kubernetes 1.19 through 1.35. Updated automatically via CI.
Kube::Schema.schema_version = "1.31"
Kube::Schema["Deployment"] # uses 1.31
Related projects
- kube_cluster -- OOP resource management with dirty tracking and persistence
- kube_kubectl -- Ruby DSL that compiles to kubectl and helm commands
- kube_kit -- Generators for kube_cluster projects
- kube_engine -- Kubernetes engine
Built with
black_hole_struct -- the dynamic nested struct that powers the block DSL. json_schemer -- JSON Schema validation against the real Kubernetes OpenAPI specs.