Skip to main content

Advanced

Patching, applying manifests, scaling deployments, YAML handling, raw API access, and resource metrics.

Prerequisites

Install the client: npm install @kubernetes/client-node. These examples require a valid kubeconfig (default: ~/.kube/config) or in-cluster service account. Run with Node.js 18+.

Patch Resources

examples/typescript/patch/patch-example.ts
import { CoreV1Api, KubeConfig, setHeaderOptions, PatchStrategy } from '@kubernetes/client-node';

const kc = new KubeConfig();
kc.loadFromDefault();

const k8sApi = kc.makeApiClient(CoreV1Api);

try {
const res = await k8sApi.listNamespacedPod({ namespace: 'default' });
const patch = [
{
op: 'replace',
path: '/metadata/labels',
value: {
foo: 'bar',
},
},
];

const podName = res.items[0]?.metadata?.name;
if (podName === undefined) {
throw new Error('Pod name is undefined');
}

await k8sApi.patchNamespacedPod(
{
name: podName,
namespace: 'default',
body: patch,
},
setHeaderOptions('Content-Type', PatchStrategy.JsonPatch),
);

console.log('Patched.');
} catch (err) {
console.error('Error: ', err);
}

Related: KubeConfig · PatchStrategy · CoreV1Api · Pod operations

Apply a Manifest

examples/typescript/apply/apply-example.ts
import * as k8s from '@kubernetes/client-node';

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

const client = k8s.KubernetesObjectApi.makeApiClient(kc);

// update deployment "my-deployment" in namespace "my-namespace" to 3 replicas
const deployment = {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: 'my-deployment',
namespace: 'my-namespace',
},
spec: {
replicas: 3,
},
};

client.patch(deployment);

Related: KubeConfig · KubernetesObjectApi

Apply from File

examples/typescript/apply/apply-from-file-example.ts
import * as k8s from '@kubernetes/client-node';
import yaml from 'js-yaml';
import fs from 'node:fs/promises';

/**
* Replicate the functionality of `kubectl apply`. That is, create the resources defined in the `specFile` if they do
* not exist, patch them if they do exist.
*
* @param specPath File system path to a YAML Kubernetes spec.
* @return Array of resources created
*/
export async function apply(specPath: string): Promise<k8s.KubernetesObject[]> {
const kc = new k8s.KubeConfig();
kc.loadFromDefault();

const client = k8s.KubernetesObjectApi.makeApiClient(kc);

const specString = await fs.readFile(specPath, 'utf8');
const specs: k8s.KubernetesObject[] = yaml.loadAll(specString);
const validSpecs = specs.filter((s) => s && s.kind && s.metadata);
const created: k8s.KubernetesObject[] = [];
for (const spec of validSpecs) {
// this is to convince the old version of TypeScript that metadata exists even though we already filtered specs
// without metadata out
spec.metadata = spec.metadata || {};
spec.metadata.annotations = spec.metadata.annotations || {};
spec.metadata.annotations['kubectl.kubernetes.io/last-applied-configuration'] = JSON.stringify(spec);
try {
// try to get the resource, if it does not exist an error will be thrown and we will end up in the catch
// block.
await client.read(spec);
// we got the resource, so it exists, so patch it
//
// Note that this could fail if the spec refers to a custom resource. For custom resources you may need
// to specify a different patch merge strategy in the content-type header.
//
// See: https://github.com/kubernetes/kubernetes/issues/97423
const response = await client.patch(spec);
created.push(response);
} catch (err) {
// if the resource doesnt exist then create it
if (err instanceof k8s.ApiException && err.code === 404) {
const response = await client.create(spec);
created.push(response);
} else {
throw err;
}
}
}

return created;
}

Related: KubeConfig · KubernetesObjectApi

Scale a Deployment

examples/scale-deployment.js
import * as k8s from '@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 deployment = await k8sApi.readNamespacedDeployment({
name,
namespace,
});

// edit
const newDeployment = {
...deployment,
spec: {
...deployment.spec,
replicas,
},
};

// replace
await k8sApi.replaceNamespacedDeployment({
name,
namespace,
body: newDeployment,
});
}

scale(targetNamespaceName, targetDeploymentName, numberOfTargetReplicas);

Related: KubeConfig · AppsV1Api · Deployment operations

Load and Apply YAML

examples/yaml-example.js
import * as k8s from '@kubernetes/client-node';

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

const k8sApi = kc.makeApiClient(k8s.CoreV1Api);

const yamlString = k8s.dumpYaml({
metadata: {
name: 'test',
},
});

const yamlNamespace = k8s.loadYaml(yamlString);

try {
const response = await k8sApi.createNamespace({ body: yamlNamespace });
console.log('Created namespace');
console.log(response);
const res = await k8sApi.readNamespace({ name: yamlNamespace.metadata.name });
console.log(res);
await k8sApi.deleteNamespace({ name: yamlNamespace.metadata.name });
} catch (err) {
console.error('Error!: ' + err);
}

Related: KubeConfig · loadYaml · dumpYaml · CoreV1Api · Namespace operations

Create an Ingress

examples/ingress.js
import * as k8s from '@kubernetes/client-node';

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

const k8sApi = kc.makeApiClient(k8s.NetworkingV1Api);

const namespace = 'default';
const clientIdentifier = 'my-subdomain';

try {
await k8sApi
.createNamespacedIngress({
namespace,
body: {
apiVersion: 'networking.k8s.io/v1',
kind: 'Ingress',
metadata: { name: `production-custom-${clientIdentifier}` },
spec: {
rules: [
{
host: `${clientIdentifier}.example.com`,
http: {
paths: [
{
backend: {
service: {
name: 'production-auto-deploy',
port: { number: 5000 },
},
},
path: '/',
pathType: 'ImplementationSpecific',
},
],
},
},
],
tls: [{ hosts: [`${clientIdentifier}.example.com`] }],
},
},
})
} catch (e) {
console.error(e);
}

Related: KubeConfig · NetworkingV1Api

Raw API Request

examples/raw-example.js
import * as k8s from '@kubernetes/client-node';
import { fetch } from 'undici';
import https from 'node:https';

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

const currentUser = kc.getCurrentUser();
const currentCluster = kc.getCurrentCluster();

const agent = new https.Agent({
// If caData, certData, and keyData are undefined, read the values from the
// files specified in caFile, certFile, and keyFile.
ca: Buffer.from(currentCluster?.caData ?? '', 'base64').toString('utf8'),
cert: Buffer.from(currentUser?.certData ?? '', 'base64').toString('utf8'),
keepAlive: true,
key: Buffer.from(currentUser?.keyData ?? '', 'base64').toString('utf8'),
});

const opts = {
headers: {},
agent: agent,
};

kc.applyToHTTPSOptions(opts);

const url = `${kc?.getCurrentCluster()?.server}/api/v1/namespaces/default/pods`;

try {
const response = await fetch(url, opts);
const body = await response.text();

console.log(`statusCode: ${response.status}`);
console.log(`body: ${body}`);
} catch (err) {
console.error(`error: ${err}`);
}

Related: KubeConfig

Top Nodes

examples/top.js
import * as k8s from '@kubernetes/client-node';

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

const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
const obj = await k8s.topNodes(k8sApi);
console.log(obj);

Related: KubeConfig · topNodes · CoreV1Api

Top Pods

examples/top_pods.js
import * as k8s from '@kubernetes/client-node';

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

const k8sApi = kc.makeApiClient(k8s.CoreV1Api);
const metricsClient = new k8s.Metrics(kc);

const namespace = 'kube-system';

{
const pods = await k8s.topPods(k8sApi, metricsClient, namespace);
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);
}

{
const pods = await k8s.topPods(k8sApi, metricsClient, namespace);
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);
}

Related: KubeConfig · Metrics · topPods · CoreV1Api