Ruby Kubernetes API client
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin
lib Release 0.8.3 Feb 14, 2019
spec
.gitignore Add Rubocop (#49) Oct 18, 2018
.rspec skeleton Jul 6, 2018
.rubocop.relaxed.yml Add Rubocop (#49) Oct 18, 2018
.rubocop.yml Add Rubocop (#49) Oct 18, 2018
.travis.yml Add Ruby 2.6 to test matrix (#78) Dec 29, 2018
Dockerfile
Gemfile rename to k8s-client Jul 18, 2018
LICENSE add license Jul 31, 2018
README.md README to have expand_path (#76) Dec 29, 2018
Rakefile Add Rubocop (#49) Oct 18, 2018
docker-compose.yaml rename to k8s-client Jul 18, 2018
k8s-client.gemspec Replace deep_merge gem with own implementation (#81) Jan 7, 2019

README.md

K8s::Client

Build Status Gem Version Yard Docs

Ruby client library for the Kubernetes (1.9+) API

Highlights

  • Clean API for dynamic Kubernetes API Groups / Resources
  • Fast API requests using HTTP connection keepalive
  • Fast API discovery and resource listings using pipelined HTTP requests
  • Typed errors with useful debugging information

Installation

Add this line to your application's Gemfile:

gem 'k8s-client'

And then execute:

$ bundle

Or install it yourself as:

$ gem install k8s-client

And then load the code using:

require 'k8s-client'

Usage

Overview

The top-level K8s::Client provides access to separate APIClient instances for each Kubernetes API Group (v1, apps/v1, etc.), which in turns provides access to separate ResourceClient instances for each API resource type (nodes, pods, deployments, etc.).

Individual resources are returned as K8s::Resource instances, which are RecursiveOpenStruct instances providing attribute access (resource.metadata.name). The resource instances are returned by methods such as client.api('v1').resource('nodes').get('foo'), and passed as arguments for client.api('v1').resource('nodes').create_resource(res). Resources can also be loaded from disk using K8s::Resource.from_files(path), and passed to the top-level methods such as client.create_resource(res), which lookup the correct API/Resource client from the resource apiVersion and kind.

The different K8s::Error::API subclasses represent different HTTP response codes, such as K8s::Error::NotFound or K8s::Error::Conflict.

See bin/k8s-client for example code.

Creating a client

Unauthenticated client

client = K8s.client('https://localhost:6443', ssl_verify_peer: false)

The keyword options are Excon options.

Client from kubeconfig

client = K8s::Client.config(
  K8s::Config.load_file(
    File.expand_path '~/.kube/config'
  )
)

Supported kubeconfig options

Not all kubeconfig options are supported, only the following kubeconfig options work:

  • current-context
  • context.cluster
  • context.user
  • cluster.server
  • cluster.insecure_skip_tls_verify
  • cluster.certificate_authority
  • cluster.certificate_authority_data
  • user.client_certificate + user.client_key
  • user.client_certificate_data + user.client_key_data
  • user.token
With overrides
client = K8s::Client.config(K8s::Config.load_file('~/.kube/config'),
  server: 'http://localhost:8001',
)

In-cluster client from pod envs/secrets

client = K8s::Client.in_cluster_config

Logging

Quiet

To supress any warning messages:

K8s::Logging.quiet!
K8s::Transport.quiet!

The K8s::Transport is quiet by default, but other components may log warnings in the future.

Debugging

Log all API requests

K8s::Logging.debug!
K8s::Transport.verbose!
I, [2018-08-09T14:19:50.404739 #1]  INFO -- K8s::Transport: Using config with server=https://167.99.39.233:6443
I, [2018-08-09T14:19:50.629521 #1]  INFO -- K8s::Transport<https://167.99.39.233:6443>: GET /version => HTTP 200: <K8s::API::Version> in 0.224s
I, [2018-08-09T14:19:50.681367 #1]  INFO -- K8s::Transport<https://167.99.39.233:6443>: GET /api/v1 => HTTP 200: <K8s::API::MetaV1::APIResourceList> in 0.046s
I, [2018-08-09T14:19:51.018740 #1]  INFO -- K8s::Transport<https://167.99.39.233:6443>: GET /api/v1/pods => HTTP 200: <K8s::API::MetaV1::List> in 0.316s

Using K8s::Transport.debug! will also log request/response bodies. The EXCON_DEBUG=true env will log all request/response attributes, including headers.

Prefetching API resources

Operations like mapping a resource kind to an API resource URL require knowledge of the API resource lists for the API group. Mapping resources for multiple API groups would require fetching the API resource lists for each API group in turn, leading to additional request latency. This can be optimized using resource prefetching:

client.apis(prefetch_resources: true)

This will fetch the API resource lists for all API groups in a single pipelined request.

Listing resources

client.api('v1').resource('pods', namespace: 'default').list(labelSelector: {'role' => 'test'}).each do |pod|
  puts "namespace=#{pod.metadata.namespace} pod: #{pod.metadata.name} node=#{pod.spec.nodeName}"
end

Updating resources

node = client.api('v1').resource('nodes').get('test-node')

node[:spec][:unschedulable] = true

client.api('v1').resource('nodes').update_resource(node)

Deleting resources

pod = client.api('v1').resource('pods', namespace: 'default').delete('test-pod')
pods = client.api('v1').resource('pods', namespace: 'default').delete_collection(labelSelector: {'role' => 'test'})

Creating resources

Programmatically defined resources

service = K8s::Resource.new(
  apiVersion: 'v1',
  kind: 'Service',
  metadata: {
    namespace: 'default',
    name: 'test',
  },
  spec: {
    type: 'ClusterIP',
    ports: [
      { port: 80 },
    ],
    selector: {'app' => 'test'},
  },
)

logger.info "Create service=#{service.metadata.name} in namespace=#{service.metadata.namespace}"

service = client.api('v1').resource('services').create_resource(service)

From file(s)

resources = K8s::Resource.from_files('./test.yaml')

for resource in resources
  resource = client.create_resource(resource)
end

Patching resources

client.api('apps/v1').resource('deployments', namespace: 'default').merge_patch('test', {
    spec: { replicas: 3 },
})

Watching resources

client.api('v1').resource('pods', namespace: 'default').watch(labelSelector: {'role' => 'test'}) do |watch_event|
  puts "type=#{watch_event.type} pod=#{watch_event.resource.metadata.name}"
end

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/kontena/k8s-client.