A Ruby DSL for defining Kubernetes resources.
KubeDSL provides a domain-specific language for defining Kubernetes resource objects in Ruby. Why would you want to do this? Well,
- I think Ruby code is easier to read than YAML.
- every property is a Ruby method, meaning Ruby will blow up if you try to configure the object the wrong way.
- doing so follows the principle of infrastructure as code.
- validations are built-in.
Either run gem install kube-dsl
or add it to your Gemfile:
gem 'kube-dsl', '< 1'
KubeDSL directly mirrors the fields and nesting structure of each Kubernetes YAML (or JSON) object. Ruby fields are snake_cased while Kubernetes fields are camelCased. Let's take a look at a short example where we define a Namespace:
ns = KubeDSL.namespace do
metadata do
name 'my-namespace'
end
end
In the example above, we've defined a KubeDSL::DSL::V1::Namespace
object and assigned it to a local variable called ns
. Now let's convert it into a YAML string and print it out:
# ---
# apiVersion: v1
# kind: Namespace
# metadata:
# name: foo
puts ns.to_resource.to_yaml
The #to_resource
method returns an instance of the KubeDSL::Resource
class while #to_yaml
converts the resource into a YAML string. Pretty cool, eh? See the next few sections for examples creating other types of common Kubernetes objects.
Note how key/value pairs are added to the labels
field.
KubeDSL.service_account do
metadata do
name 'my-service-account'
namespace 'my-namespace'
labels do
add :app, 'my-app'
add :role, 'web'
end
end
end
KubeDSL.service do
metadata do
name 'my-service'
namespace 'my-namespace'
labels do
add :app, 'my-app'
add :role, 'web'
end
end
spec do
type 'NodePort'
selector do
add :app, 'my-app'
add :role, 'web'
end
port do
name 'http'
port 3000
protocol 'TCP'
target_port 'http'
end
end
end
Note:
- Elements of arrays can be given names (see the use of the
#container
method below) so they can be easily retrieved and/or modified later. - The example below shows how to add config maps and secrets to a deployment via references.
KubeDSL.deployment do
metadata do
name 'my-deployment'
namespace 'my-namespace'
labels do
add :app, 'my-app'
add :role, 'web'
end
end
spec do
replicas 2
selector do
match_labels do
add :app, 'my-app'
add :role, 'web'
end
end
strategy do
type 'RollingUpdate'
rolling_update do
max_surge '25%'
max_unavailable 1
end
end
template do
metadata do
labels do
add :app, 'my-app'
add :role, 'web'
end
end
spec do
# elements of arrays can be given names (:web in this case) so they can be
# easily retrieved and/or modified later
container(:web) do
name 'my-web-container'
image_pull_policy 'IfNotPresent'
port do
container_port 3000
name 'http'
protocol 'TCP'
end
env_from do
config_map_ref do
name 'my-config-map'
end
end
env_from do
secret_ref do
name 'my-secrets'
end
end
readiness_probe do
success_threshold 1
failure_threshold 2
initial_delay_seconds 15
period_seconds 3
timeout_seconds 1
http_get do
path '/healthz'
port 3000
scheme 'HTTP'
end
end
end
image_pull_secret do
name 'my-registry-secret'
end
end
restart_policy 'Always'
service_account_name 'my-service-account'
end
end
end
NOTE: the example below includes an annotation that is specific to the Nginx ingress controller.
KubeDSL::DSL::Extensions::V1beta1::Ingress.new do
metadata do
name 'my-ingress'
namespace 'my-namespace'
annotations do
add :'kubernetes.io/ingress.class', 'nginx'
end
end
spec do
rule do
host 'my-website.com'
http do
path do
path '/'
backend do
service_name 'my-service'
service_port 80
end
end
end
end
end
end
KubeDSL.config_map do
metadata do
name 'my-config-map'
namespace 'my-namespace'
end
data do
add :MY_VAR, 'value'
add :MY_OTHER_VAR, 'value'
end
end
KubeDSL.secret do
metadata do
name 'my-secrets'
namespace 'my-namespace'
end
type 'Opaque'
data do
add :MY_SECRET, 'value'
end
end
All KubeDSL::DSLObject
s respond to #valid?
and #validate
methods. Use #valid?
to determine whether or not an object is valid. Use #validate
to retrieve a list of validation errors:
ns = KubeDSL.namespace do
metadata do
name 123
end
end
ns.valid? # => false
ns.validate # => #<KubeDSL::Validations::ValidationErrors:0x00007fc8ce276e80 ... >
ns.validate.messages # => {"metadata.name"=>["is not a String"]}
The handy #validate!
method will raise a KubeDSL::ValidationError
if the object is invalid.
All the Ruby code present in KubeDSL is generated from the Kubernetes JSON schema available here. Run the following rake task to regenerate:
bundle exec rake generate
- Cameron C. Dutro: http://github.com/camertron
Licensed under the MIT license.