0

Connect and control Kubernetes system from NodeJS client

Kubernetes clients

As you know, we have many Kubenetes client, for example

A nearly full list of clients in many programming language at here https://kubernetes.io/docs/reference/using-api/client-libraries/ .

Kuberntes clients for NodeJS / TypeScript / JavaScript

In this article, I share with you client what written in TypeScript by community (not official) https://www.npmjs.com/package/@kubernetes/client-node . GitHub repository at https://github.com/kubernetes-client/javascript (443 Folks, 1,600 starts)

List all pods

Print name of all pods for you

const k8sClient = require('@kubernetes/client-node');
const kcFromNodeJS = new k8sClient.KubeConfig();
kcFromNodeJS.loadFromDefault();
const k_api = kcFromNodeJS.makeApiClient(k8sClient.CoreV1Api);
k_api.listNamespacedPod('default').then((res) => {
    console.log(res.body);
});

Top pods what consuming resource intensively

const k8s = require('../dist/index');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
const metricsClient = new k8s.Metrics(kc);

k8s.topPods(k8sApi, metricsClient, "kube-system")
.then((pods) => {
    const podsColumns = pods.map((pod) => {
        return {
            "POD": pod.Pod.metadata.name,
            "CPU(cores)": pod.CPU.CurrentUsage,
            "MEMORY(bytes)": pod.Memory.CurrentUsage,
        }
    });
    console.log("TOP PODS")
    console.table(podsColumns)
});
k8s.topPods(k8sApi, metricsClient, "kube-system")
.then((pods) => {
    const podsAndContainersColumns = pods.flatMap((pod) => {
        return pod.Containers.map(containerUsage => {
            return {
                "POD": pod.Pod.metadata.name,
                "NAME": containerUsage.Container,
                "CPU(cores)": containerUsage.CPUUsage.CurrentUsage,
                "MEMORY(bytes)": containerUsage.MemoryUsage.CurrentUsage,
            };
        })
    });

    console.log("TOP CONTAINERS")
    console.table(podsAndContainersColumns)
});

See flow stream log

const stream = require('stream');
const k8s = require('@kubernetes/client-node');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const log = new k8s.Log(kc);
const logStream = new stream.PassThrough();
logStream.on('data', (chunk) => {
	// use write rather than console.log to prevent double line feed
	process.stdout.write(chunk);
});
log.log('default', 'pod1', 'container', logStream, {follow: true, tailLines: 50, pretty: false, timestamps: false})
.catch(err => {
        console.log(err);
        process.exit(1);
})
.then(req => {
	// disconnects after 5 seconds
	if (req) {
		setTimeout(function(){
			req.abort();
		}, 5000);
	}
});

List Kuberntes cache services

const stream = require('stream');
const k8s = require('@kubernetes/client-node');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const log = new k8s.Log(kc);
const logStream = new stream.PassThrough();
logStream.on('data', (chunk) => {
	// use write rather than console.log to prevent double line feed
	process.stdout.write(chunk);
});
log.log('default', 'pod1', 'container', logStream, {follow: true, tailLines: 50, pretty: false, timestamps: false})
.catch(err => {
        console.log(err);
        process.exit(1);
})
.then(req => {
	// disconnects after 5 seconds
	if (req) {
		setTimeout(function(){
			req.abort();
		}, 5000);
	}
});

Create a new namespace

For example, named it is test_a_thursday .

const k8sClient = require('@kubernetes/client-node');

const my_kc = new k8sClient.KubeConfig();
my_kc.loadFromDefault();
const my_api = my_kc.makeApiClient(k8sClient.CoreV1Api);
var namespace = {
    metadata: {
        name: 'test_a_thursday',
    },
};
my_api.createNamespace(blabla_namespace).then(
    (response) => {
        console.log('Your namespace created! Response: '); console.log(response);        
        k8sApi.readNamespace(blabla_namespace.metadata.name).then((response) => {
            console.log(response);
           my_api.deleteNamespace(blabla_namespace.metadata.name, {} /* delete options */);
        });
    },
    (er) => {
        console.log('Error you catch: ' + er);
    },
);

Config a cluster from source code of programming language (SDK)

const k8s = require('@kubernetes/client-node');
const cluster = {
    name: 'my-server',
    server: 'http://server.com',
};
const user = {
    name: 'my-user',
    password: 'some-password',
};
const context = {
    name: 'my-context',
    user: user.name,
    cluster: cluster.name,
};
const kc = new k8s.KubeConfig();
kc.loadFromOptions({
    clusters: [cluster],
    users: [user],
    contexts: [context],
    currentContext: context.name,
});
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);

Config Ingress

const k8s = require('@kubernetes/client-node');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();

const k8sApi = kc.makeApiClient(k8s.NetworkingV1Api); // before 1.14 use extensions/v1beta1
const clientIdentifier = 'my-subdomain';

k8sApi.createNamespacedIngress('default', {
  apiVersions: 'networking.k8s.io/v1',
  kind: 'Ingress',
  metadata: {
    name: `production-custom-${clientIdentifier}`,
    labels: {
      createdBy: 'node-client',
    },
    annotations: {
      'meta.helm.sh/release-namespace': 'production-auto-deploy',
    },
  },
  spec: {
    ingressClassName: 'nginx',
    rules: [{
      host: `${clientIdentifier}`,
      http: {
        paths: [{
          backend: {
            service: {
              name: 'production-auto-deploy',
              port: {
                number: 5000,
              },
            },
          },
          path: '/default-kuberiq(/|$)(.*)',
          pathType: 'ImplementationSpecific',
        }],
      },
    }],
    tls: [{
      hosts: [`${clientIdentifier}.example.com`],
    }],
  },
}).catch(e => console.log(e));

Scale deployement

const k8s = require('@kubernetes/client-node');
const kc = new k8s.KubeConfig();
kc.loadFromDefault();
const k8sApi = kc.makeApiClient(k8s.AppsV1Api);
const targetNamespaceName = 'default';
const targetDeploymentName = 'docker-test-deployment';
const numberOfTargetReplicas = 3;

async function scale(namespace, name, replicas) {
  // find the particular deployment
  const res = await k8sApi.readNamespacedDeployment(name, namespace);
  let deployment = res.body;

  // edit
  deployment.spec.replicas = replicas;

  // replace
  await k8sApi.replaceNamespacedDeployment(name, namespace, deployment);
}

scale(targetNamespaceName, targetDeploymentName, numberOfTargetReplicas);

Create job from cronjob in cluster

const k8s = require('@kubernetes/client-node');

const kc = new k8s.KubeConfig();
kc.loadFromCluster();

const batchV1Api = kc.makeApiClient(k8s.BatchV1Api);
const batchV1beta1Api = kc.makeApiClient(k8s.BatchV1beta1Api);
const cronJobName = 'myCronJob';
const jobName = 'myJob';

const job = new k8s.V1Job();
const metadata = new k8s.V1ObjectMeta();
job.apiVersion = 'batch/v1';
job.kind = 'Job';
metadata.name = jobName;
metadata.annotations = {
    'cronjob.kubernetes.io/instantiate': 'manual',
};
job.metadata = metadata;

batchV1beta1Api.readNamespacedCronJob(cronJobName, 'default')
    .then((cronJobRes) => {
        job.spec = cronJobRes.body.spec.jobTemplate.spec;
        batchV1Api.createNamespacedJob('default', job)
            .then((res) => {
                console.log(res.body);
            })
            .catch((err) => {
                console.log(err);
            });
    })
    .catch((err) => {
        console.log(err);
    });

These examples are not full list of feature what Kubernetes NodeJS client can bring to you, has more features for you.

Choose correct version of NodeJS client works together with Kubernetes system

Matrix of compatibility

image.png

Order of compatibility (greatest to lower):

  1. Fully comaptible
  2. + Common will work
  3. - The Kuberntes cluster has features the JS client cannot use.
  4. x Not supported totally

Lastest version (at the time of writing) of NodeJS client is 0.18.1 what support Kuberntes 1.25 (Current version of Kubernetes is 1.27.1)

Author: https://github.com/donhuvy , https://stackoverflow.com/users/3728901 

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí